@@ -401,12 +401,45 @@ void ConstraintSystem::PotentialBindings::inferDefaultTypes(
401
401
// Key is a literal protocol requirement, Value indicates whether (first)
402
402
// given protocol is a direct requirement, and (second) whether it has been
403
403
// covered by an existing binding.
404
+ bool canBeNil = false ;
404
405
llvm::SmallMapVector<ProtocolDecl *, std::pair<bool , bool >, 4 >
405
406
literalProtocols;
406
407
for (auto *constraint : Protocols) {
407
- if (constraint->getKind () == ConstraintKind::LiteralConformsTo)
408
- literalProtocols.insert ({constraint->getProtocol (),
409
- {isDirectRequirement (constraint), false }});
408
+ if (constraint->getKind () != ConstraintKind::LiteralConformsTo)
409
+ continue ;
410
+
411
+ auto *protocol = constraint->getProtocol ();
412
+
413
+ // No reason to add `ExpressibleByNilLiteral` into the set
414
+ // because it doesn't have a default type.
415
+ if (protocol->isSpecificProtocol (
416
+ KnownProtocolKind::ExpressibleByNilLiteral)) {
417
+ canBeNil = true ;
418
+ continue ;
419
+ }
420
+
421
+ // Let's try to coalesce integer and floating point literal protocols
422
+ // if they appear together because the only possible default type that
423
+ // could satisfy both requirements is `Double`.
424
+ {
425
+ if (protocol->isSpecificProtocol (
426
+ KnownProtocolKind::ExpressibleByIntegerLiteral)) {
427
+ auto *floatLiteral = CS.getASTContext ().getProtocol (
428
+ KnownProtocolKind::ExpressibleByFloatLiteral);
429
+ if (literalProtocols.count (floatLiteral))
430
+ continue ;
431
+ }
432
+
433
+ if (protocol->isSpecificProtocol (
434
+ KnownProtocolKind::ExpressibleByFloatLiteral)) {
435
+ auto *intLiteral = CS.getASTContext ().getProtocol (
436
+ KnownProtocolKind::ExpressibleByIntegerLiteral);
437
+ literalProtocols.erase (intLiteral);
438
+ }
439
+ }
440
+
441
+ literalProtocols.insert (
442
+ {protocol, {isDirectRequirement (constraint), false }});
410
443
}
411
444
412
445
for (auto &binding : Bindings) {
@@ -435,19 +468,20 @@ void ConstraintSystem::PotentialBindings::inferDefaultTypes(
435
468
if (isCovered)
436
469
continue ;
437
470
438
- // FIXME: This is a hack and it's incorrect because it depends
439
- // on ordering of the literal procotols e.g. if `ExpressibleByNilLiteral`
440
- // appears before e.g. `ExpressibleByIntegerLiteral` we'd drop
441
- // optionality although that would be incorrect.
442
471
do {
443
472
// If the type conforms to this protocol, we're covered.
444
473
if (TypeChecker::conformsToProtocol (type, protocol, cs.DC )) {
445
474
isCovered = true ;
446
475
break ;
447
476
}
448
477
478
+ // Can't unwrap optionals if there is `ExpressibleByNilLiteral`
479
+ // conformance requirement placed on the type variable.
480
+ if (canBeNil)
481
+ break ;
482
+
449
483
// If this literal protocol is not a direct requirement it
450
- // would be possible to change optionality while inferring
484
+ // would not be possible to change optionality while inferring
451
485
// bindings for a supertype, so this hack doesn't apply.
452
486
if (!isDirectRequirement)
453
487
break ;
@@ -472,31 +506,23 @@ void ConstraintSystem::PotentialBindings::inferDefaultTypes(
472
506
binding.BindingType = type;
473
507
}
474
508
475
- // If this is not a literal protocol or it has been "covered" by an existing
476
- // binding it can't provide a default type.
477
- auto isUnviableForDefaulting = [&literalProtocols](ProtocolDecl *protocol) {
478
- auto literal = literalProtocols.find (protocol);
479
- return literal == literalProtocols.end () || literal->second .second ;
480
- };
481
-
482
509
for (auto *constraint : Protocols) {
483
510
auto *protocol = constraint->getProtocol ();
484
511
485
- if (isUnviableForDefaulting (protocol))
512
+ auto literal = literalProtocols.find (protocol);
513
+ if (literal == literalProtocols.end ())
486
514
continue ;
487
515
488
- // Let's try to coalesce integer and floating point literal protocols
489
- // if they appear together because the only possible default type that
490
- // could satisfy both requirements is `Double`.
491
- if (protocol->isSpecificProtocol (
492
- KnownProtocolKind::ExpressibleByIntegerLiteral)) {
493
- auto *floatLiteral = cs.getASTContext ().getProtocol (
494
- KnownProtocolKind::ExpressibleByFloatLiteral);
495
- // If `ExpressibleByFloatLiteral` is a requirement and it isn't
496
- // covered, let's skip `ExpressibleByIntegerLiteral` requirement.
497
- if (!isUnviableForDefaulting (floatLiteral))
498
- continue ;
499
- }
516
+ bool isDirectRequirement = false ;
517
+ bool isCovered = false ;
518
+
519
+ std::tie (isDirectRequirement, isCovered) = literal->second ;
520
+
521
+ // Can't be defaulted because it's already covered by an
522
+ // existing direct or transitive binding which is always
523
+ // better.
524
+ if (isCovered)
525
+ continue ;
500
526
501
527
auto defaultType = TypeChecker::getDefaultType (protocol, cs.DC );
502
528
if (!defaultType)
@@ -509,9 +535,8 @@ void ConstraintSystem::PotentialBindings::inferDefaultTypes(
509
535
// requirement or inferred transitive one to identify binding
510
536
// kind correctly.
511
537
addPotentialBinding ({defaultType,
512
- isDirectRequirement (constraint)
513
- ? AllowedBindingKind::Subtypes
514
- : AllowedBindingKind::Supertypes,
538
+ isDirectRequirement ? AllowedBindingKind::Subtypes
539
+ : AllowedBindingKind::Supertypes,
515
540
constraint});
516
541
}
517
542
}
0 commit comments