@@ -5485,146 +5485,89 @@ NeverNullType TypeResolver::resolveTupleType(TupleTypeRepr *repr,
5485
5485
return TupleType::get (elements, ctx);
5486
5486
}
5487
5487
5488
- // / \returns the inverse ~P that is conflicted if a protocol in \c tys
5489
- // / requires P. For example, `Q & ~Copyable` is a conflict, if `Q` requires
5490
- // / or is equal to `Copyable`
5491
- static std::optional<InvertibleProtocolKind>
5492
- hasConflictedInverse (ArrayRef<Type> tys, InvertibleProtocolSet inverses) {
5493
- // Fast-path: no inverses that could be conflicted!
5494
- if (inverses.empty ())
5495
- return std::nullopt;
5496
-
5497
- for (auto ty : tys) {
5498
- // Handle nested PCT's recursively since we haven't flattened them away yet.
5499
- if (auto pct = dyn_cast<ProtocolCompositionType>(ty)) {
5500
- if (auto conflict = hasConflictedInverse (pct->getMembers (), inverses))
5501
- return conflict;
5502
- continue ;
5503
- }
5504
-
5505
- // Dig out a protocol.
5506
- ProtocolDecl *decl = nullptr ;
5507
- if (auto protoTy = dyn_cast<ProtocolType>(ty))
5508
- decl = protoTy->getDecl ();
5509
- else if (auto paramProtoTy = dyn_cast<ParameterizedProtocolType>(ty))
5510
- decl = paramProtoTy->getProtocol ();
5511
-
5512
- if (!decl)
5513
- continue ;
5514
-
5515
- // If an inverse ~I exists for this protocol member of the PCT that
5516
- // requires I, then it's a conflict.
5517
- for (auto inverse : inverses) {
5518
- if (decl->isSpecificProtocol (getKnownProtocolKind (inverse))
5519
- || decl->requiresInvertible (inverse)) {
5520
- return inverse;
5521
- }
5522
- }
5523
- }
5524
-
5525
- return std::nullopt;
5526
- }
5527
-
5528
5488
NeverNullType
5529
5489
TypeResolver::resolveCompositionType (CompositionTypeRepr *repr,
5530
5490
TypeResolutionOptions options) {
5531
5491
5492
+ SmallVector<Type, 4 > Members;
5493
+
5532
5494
// Note that the superclass type will appear as part of one of the
5533
5495
// types in 'Members', so it's not used when constructing the
5534
5496
// fully-realized type below -- but we just record it to make sure
5535
5497
// there is only one superclass.
5536
5498
Type SuperclassType;
5537
- SmallVector<Type, 4 > Members;
5538
- InvertibleProtocolSet Inverses;
5539
- bool HasAnyObject = false ;
5540
5499
5541
- // Whether we saw at least one protocol. A protocol composition
5542
- // must either be empty (in which case it is Any or AnyObject),
5543
- // or if it has a superclass constraint, have at least one protocol.
5544
- bool HasProtocol = false ;
5500
+ // Did we see at least one protocol or inverse?
5501
+ bool HasNonClassMember = false ;
5545
5502
5546
- auto checkSuperclass = [&](SourceLoc loc, Type t) -> bool {
5547
- if (SuperclassType && !SuperclassType->isEqual (t)) {
5548
- diagnose (loc, diag::protocol_composition_one_class, t,
5503
+ // If true, we cannot form a composition from these members.
5504
+ bool IsInvalid = false ;
5505
+
5506
+ std::function<void (SourceLoc, Type)> checkMember
5507
+ = [&](SourceLoc loc, Type ty) {
5508
+ if (auto pct = ty->getAs <ProtocolCompositionType>()) {
5509
+ if (!pct->getInverses ().empty ())
5510
+ HasNonClassMember = true ;
5511
+
5512
+ for (auto member : pct->getMembers ())
5513
+ checkMember (loc, member);
5514
+ return ;
5515
+ }
5516
+
5517
+ if (ty->is <ProtocolType>() ||
5518
+ ty->is <ParameterizedProtocolType>()) {
5519
+ HasNonClassMember = true ;
5520
+ return ;
5521
+ }
5522
+
5523
+ assert (isa<ClassDecl>(ty->getAnyNominal ()));
5524
+
5525
+ if (SuperclassType && !SuperclassType->isEqual (ty)) {
5526
+ diagnose (loc, diag::protocol_composition_one_class, ty,
5549
5527
SuperclassType);
5550
- return true ;
5528
+ IsInvalid = true ;
5529
+ return ;
5551
5530
}
5552
5531
5553
- SuperclassType = t;
5554
- return false ;
5532
+ SuperclassType = ty;
5555
5533
};
5556
5534
5557
- bool IsInvalid = false ;
5558
-
5559
5535
for (auto tyR : repr->getTypes ()) {
5560
5536
auto ty = resolveType (tyR,
5561
5537
options.withContext (TypeResolverContext::GenericRequirement));
5562
5538
if (ty->hasError ()) return ty;
5563
5539
5564
- auto nominalDecl = ty->getAnyNominal ();
5565
- if (isa_and_nonnull<ClassDecl>(nominalDecl)) {
5566
- if (checkSuperclass (tyR->getStartLoc (), ty))
5567
- continue ;
5568
-
5540
+ if (ty->is <ProtocolType>()) {
5541
+ checkMember (tyR->getStartLoc (), ty);
5569
5542
Members.push_back (ty);
5570
5543
continue ;
5571
5544
}
5572
5545
5573
5546
// FIXME: Support compositions involving parameterized protocol types,
5574
5547
// like 'any Collection<String> & Sendable', etc.
5575
- if (ty->isConstraintType ()) {
5576
- if (ty->is <ProtocolType>()) {
5577
- HasProtocol = true ;
5578
- Members.push_back (ty);
5579
- continue ;
5580
- }
5581
-
5582
- if (ty->is <ParameterizedProtocolType>() &&
5583
- !options.isConstraintImplicitExistential () &&
5584
- options.getContext () != TypeResolverContext::ExistentialConstraint) {
5585
- HasProtocol = true ;
5586
- Members.push_back (ty);
5587
- continue ;
5588
- }
5548
+ if (ty->is <ParameterizedProtocolType>() &&
5549
+ !options.isConstraintImplicitExistential () &&
5550
+ options.getContext () != TypeResolverContext::ExistentialConstraint) {
5551
+ checkMember (tyR->getStartLoc (), ty);
5552
+ Members.push_back (ty);
5553
+ continue ;
5554
+ }
5589
5555
5590
- if (auto pct = ty->getAs <ProtocolCompositionType>()) {
5591
- auto layout = ty->getExistentialLayout ();
5592
- if (auto superclass = layout.explicitSuperclass )
5593
- if (checkSuperclass (tyR->getStartLoc (), superclass))
5594
- continue ;
5595
- if (!layout.getProtocols ().empty ())
5596
- HasProtocol = true ;
5597
- if (layout.hasExplicitAnyObject )
5598
- HasAnyObject = true ;
5556
+ if (ty->is <ProtocolCompositionType>()) {
5557
+ checkMember (tyR->getStartLoc (), ty);
5558
+ Members.push_back (ty);
5559
+ continue ;
5560
+ }
5599
5561
5600
- Inverses. insertAll (pct-> getInverses ());
5601
- Members. push_back ( ty);
5602
- continue ;
5603
- }
5562
+ if (isa_and_nonnull<ClassDecl>(ty-> getAnyNominal ())) {
5563
+ checkMember (tyR-> getStartLoc (), ty);
5564
+ Members. push_back (ty) ;
5565
+ continue ;
5604
5566
}
5605
5567
5606
5568
diagnose (tyR->getStartLoc (),
5607
5569
diag::invalid_protocol_composition_member,
5608
5570
ty);
5609
-
5610
- IsInvalid = true ;
5611
- }
5612
-
5613
- // Cannot combine inverses with Superclass or AnyObject in a composition.
5614
- if ((SuperclassType || HasAnyObject) && !Inverses.empty ()) {
5615
- diagnose (repr->getStartLoc (),
5616
- diag::inverse_with_class_constraint,
5617
- HasAnyObject,
5618
- getProtocolName (getKnownProtocolKind (*Inverses.begin ())),
5619
- SuperclassType);
5620
- IsInvalid = true ;
5621
- }
5622
-
5623
- // Cannot provide an inverse in the same composition requiring the protocol.
5624
- if (auto conflict = hasConflictedInverse (Members, Inverses)) {
5625
- diagnose (repr->getLoc (),
5626
- diag::inverse_conflicts_explicit_composition,
5627
- getProtocolName (getKnownProtocolKind (*conflict)));
5628
5571
IsInvalid = true ;
5629
5572
}
5630
5573
@@ -5636,17 +5579,58 @@ TypeResolver::resolveCompositionType(CompositionTypeRepr *repr,
5636
5579
// Avoid confusing diagnostics ('MyClass' not convertible to 'MyClass',
5637
5580
// etc) by collapsing a composition consisting of a single class down
5638
5581
// to the class itself.
5639
- if (SuperclassType && !HasProtocol )
5582
+ if (SuperclassType && !HasNonClassMember )
5640
5583
return SuperclassType;
5641
5584
5642
- // In user-written types, AnyObject constraints always refer to the
5643
- // AnyObject type in the standard library.
5644
5585
auto composition =
5645
- ProtocolCompositionType::get (getASTContext (), Members, Inverses,
5586
+ ProtocolCompositionType::get (getASTContext (), Members,
5587
+ /* Inverses=*/ {},
5646
5588
/* HasExplicitAnyObject=*/ false );
5589
+
5590
+ // Flatten the composition.
5591
+ if (auto canComposition = dyn_cast<ProtocolCompositionType>(
5592
+ composition->getCanonicalType ())) {
5593
+ auto inverses = canComposition->getInverses ();
5594
+ auto layout = composition->getExistentialLayout ();
5595
+
5596
+ // Cannot provide an inverse in the same composition requiring the protocol.
5597
+ for (auto ip : inverses) {
5598
+ auto kp = getKnownProtocolKind (ip);
5599
+
5600
+ if (layout.requiresClass ()) {
5601
+ bool hasExplicitAnyObject = layout.hasExplicitAnyObject ;
5602
+ diagnose (repr->getStartLoc (),
5603
+ diag::inverse_with_class_constraint,
5604
+ hasExplicitAnyObject,
5605
+ getProtocolName (kp),
5606
+ layout.getSuperclass ());
5607
+ IsInvalid = true ;
5608
+ break ;
5609
+ }
5610
+
5611
+ auto *proto = getASTContext ().getProtocol (kp);
5612
+ for (auto *otherProto : layout.getProtocols ()) {
5613
+ if (proto == otherProto ||
5614
+ otherProto->inheritsFrom (proto)) {
5615
+ diagnose (repr->getLoc (),
5616
+ diag::inverse_conflicts_explicit_composition,
5617
+ getProtocolName (kp));
5618
+ IsInvalid = true ;
5619
+ break ;
5620
+ }
5621
+ }
5622
+ }
5623
+ }
5624
+
5625
+ if (IsInvalid) {
5626
+ repr->setInvalid ();
5627
+ return ErrorType::get (getASTContext ());
5628
+ }
5629
+
5647
5630
if (options.isConstraintImplicitExistential ()) {
5648
5631
return ExistentialType::get (composition);
5649
5632
}
5633
+
5650
5634
return composition;
5651
5635
}
5652
5636
0 commit comments