@@ -4337,6 +4337,20 @@ static void diagnosePotentialWitness(TypeChecker &tc, ValueDecl *req,
4337
4337
tc.diagnose (req, diag::protocol_requirement_here, req->getFullName ());
4338
4338
}
4339
4339
4340
+ // / Determine whether the given requirement was left unsatisfied.
4341
+ static bool isUnsatisfiedReq (NormalProtocolConformance *conformance,
4342
+ ValueDecl *req) {
4343
+ if (conformance->isInvalid ()) return false ;
4344
+ if (isa<TypeDecl>(req)) return false ;
4345
+
4346
+ // An optional requirement might not have a witness...
4347
+ if (!conformance->hasWitness (req) ||
4348
+ !conformance->getWitness (req, nullptr ).getDecl ())
4349
+ return req->getAttrs ().hasAttribute <OptionalAttr>();
4350
+
4351
+ return false ;
4352
+ }
4353
+
4340
4354
void TypeChecker::checkConformancesInContext (DeclContext *dc,
4341
4355
IterableDeclContext *idc) {
4342
4356
// Determine the accessibility of this conformance.
@@ -4364,27 +4378,35 @@ void TypeChecker::checkConformancesInContext(DeclContext *dc,
4364
4378
auto conformances = dc->getLocalConformances (ConformanceLookupKind::All,
4365
4379
&diagnostics,
4366
4380
/* sorted=*/ true );
4367
- bool hasAnyUnsatisfiedOptionalReqs = false ;
4381
+ // Catalog all of members of this declaration context that satisfy
4382
+ // requirements of conformances in this context.
4383
+ llvm::MapVector<DeclName, llvm::TinyPtrVector<ValueDecl *>>
4384
+ unsatisfiedReqs;
4385
+
4386
+ bool anyInvalid = false ;
4368
4387
for (auto conformance : conformances) {
4369
4388
// Check and record normal conformances.
4370
4389
if (auto normal = dyn_cast<NormalProtocolConformance>(conformance)) {
4371
4390
checkConformance (normal);
4372
4391
4373
- // Check whether there are any unsatisfied optional requirements.
4374
- if (!normal->isInvalid () && !hasAnyUnsatisfiedOptionalReqs) {
4375
- auto proto = conformance->getProtocol ();
4376
- for (auto member : proto->getMembers ()) {
4377
- if (isa<TypeDecl>(member)) continue ;
4392
+ if (anyInvalid) continue ;
4378
4393
4379
- auto value = dyn_cast<ValueDecl>(member);
4380
- if (!value) continue ;
4394
+ if (normal->isInvalid ()) {
4395
+ anyInvalid = true ;
4396
+ continue ;
4397
+ }
4381
4398
4382
- // If there is an empty witness, record it.
4383
- if (normal->hasWitness (value) &&
4384
- !normal->getWitness (value, nullptr ).getDecl ()) {
4385
- hasAnyUnsatisfiedOptionalReqs = true ;
4386
- break ;
4387
- }
4399
+ // Check whether there are any unsatisfied requirements.
4400
+ auto proto = conformance->getProtocol ();
4401
+ for (auto member : proto->getMembers ()) {
4402
+ auto req = dyn_cast<ValueDecl>(member);
4403
+ if (!req) continue ;
4404
+
4405
+ // If the requirement is unsatisfied, we might want to warn
4406
+ // about near misses; record it.
4407
+ if (isUnsatisfiedReq (normal, req)) {
4408
+ unsatisfiedReqs[req->getBaseName ()].push_back (req);
4409
+ continue ;
4388
4410
}
4389
4411
}
4390
4412
}
@@ -4413,50 +4435,43 @@ void TypeChecker::checkConformancesInContext(DeclContext *dc,
4413
4435
diag.ExistingExplicitProtocol ->getName ());
4414
4436
}
4415
4437
4416
- // If there were any unsatisfied optional requirements, check whether
4417
- // there are any near-matches we should diagnose.
4418
- if (hasAnyUnsatisfiedOptionalReqs) {
4419
- // Catalog all of members of this declaration context that satisfy
4420
- // requirements of conformances in this context.
4421
- llvm::MapVector<DeclName, llvm::TinyPtrVector<ValueDecl *>>
4422
- unsatisfiedOptionalReqs;
4438
+ // If there were any unsatisfied requirements, check whether there
4439
+ // are any near-matches we should diagnose.
4440
+ if (!unsatisfiedReqs.empty () && !anyInvalid) {
4441
+ // Collect the set of witnesses that came from this context.
4423
4442
llvm::SmallPtrSet<ValueDecl *, 16 > knownWitnesses;
4424
4443
for (auto conformance : conformances) {
4425
4444
conformance->forEachValueWitness (
4426
4445
nullptr ,
4427
4446
[&](ValueDecl *req, ConcreteDeclRef witness) {
4428
4447
// If there is a witness, record it if it's within this context.
4429
- if (witness.getDecl ()) {
4430
- if (witness.getDecl ()->getDeclContext () == dc)
4431
- knownWitnesses.insert (witness.getDecl ());
4432
- return ;
4433
- }
4434
-
4435
- // There is no witness. If this was an optional requirement,
4436
- // record it as such.
4437
- if (req->getAttrs ().hasAttribute <OptionalAttr>())
4438
- unsatisfiedOptionalReqs[req->getBaseName ()].push_back (req);
4448
+ if (witness.getDecl () && witness.getDecl ()->getDeclContext () == dc)
4449
+ knownWitnesses.insert (witness.getDecl ());
4439
4450
});
4440
4451
}
4441
4452
4442
- // Find all of the members that aren't used to satisfy requirements,
4443
- // and check whether they are close to an unsatisfied requirement.
4453
+ // Find all of the members that aren't used to satisfy
4454
+ // requirements, and check whether they are close to an
4455
+ // unsatisfied or defaulted requirement.
4444
4456
for (auto member : idc->getMembers ()) {
4445
- // Filter out anything that couldn't satisfy an optional requirement.
4457
+ // Filter out anything that couldn't satisfy one of the
4458
+ // requirements or was used to satisfy a different requirement.
4446
4459
auto value = dyn_cast<ValueDecl>(member);
4447
4460
if (!value) continue ;
4448
4461
if (isa<TypeDecl>(value)) continue ;
4449
4462
if (knownWitnesses.count (value) > 0 ) continue ;
4450
4463
if (!value->getFullName ()) continue ;
4451
4464
4452
- // Consider any optional requirements with the same base name.
4453
- auto optionalReqs = unsatisfiedOptionalReqs.find (value->getBaseName ());
4454
- if (optionalReqs == unsatisfiedOptionalReqs.end ()) continue ;
4465
+ // Consider any unsatisfied requirements with the same base
4466
+ // name.
4467
+ auto reqs = unsatisfiedReqs.find (value->getBaseName ());
4468
+ if (reqs == unsatisfiedReqs.end ()) continue ;
4455
4469
4456
- // Find the optional requirements with the nearest-matching names.
4470
+ // Find the unsatisfied requirements with the nearest-matching
4471
+ // names.
4457
4472
SmallVector<ValueDecl *, 4 > bestOptionalReqs;
4458
4473
unsigned bestScore = UINT_MAX;
4459
- for (auto req : optionalReqs ->second ) {
4474
+ for (auto req : reqs ->second ) {
4460
4475
// Score this particular optional requirement.
4461
4476
auto score = scorePotentiallyMatchingNames (value->getFullName (),
4462
4477
req->getFullName (),
@@ -4496,19 +4511,20 @@ void TypeChecker::checkConformancesInContext(DeclContext *dc,
4496
4511
4497
4512
// Remove this optional requirement from the list. We don't want to
4498
4513
// complain about it twice.
4499
- if (optionalReqs ->second .size () == 1 ) {
4500
- unsatisfiedOptionalReqs .erase (optionalReqs );
4514
+ if (reqs ->second .size () == 1 ) {
4515
+ unsatisfiedReqs .erase (reqs );
4501
4516
} else {
4502
- optionalReqs ->second .erase (std::find (optionalReqs ->second .begin (),
4503
- optionalReqs ->second .end (),
4504
- req));
4517
+ reqs ->second .erase (std::find (reqs ->second .begin (),
4518
+ reqs ->second .end (),
4519
+ req));
4505
4520
}
4506
4521
}
4507
4522
}
4508
4523
4509
- // For any unsatified optional @objc requirements that remain,
4510
- // note them in the AST for @objc selector collision checking.
4511
- for (const auto &unsatisfied : unsatisfiedOptionalReqs) {
4524
+ // For any unsatified optional @objc requirements that remain
4525
+ // unsatisfied, note them in the AST for @objc selector collision
4526
+ // checking.
4527
+ for (const auto &unsatisfied : unsatisfiedReqs) {
4512
4528
for (auto req : unsatisfied.second ) {
4513
4529
// Skip non-@objc requirements.
4514
4530
if (!req->isObjC ()) continue ;
0 commit comments