Skip to content

Commit 5dced8e

Browse files
committed
[ConstraintSystem] Fix a few constraint system corner cases with explicit
existential types.
1 parent b7c6348 commit 5dced8e

File tree

7 files changed

+106
-43
lines changed

7 files changed

+106
-43
lines changed

lib/AST/DiagnosticEngine.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,24 @@ static bool typeSpellingIsAmbiguous(Type type,
549549
auto argType = arg.getAsType();
550550
if (argType && argType->getWithoutParens().getPointer() != type.getPointer() &&
551551
argType->getWithoutParens().getString(PO) == type.getString(PO)) {
552+
// Currently, existential types are spelled the same way
553+
// as protocols and compositions. We can remove this once
554+
// existenials are printed with 'any'.
555+
if (type->is<ExistentialType>() || argType->isExistentialType()) {
556+
auto constraint = type;
557+
if (auto existential = type->getAs<ExistentialType>())
558+
constraint = existential->getConstraintType();
559+
560+
auto argConstraint = argType;
561+
if (auto existential = argType->getAs<ExistentialType>())
562+
argConstraint = existential->getConstraintType();
563+
564+
if (constraint.getPointer() != argConstraint.getPointer())
565+
return true;
566+
567+
continue;
568+
}
569+
552570
return true;
553571
}
554572
}

lib/Sema/CSDiagnostics.cpp

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,10 @@ ValueDecl *RequirementFailure::getDeclRef() const {
221221
// diagnostic directly to its declaration without desugaring.
222222
if (auto *alias = dyn_cast<TypeAliasType>(type.getPointer()))
223223
return alias->getDecl();
224+
225+
if (auto existential = type->getAs<ExistentialType>())
226+
return existential->getConstraintType()->getAnyGeneric();
227+
224228
return type->getAnyGeneric();
225229
};
226230

@@ -531,10 +535,14 @@ bool MissingConformanceFailure::diagnoseTypeCannotConform(
531535
return false;
532536
}
533537

538+
Type constraintType = nonConformingType;
539+
if (auto existential = constraintType->getAs<ExistentialType>())
540+
constraintType = existential->getConstraintType();
541+
534542
emitDiagnostic(diag::type_cannot_conform,
535543
nonConformingType->isExistentialType(),
536544
nonConformingType,
537-
nonConformingType->isEqual(protocolType),
545+
constraintType->isEqual(protocolType),
538546
protocolType);
539547

540548
bool emittedSpecializedNote = false;
@@ -2328,9 +2336,13 @@ bool ContextualFailure::diagnoseAsError() {
23282336

23292337
if (CTP == CTP_ForEachStmt || CTP == CTP_ForEachSequence) {
23302338
if (fromType->isAnyExistentialType()) {
2339+
Type constraintType = fromType;
2340+
if (auto existential = constraintType->getAs<ExistentialType>())
2341+
constraintType = existential->getConstraintType();
2342+
23312343
emitDiagnostic(diag::type_cannot_conform,
23322344
/*isExistentialType=*/true, fromType,
2333-
fromType->isEqual(toType), toType);
2345+
constraintType->isEqual(toType), toType);
23342346
emitDiagnostic(diag::only_concrete_types_conform_to_protocols);
23352347
return true;
23362348
}
@@ -3063,7 +3075,10 @@ bool ContextualFailure::tryProtocolConformanceFixIt(
30633075
// the protocols of the composition, then store the composition directly.
30643076
// This is because we need to append 'Foo & Bar' instead of 'Foo, Bar' in
30653077
// order to match the written type.
3066-
if (auto compositionTy = unwrappedToType->getAs<ProtocolCompositionType>()) {
3078+
auto constraint = unwrappedToType;
3079+
if (auto existential = constraint->getAs<ExistentialType>())
3080+
constraint = existential->getConstraintType();
3081+
if (auto compositionTy = constraint->getAs<ProtocolCompositionType>()) {
30673082
if (compositionTy->getMembers().size() == missingProtoTypeStrings.size()) {
30683083
missingProtoTypeStrings = {compositionTy->getString()};
30693084
}
@@ -3651,7 +3666,8 @@ bool MissingMemberFailure::diagnoseAsError() {
36513666
diagnostic.highlight(getSourceRange())
36523667
.highlight(nameLoc.getSourceRange());
36533668
correction->addFixits(diagnostic);
3654-
} else if (instanceTy->getAnyNominal() &&
3669+
} else if ((instanceTy->getAnyNominal() ||
3670+
instanceTy->is<ExistentialType>()) &&
36553671
getName().getBaseName() == DeclBaseName::createConstructor()) {
36563672
auto &cs = getConstraintSystem();
36573673

@@ -4123,7 +4139,11 @@ bool AllowTypeOrInstanceMemberFailure::diagnoseAsError() {
41234139
// If we are in a protocol extension of 'Proto' and we see
41244140
// 'Proto.static', suggest 'Self.static'
41254141
if (auto extensionContext = parent->getExtendedProtocolDecl()) {
4126-
if (extensionContext->getDeclaredType()->isEqual(instanceTy)) {
4142+
auto constraint = instanceTy;
4143+
if (auto existential = constraint->getAs<ExistentialType>())
4144+
constraint = existential->getConstraintType();
4145+
4146+
if (extensionContext->getDeclaredType()->isEqual(constraint)) {
41274147
Diag->fixItReplace(getSourceRange(), "Self");
41284148
}
41294149
}
@@ -6838,10 +6858,14 @@ bool AssignmentTypeMismatchFailure::diagnoseMissingConformance() const {
68386858

68396859
auto retrieveProtocols = [](Type type,
68406860
llvm::SmallPtrSetImpl<ProtocolDecl *> &members) {
6841-
if (auto *protocol = type->getAs<ProtocolType>())
6861+
auto constraint = type;
6862+
if (auto existential = constraint->getAs<ExistentialType>())
6863+
constraint = existential->getConstraintType();
6864+
6865+
if (auto *protocol = constraint->getAs<ProtocolType>())
68426866
members.insert(protocol->getDecl());
68436867

6844-
if (auto *composition = type->getAs<ProtocolCompositionType>()) {
6868+
if (auto *composition = constraint->getAs<ProtocolCompositionType>()) {
68456869
for (auto member : composition->getMembers()) {
68466870
if (auto *protocol = member->getAs<ProtocolType>())
68476871
members.insert(protocol->getDecl());

lib/Sema/CSSimplify.cpp

Lines changed: 40 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2886,42 +2886,40 @@ ConstraintSystem::matchDeepEqualityTypes(Type type1, Type type2,
28862886
return result;
28872887
}
28882888

2889-
// Handle protocol compositions.
2890-
if (auto existential1 = type1->getAs<ProtocolCompositionType>()) {
2891-
if (auto existential2 = type2->getAs<ProtocolCompositionType>()) {
2892-
auto layout1 = existential1->getExistentialLayout();
2893-
auto layout2 = existential2->getExistentialLayout();
2894-
2895-
// Explicit AnyObject and protocols must match exactly.
2896-
if (layout1.hasExplicitAnyObject != layout2.hasExplicitAnyObject)
2897-
return getTypeMatchFailure(locator);
2889+
// Handle existential types.
2890+
if (type1->isExistentialType() && type2->isExistentialType()) {
2891+
auto layout1 = type1->getExistentialLayout();
2892+
auto layout2 = type2->getExistentialLayout();
28982893

2899-
if (layout1.getProtocols().size() != layout2.getProtocols().size())
2900-
return getTypeMatchFailure(locator);
2894+
// Explicit AnyObject and protocols must match exactly.
2895+
if (layout1.hasExplicitAnyObject != layout2.hasExplicitAnyObject)
2896+
return getTypeMatchFailure(locator);
29012897

2902-
for (unsigned i: indices(layout1.getProtocols())) {
2903-
if (!layout1.getProtocols()[i]->isEqual(layout2.getProtocols()[i]))
2904-
return getTypeMatchFailure(locator);
2905-
}
2898+
if (layout1.getProtocols().size() != layout2.getProtocols().size())
2899+
return getTypeMatchFailure(locator);
29062900

2907-
// This is the only interesting case. We might have type variables
2908-
// on either side of the superclass constraint, so make sure we
2909-
// recursively call matchTypes() here.
2910-
if (layout1.explicitSuperclass || layout2.explicitSuperclass) {
2911-
if (!layout1.explicitSuperclass || !layout2.explicitSuperclass)
2912-
return getTypeMatchFailure(locator);
2901+
for (unsigned i: indices(layout1.getProtocols())) {
2902+
if (!layout1.getProtocols()[i]->isEqual(layout2.getProtocols()[i]))
2903+
return getTypeMatchFailure(locator);
2904+
}
29132905

2914-
auto result = matchTypes(layout1.explicitSuperclass,
2915-
layout2.explicitSuperclass,
2916-
ConstraintKind::Bind, subflags,
2917-
locator.withPathElement(
2918-
ConstraintLocator::ExistentialSuperclassType));
2919-
if (result.isFailure())
2920-
return result;
2921-
}
2906+
// This is the only interesting case. We might have type variables
2907+
// on either side of the superclass constraint, so make sure we
2908+
// recursively call matchTypes() here.
2909+
if (layout1.explicitSuperclass || layout2.explicitSuperclass) {
2910+
if (!layout1.explicitSuperclass || !layout2.explicitSuperclass)
2911+
return getTypeMatchFailure(locator);
29222912

2923-
return getTypeMatchSuccess();
2913+
auto result = matchTypes(layout1.explicitSuperclass,
2914+
layout2.explicitSuperclass,
2915+
ConstraintKind::Bind, subflags,
2916+
locator.withPathElement(
2917+
ConstraintLocator::ExistentialSuperclassType));
2918+
if (result.isFailure())
2919+
return result;
29242920
}
2921+
2922+
return getTypeMatchSuccess();
29252923
}
29262924
// Handle nominal types that are not directly generic.
29272925
if (auto nominal1 = type1->getAs<NominalType>()) {
@@ -6033,8 +6031,12 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
60336031
return true;
60346032
return false;
60356033
};
6034+
6035+
auto constraintType = meta1->getInstanceType();
6036+
if (auto existential = constraintType->getAs<ExistentialType>())
6037+
constraintType = existential->getConstraintType();
60366038

6037-
if (auto protoTy = meta1->getInstanceType()->getAs<ProtocolType>()) {
6039+
if (auto protoTy = constraintType->getAs<ProtocolType>()) {
60386040
if (protoTy->getDecl()->isObjC()
60396041
&& isProtocolClassType(type2)) {
60406042
increaseScore(ScoreKind::SK_UserConversion);
@@ -7007,7 +7009,12 @@ static bool isCastToExpressibleByNilLiteral(ConstraintSystem &cs, Type fromType,
70077009
if (!nilLiteral)
70087010
return false;
70097011

7010-
return toType->isEqual(nilLiteral->getDeclaredType()) &&
7012+
auto nilLiteralType = nilLiteral->getDeclaredType();
7013+
if (ctx.LangOpts.EnableExplicitExistentialTypes) {
7014+
nilLiteralType = ExistentialType::get(nilLiteralType);
7015+
}
7016+
7017+
return toType->isEqual(nilLiteralType) &&
70117018
fromType->getOptionalObjectType();
70127019
}
70137020

@@ -9808,7 +9815,7 @@ ConstraintSystem::simplifyOpenedExistentialOfConstraint(
98089815
auto instanceTy = type2;
98099816
if (auto metaTy = type2->getAs<ExistentialMetatypeType>()) {
98109817
isMetatype = true;
9811-
instanceTy = metaTy->getInstanceType();
9818+
instanceTy = metaTy->getExistentialInstanceType();
98129819
}
98139820
assert(instanceTy->isExistentialType());
98149821
Type openedTy = OpenedArchetypeType::get(instanceTy);

lib/Sema/ConstraintSystem.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2150,7 +2150,8 @@ Type ConstraintSystem::getEffectiveOverloadType(ConstraintLocator *locator,
21502150
} else if (isa<AbstractFunctionDecl>(decl) || isa<EnumElementDecl>(decl)) {
21512151
if (decl->isInstanceMember() &&
21522152
(!overload.getBaseType() ||
2153-
!overload.getBaseType()->getAnyNominal()))
2153+
(!overload.getBaseType()->getAnyNominal() &&
2154+
!overload.getBaseType()->is<ExistentialType>())))
21542155
return Type();
21552156

21562157
// Cope with 'Self' returns.

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1712,13 +1712,16 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
17121712
// }
17131713
// }
17141714
//
1715+
auto constraint = fromType;
1716+
if (auto existential = constraint->getAs<ExistentialType>())
1717+
constraint = existential->getConstraintType();
17151718
if (auto *protocolDecl =
1716-
dyn_cast_or_null<ProtocolDecl>(fromType->getAnyNominal())) {
1719+
dyn_cast_or_null<ProtocolDecl>(constraint->getAnyNominal())) {
17171720
if (!couldDynamicallyConformToProtocol(toType, protocolDecl, module)) {
17181721
return failed();
17191722
}
17201723
} else if (auto protocolComposition =
1721-
fromType->getAs<ProtocolCompositionType>()) {
1724+
constraint->getAs<ProtocolCompositionType>()) {
17221725
if (llvm::any_of(protocolComposition->getMembers(),
17231726
[&](Type protocolType) {
17241727
if (auto protocolDecl = dyn_cast_or_null<ProtocolDecl>(
@@ -1973,6 +1976,12 @@ static bool checkForDynamicAttribute(CanType ty,
19731976
}
19741977
}
19751978

1979+
// If this is an existential type, check if its constraint type
1980+
// has the attribute.
1981+
if (auto existential = ty->getAs<ExistentialType>()) {
1982+
return hasAttribute(existential->getConstraintType());
1983+
}
1984+
19761985
// If this is a protocol composition, check if any of its members have the
19771986
// attribute.
19781987
if (auto protocolComp = dyn_cast<ProtocolCompositionType>(ty)) {

test/Constraints/common_type_objc.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -verify %s -debug-constraints 2>%t.err
22
// RUN: %FileCheck %s < %t.err
33

4+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -verify -enable-explicit-existential-types %s -debug-constraints 2>%t.err
5+
// RUN: %FileCheck %s < %t.err
6+
47
// REQUIRES: objc_interop
58

69
import Foundation

test/Constraints/openExistential.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// RUN: %target-typecheck-verify-swift
2+
// RUN: %target-typecheck-verify-swift -enable-explicit-existential-types
23

34
protocol P { }
45

0 commit comments

Comments
 (0)