22
22
using namespace swift ;
23
23
using namespace constraints ;
24
24
25
+ bool ConstraintSystem::PotentialBindings::canBeNil () const {
26
+ auto &ctx = CS.getASTContext ();
27
+ return Literals.count (
28
+ ctx.getProtocol (KnownProtocolKind::ExpressibleByNilLiteral));
29
+ }
30
+
25
31
bool ConstraintSystem::PotentialBinding::isViableForJoin () const {
26
32
return Kind == AllowedBindingKind::Supertypes &&
27
33
!BindingType->hasLValueType () &&
@@ -349,110 +355,8 @@ void ConstraintSystem::PotentialBindings::inferTransitiveBindings(
349
355
}
350
356
}
351
357
352
- static bool
353
- isUnviableDefaultType (Type defaultType,
354
- llvm::SmallPtrSetImpl<CanType> &existingTypes) {
355
- auto canType = defaultType->getCanonicalType ();
356
-
357
- if (!defaultType->hasUnboundGenericType ())
358
- return !existingTypes.insert (canType).second ;
359
-
360
- // For generic literal types, check whether we already have a
361
- // specialization of this generic within our list.
362
- // FIXME: This assumes that, e.g., the default literal
363
- // int/float/char/string types are never generic.
364
- auto nominal = defaultType->getAnyNominal ();
365
- if (!nominal)
366
- return true ;
367
-
368
- if (llvm::any_of (existingTypes, [&nominal](CanType existingType) {
369
- // FIXME: Check parents?
370
- return nominal == existingType->getAnyNominal ();
371
- }))
372
- return true ;
373
-
374
- existingTypes.insert (canType);
375
- return false ;
376
- }
377
-
378
358
void ConstraintSystem::PotentialBindings::inferDefaultTypes (
379
359
ConstraintSystem &cs, llvm::SmallPtrSetImpl<CanType> &existingTypes) {
380
- bool canBeNil = llvm::any_of (
381
- Literals, [](const std::pair<ProtocolDecl *, LiteralInfo> &literal) {
382
- return literal.first ->isSpecificProtocol (
383
- KnownProtocolKind::ExpressibleByNilLiteral);
384
- });
385
-
386
- for (auto &binding : Bindings) {
387
- Type type;
388
-
389
- switch (binding.Kind ) {
390
- case AllowedBindingKind::Exact:
391
- type = binding.BindingType ;
392
- break ;
393
-
394
- case AllowedBindingKind::Subtypes:
395
- case AllowedBindingKind::Supertypes:
396
- type = binding.BindingType ->getRValueType ();
397
- break ;
398
- }
399
-
400
- if (type->isTypeVariableOrMember () || type->isHole ())
401
- continue ;
402
-
403
- bool requiresUnwrap = false ;
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 );
408
-
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))
416
- continue ;
417
-
418
- do {
419
- // If the type conforms to this protocol, we're covered.
420
- if (TypeChecker::conformsToProtocol (type, protocol, cs.DC )) {
421
- coveredBy = binding.getSource ();
422
- break ;
423
- }
424
-
425
- // Can't unwrap optionals if there is `ExpressibleByNilLiteral`
426
- // conformance requirement placed on the type variable.
427
- if (canBeNil)
428
- break ;
429
-
430
- // If this literal protocol is not a direct requirement it
431
- // would not be possible to change optionality while inferring
432
- // bindings for a supertype, so this hack doesn't apply.
433
- if (!isDirectRequirement)
434
- break ;
435
-
436
- // If we're allowed to bind to subtypes, look through optionals.
437
- // FIXME: This is really crappy special case of computing a reasonable
438
- // result based on the given constraints.
439
- if (binding.Kind == AllowedBindingKind::Subtypes) {
440
- if (auto objTy = type->getOptionalObjectType ()) {
441
- requiresUnwrap = true ;
442
- type = objTy;
443
- continue ;
444
- }
445
- }
446
-
447
- requiresUnwrap = false ;
448
- break ;
449
- } while (true );
450
- }
451
-
452
- if (requiresUnwrap)
453
- binding.BindingType = type;
454
- }
455
-
456
360
for (const auto &literal : Literals) {
457
361
Constraint *constraint = nullptr ;
458
362
bool isDirectRequirement = false ;
@@ -470,9 +374,6 @@ void ConstraintSystem::PotentialBindings::inferDefaultTypes(
470
374
if (!defaultType)
471
375
continue ;
472
376
473
- if (isUnviableDefaultType (defaultType, existingTypes))
474
- continue ;
475
-
476
377
// We need to figure out whether this is a direct conformance
477
378
// requirement or inferred transitive one to identify binding
478
379
// kind correctly.
@@ -611,6 +512,86 @@ void ConstraintSystem::PotentialBindings::addDefault(Constraint *constraint) {
611
512
Defaults.insert ({defaultTy->getCanonicalType (), constraint});
612
513
}
613
514
515
+ static bool isCoveredBy (ProtocolDecl *protocol, Type type, DeclContext *useDC) {
516
+ auto coversDefaultType = [](Type type, Type defaultType) -> bool {
517
+ if (!defaultType->hasUnboundGenericType ())
518
+ return type->isEqual (defaultType);
519
+
520
+ // For generic literal types, check whether we already have a
521
+ // specialization of this generic within our list.
522
+ // FIXME: This assumes that, e.g., the default literal
523
+ // int/float/char/string types are never generic.
524
+ auto nominal = defaultType->getAnyNominal ();
525
+ if (!nominal)
526
+ return false ;
527
+
528
+ // FIXME: Check parents?
529
+ return nominal == type->getAnyNominal ();
530
+ };
531
+
532
+ if (auto defaultType = TypeChecker::getDefaultType (protocol, useDC)) {
533
+ if (coversDefaultType (type, defaultType))
534
+ return true ;
535
+ }
536
+
537
+ return bool (TypeChecker::conformsToProtocol (type, protocol, useDC));
538
+ }
539
+
540
+ bool ConstraintSystem::PotentialBindings::isLiteralCoveredBy (
541
+ ProtocolDecl *literal, PotentialBinding &binding, bool canBeNil,
542
+ bool isDirectRequirement) const {
543
+ auto type = binding.BindingType ;
544
+ switch (binding.Kind ) {
545
+ case AllowedBindingKind::Exact:
546
+ type = binding.BindingType ;
547
+ break ;
548
+
549
+ case AllowedBindingKind::Subtypes:
550
+ case AllowedBindingKind::Supertypes:
551
+ type = binding.BindingType ->getRValueType ();
552
+ break ;
553
+ }
554
+
555
+ if (type->isTypeVariableOrMember () || type->isHole ())
556
+ return false ;
557
+
558
+ bool requiresUnwrap = false ;
559
+ do {
560
+ if (isCoveredBy (literal, type, CS.DC )) {
561
+ // FIXME: Side-effect like this is not great (to say the least),
562
+ // but this is an artifact of the binding collection which could
563
+ // be fixed separately.
564
+ if (requiresUnwrap)
565
+ binding.BindingType = type;
566
+ return true ;
567
+ }
568
+
569
+ // Can't unwrap optionals if there is `ExpressibleByNilLiteral`
570
+ // conformance requirement placed on the type variable.
571
+ if (canBeNil)
572
+ return false ;
573
+
574
+ // If this literal protocol is not a direct requirement it
575
+ // would not be possible to change optionality while inferring
576
+ // bindings for a supertype, so this hack doesn't apply.
577
+ if (!isDirectRequirement)
578
+ return false ;
579
+
580
+ // If we're allowed to bind to subtypes, look through optionals.
581
+ // FIXME: This is really crappy special case of computing a reasonable
582
+ // result based on the given constraints.
583
+ if (binding.Kind == AllowedBindingKind::Subtypes) {
584
+ if (auto objTy = type->getOptionalObjectType ()) {
585
+ requiresUnwrap = true ;
586
+ type = objTy;
587
+ continue ;
588
+ }
589
+ }
590
+
591
+ return false ;
592
+ } while (true );
593
+ }
594
+
614
595
void ConstraintSystem::PotentialBindings::addPotentialBinding (
615
596
PotentialBinding binding, bool allowJoinMeet) {
616
597
assert (!binding.BindingType ->is <ErrorType>());
@@ -654,6 +635,29 @@ void ConstraintSystem::PotentialBindings::addPotentialBinding(
654
635
if (!isViable (binding))
655
636
return ;
656
637
638
+ // Check whether the given binding covers any of the literal protocols
639
+ // associated with this type variable.
640
+ {
641
+ bool allowsNil = canBeNil ();
642
+
643
+ for (auto &literal : Literals) {
644
+ auto *protocol = literal.first ;
645
+
646
+ // Skip conformance to `nil` protocol since it doesn't
647
+ // have a default type and can't affect binding set.
648
+ if (protocol->isSpecificProtocol (
649
+ KnownProtocolKind::ExpressibleByNilLiteral))
650
+ continue ;
651
+
652
+ auto isDirectRequirement = std::get<1 >(literal.second );
653
+ auto *&coveredBy = std::get<2 >(literal.second );
654
+
655
+ if (!coveredBy &&
656
+ isLiteralCoveredBy (protocol, binding, allowsNil, isDirectRequirement))
657
+ coveredBy = binding.getSource ();
658
+ }
659
+ }
660
+
657
661
Bindings.push_back (std::move (binding));
658
662
}
659
663
@@ -689,9 +693,36 @@ void ConstraintSystem::PotentialBindings::addLiteral(Constraint *constraint) {
689
693
}
690
694
}
691
695
692
- Literals.insert (
693
- {protocol, std::make_tuple (constraint, isDirectRequirement (constraint),
694
- /* coveredBy=*/ nullptr )});
696
+ if (Literals.count (protocol) > 0 )
697
+ return ;
698
+
699
+ bool isDirect = isDirectRequirement (constraint);
700
+ Constraint *coveredBy = nullptr ;
701
+
702
+ // Coverage is not applicable to `ExpressibleByNilLiteral` since it
703
+ // doesn't have a default type.
704
+ if (protocol->isSpecificProtocol (
705
+ KnownProtocolKind::ExpressibleByNilLiteral)) {
706
+ Literals.insert (
707
+ {protocol, std::make_tuple (constraint, isDirect, coveredBy)});
708
+ return ;
709
+ }
710
+
711
+ // Check whether any of the existing bindings covers this literal
712
+ // protocol.
713
+ {
714
+ bool allowsNil = canBeNil ();
715
+
716
+ for (auto &binding : Bindings) {
717
+ if (!coveredBy &&
718
+ isLiteralCoveredBy (protocol, binding, allowsNil, isDirect)) {
719
+ coveredBy = binding.getSource ();
720
+ break ;
721
+ }
722
+ }
723
+ }
724
+
725
+ Literals.insert ({protocol, std::make_tuple (constraint, isDirect, coveredBy)});
695
726
}
696
727
697
728
bool ConstraintSystem::PotentialBindings::isViable (
0 commit comments