Skip to content

Commit ece4dd0

Browse files
committed
Merge remote-tracking branch 'origin/master' into master-next
2 parents 9e89373 + 49bd9b2 commit ece4dd0

File tree

4 files changed

+81
-2
lines changed

4 files changed

+81
-2
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1639,7 +1639,44 @@ ConstraintSystem::matchDeepEqualityTypes(Type type1, Type type2,
16391639
// Match up the replacement types of the respective substitution maps.
16401640
return matchDeepTypeArguments(*this, subflags, args1, args2, locator);
16411641
}
1642-
1642+
1643+
// Handle protocol compositions.
1644+
if (auto existential1 = type1->getAs<ProtocolCompositionType>()) {
1645+
if (auto existential2 = type2->getAs<ProtocolCompositionType>()) {
1646+
auto layout1 = existential1->getExistentialLayout();
1647+
auto layout2 = existential2->getExistentialLayout();
1648+
1649+
// Explicit AnyObject and protocols must match exactly.
1650+
if (layout1.hasExplicitAnyObject != layout2.hasExplicitAnyObject)
1651+
return getTypeMatchFailure(locator);
1652+
1653+
if (layout1.getProtocols().size() != layout2.getProtocols().size())
1654+
return getTypeMatchFailure(locator);
1655+
1656+
for (unsigned i: indices(layout1.getProtocols())) {
1657+
if (!layout1.getProtocols()[i]->isEqual(layout2.getProtocols()[i]))
1658+
return getTypeMatchFailure(locator);
1659+
}
1660+
1661+
// This is the only interesting case. We might have type variables
1662+
// on either side of the superclass constraint, so make sure we
1663+
// recursively call matchTypes() here.
1664+
if (layout1.explicitSuperclass || layout2.explicitSuperclass) {
1665+
if (!layout1.explicitSuperclass || !layout2.explicitSuperclass)
1666+
return getTypeMatchFailure(locator);
1667+
1668+
auto result = matchTypes(layout1.explicitSuperclass,
1669+
layout2.explicitSuperclass,
1670+
ConstraintKind::Bind, subflags,
1671+
locator.withPathElement(
1672+
ConstraintLocator::ExistentialSuperclassType));
1673+
if (result.isFailure())
1674+
return result;
1675+
}
1676+
1677+
return getTypeMatchSuccess();
1678+
}
1679+
}
16431680
// Handle nominal types that are not directly generic.
16441681
if (auto nominal1 = type1->getAs<NominalType>()) {
16451682
auto nominal2 = type2->castTo<NominalType>();
@@ -2631,7 +2668,22 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
26312668
llvm_unreachable("Polymorphic function type should have been opened");
26322669

26332670
case TypeKind::ProtocolComposition:
2634-
// Existential types handled below.
2671+
switch (kind) {
2672+
case ConstraintKind::Equal:
2673+
case ConstraintKind::Bind:
2674+
case ConstraintKind::BindParam:
2675+
// If we are matching types for equality, we might still have
2676+
// type variables inside the protocol composition's superclass
2677+
// constraint.
2678+
conversionsOrFixes.push_back(ConversionRestrictionKind::DeepEquality);
2679+
break;
2680+
2681+
default:
2682+
// Subtype constraints where the RHS is an existential type are
2683+
// handled below.
2684+
break;
2685+
}
2686+
26352687
break;
26362688

26372689
case TypeKind::LValue:

lib/Sema/ConstraintLocator.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ void ConstraintLocator::Profile(llvm::FoldingSetNodeID &id, Expr *anchor,
6363
case RValueAdjustment:
6464
case ClosureResult:
6565
case ParentType:
66+
case ExistentialSuperclassType:
6667
case InstanceType:
6768
case SequenceElementType:
6869
case AutoclosureResult:
@@ -309,6 +310,10 @@ void ConstraintLocator::dump(SourceManager *sm, raw_ostream &out) {
309310
out << "parent type";
310311
break;
311312

313+
case ExistentialSuperclassType:
314+
out << "existential superclass type";
315+
break;
316+
312317
case LValueConversion:
313318
out << "@lvalue-to-inout conversion";
314319
break;

lib/Sema/ConstraintLocator.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ class ConstraintLocator : public llvm::FoldingSetNode {
9696
ClosureResult,
9797
/// The parent of a nested type.
9898
ParentType,
99+
/// The superclass of a protocol existential type.
100+
ExistentialSuperclassType,
99101
/// The instance of a metatype type.
100102
InstanceType,
101103
/// The element type of a sequence in a for ... in ... loop.
@@ -157,6 +159,7 @@ class ConstraintLocator : public llvm::FoldingSetNode {
157159
case ClosureResult:
158160
case ParentType:
159161
case InstanceType:
162+
case ExistentialSuperclassType:
160163
case SequenceElementType:
161164
case AutoclosureResult:
162165
case Requirement:
@@ -215,6 +218,7 @@ class ConstraintLocator : public llvm::FoldingSetNode {
215218
case MemberRefBase:
216219
case UnresolvedMember:
217220
case ParentType:
221+
case ExistentialSuperclassType:
218222
case LValueConversion:
219223
case RValueAdjustment:
220224
case SubscriptMember:

test/type/subclass_composition.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,3 +530,21 @@ struct DerivedBox<T : Derived> {}
530530

531531
func takesBoxWithP3(_: DerivedBox<Derived & P3>) {}
532532
// expected-error@-1 {{'DerivedBox' requires that 'Derived & P3' inherit from 'Derived'}}
533+
534+
// A bit of a tricky setup -- the real problem is that matchTypes() did the
535+
// wrong thing when solving a Bind constraint where both sides were protocol
536+
// compositions, but one of them had a superclass constraint containing type
537+
// variables. We were checking type equality in this case, which is not
538+
// correct; we have to do a 'deep equality' check, recursively matching the
539+
// superclass types.
540+
struct Generic<T> {
541+
var _x: (Base<T> & P2)!
542+
543+
var x: (Base<T> & P2)? {
544+
get { return _x }
545+
set { _x = newValue }
546+
_modify {
547+
yield &_x
548+
}
549+
}
550+
}

0 commit comments

Comments
 (0)