@@ -312,11 +312,8 @@ void ConstraintSystem::PotentialBindings::inferTransitiveBindings(
312
312
// If one of the literal arguments doesn't propagate its
313
313
// `ExpressibleByStringLiteral` conformance, we'd end up picking
314
314
// `T` with only one type `Any?` which is incorrect.
315
- llvm::copy_if (bindings.Protocols , std::back_inserter (Protocols),
316
- [](const Constraint *protocol) {
317
- return protocol->getKind () ==
318
- ConstraintKind::LiteralConformsTo;
319
- });
315
+ for (const auto &literal : bindings.Literals )
316
+ addLiteral (std::get<0 >(literal.second ));
320
317
321
318
// Infer transitive defaults.
322
319
for (const auto &def : bindings.Defaults )
@@ -380,67 +377,11 @@ isUnviableDefaultType(Type defaultType,
380
377
381
378
void ConstraintSystem::PotentialBindings::inferDefaultTypes (
382
379
ConstraintSystem &cs, llvm::SmallPtrSetImpl<CanType> &existingTypes) {
383
- auto isDirectRequirement = [&](Constraint *constraint) -> bool {
384
- if (auto *typeVar = constraint->getFirstType ()->getAs <TypeVariableType>()) {
385
- auto *repr = cs.getRepresentative (typeVar);
386
- return repr == TypeVar;
387
- }
388
-
389
- return false ;
390
- };
391
-
392
- // If we have any literal constraints, check whether there is already a
393
- // binding that provides a type that conforms to that literal protocol. In
394
- // such cases, don't add the default binding suggestion because the existing
395
- // suggestion is better.
396
- //
397
- // Note that ordering is important when it comes to bindings, we'd like to
398
- // add any "direct" default types first to attempt them before transitive
399
- // ones.
400
- //
401
- // Key is a literal protocol requirement, Value indicates whether (first)
402
- // given protocol is a direct requirement, and (second) whether it has been
403
- // covered by an existing binding.
404
- bool canBeNil = false ;
405
- llvm::SmallMapVector<ProtocolDecl *, std::pair<bool , bool >, 4 >
406
- literalProtocols;
407
- for (auto *constraint : Protocols) {
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 }});
443
- }
380
+ bool canBeNil = llvm::any_of (
381
+ Literals, [](const std::pair<ProtocolDecl *, LiteralInfo> &literal) {
382
+ return literal.first ->isSpecificProtocol (
383
+ KnownProtocolKind::ExpressibleByNilLiteral);
384
+ });
444
385
445
386
for (auto &binding : Bindings) {
446
387
Type type;
@@ -460,18 +401,24 @@ void ConstraintSystem::PotentialBindings::inferDefaultTypes(
460
401
continue ;
461
402
462
403
bool requiresUnwrap = false ;
463
- for (auto &entry : literalProtocols ) {
464
- auto *protocol = entry .first ;
465
- bool isDirectRequirement = entry .second . first ;
466
- bool &isCovered = entry .second . second ;
404
+ for (auto &literal : Literals ) {
405
+ auto *protocol = literal .first ;
406
+ bool isDirectRequirement = std::get< 1 >(literal .second ) ;
407
+ Constraint *&coveredBy = std::get< 2 >(literal .second ) ;
467
408
468
- if (isCovered)
409
+ if (coveredBy)
410
+ continue ;
411
+
412
+ // Ignore `ExpressibleByNilLiteral` since it can't produce
413
+ // a default type.
414
+ if (protocol->isSpecificProtocol (
415
+ KnownProtocolKind::ExpressibleByNilLiteral))
469
416
continue ;
470
417
471
418
do {
472
419
// If the type conforms to this protocol, we're covered.
473
420
if (TypeChecker::conformsToProtocol (type, protocol, cs.DC )) {
474
- isCovered = true ;
421
+ coveredBy = binding. getSource () ;
475
422
break ;
476
423
}
477
424
@@ -506,25 +453,20 @@ void ConstraintSystem::PotentialBindings::inferDefaultTypes(
506
453
binding.BindingType = type;
507
454
}
508
455
509
- for (auto *constraint : Protocols) {
510
- auto *protocol = constraint->getProtocol ();
511
-
512
- auto literal = literalProtocols.find (protocol);
513
- if (literal == literalProtocols.end ())
514
- continue ;
515
-
456
+ for (const auto &literal : Literals) {
457
+ Constraint *constraint = nullptr ;
516
458
bool isDirectRequirement = false ;
517
- bool isCovered = false ;
459
+ Constraint *coveredBy = nullptr ;
518
460
519
- std::tie (isDirectRequirement, isCovered ) = literal-> second ;
461
+ std::tie (constraint, isDirectRequirement, coveredBy ) = literal. second ;
520
462
521
463
// Can't be defaulted because it's already covered by an
522
464
// existing direct or transitive binding which is always
523
465
// better.
524
- if (isCovered )
466
+ if (coveredBy )
525
467
continue ;
526
468
527
- auto defaultType = TypeChecker::getDefaultType (protocol , cs.DC );
469
+ auto defaultType = TypeChecker::getDefaultType (literal. first , cs.DC );
528
470
if (!defaultType)
529
471
continue ;
530
472
@@ -584,10 +526,12 @@ ConstraintSystem::determineBestBindings() {
584
526
return true ;
585
527
586
528
return bindings ||
587
- llvm::any_of (bindings.Protocols , [&](Constraint *constraint) {
588
- return bool (
589
- TypeChecker::getDefaultType (constraint->getProtocol (), DC));
590
- });
529
+ llvm::any_of (
530
+ bindings.Literals ,
531
+ [&](const std::pair<ProtocolDecl *,
532
+ PotentialBindings::LiteralInfo> &literal) {
533
+ return bool (TypeChecker::getDefaultType (literal.first , DC));
534
+ });
591
535
};
592
536
593
537
// Now let's see if we could infer something for related type
@@ -716,6 +660,43 @@ void ConstraintSystem::PotentialBindings::addPotentialBinding(
716
660
Bindings.push_back (std::move (binding));
717
661
}
718
662
663
+ void ConstraintSystem::PotentialBindings::addLiteral (Constraint *constraint) {
664
+ auto isDirectRequirement = [&](Constraint *constraint) -> bool {
665
+ if (auto *typeVar = constraint->getFirstType ()->getAs <TypeVariableType>()) {
666
+ auto *repr = CS.getRepresentative (typeVar);
667
+ return repr == TypeVar;
668
+ }
669
+
670
+ return false ;
671
+ };
672
+
673
+ auto *protocol = constraint->getProtocol ();
674
+
675
+ // Let's try to coalesce integer and floating point literal protocols
676
+ // if they appear together because the only possible default type that
677
+ // could satisfy both requirements is `Double`.
678
+ {
679
+ if (protocol->isSpecificProtocol (
680
+ KnownProtocolKind::ExpressibleByIntegerLiteral)) {
681
+ auto *floatLiteral = CS.getASTContext ().getProtocol (
682
+ KnownProtocolKind::ExpressibleByFloatLiteral);
683
+ if (Literals.count (floatLiteral))
684
+ return ;
685
+ }
686
+
687
+ if (protocol->isSpecificProtocol (
688
+ KnownProtocolKind::ExpressibleByFloatLiteral)) {
689
+ auto *intLiteral = CS.getASTContext ().getProtocol (
690
+ KnownProtocolKind::ExpressibleByIntegerLiteral);
691
+ Literals.erase (intLiteral);
692
+ }
693
+ }
694
+
695
+ Literals.insert (
696
+ {protocol, std::make_tuple (constraint, isDirectRequirement (constraint),
697
+ /* coveredBy=*/ nullptr )});
698
+ }
699
+
719
700
bool ConstraintSystem::PotentialBindings::isViable (
720
701
PotentialBinding &binding) const {
721
702
// Prevent against checking against the same opened nominal type
@@ -1129,13 +1110,14 @@ bool ConstraintSystem::PotentialBindings::infer(
1129
1110
if (!protocolTy->is <ProtocolType>())
1130
1111
return false ;
1131
1112
1132
- LLVM_FALLTHROUGH;
1113
+ Protocols.push_back (constraint);
1114
+ break ;
1133
1115
}
1134
1116
1135
1117
case ConstraintKind::LiteralConformsTo: {
1136
1118
// Record constraint where protocol requirement originated
1137
1119
// this is useful to use for the binding later.
1138
- Protocols. push_back (constraint);
1120
+ addLiteral (constraint);
1139
1121
break ;
1140
1122
}
1141
1123
0 commit comments