Skip to content

Commit 3eabc21

Browse files
committed
AST: Remove TypeBase::hasDependentProtocolConformances()
Another oddly-named utility function with poorly-defined behavior. It returned true for archetypes, generic parameters, existential types, and metatypes of existential types. However, it would return false for dependent member types, or metatypes of archetypes, and so on. All the callers were doing something bad to begin with, so changing them over to more precise predicates improved the code. In particular, this simplifies substitution construction in the SIL parser, and makes it stricter, which turned up a couple of mistakes in the SIL tests where we were doing stuff with non-conforming types.
1 parent e59cdc8 commit 3eabc21

File tree

7 files changed

+61
-143
lines changed

7 files changed

+61
-143
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -508,7 +508,8 @@ ERROR(sil_member_lookup_bad_type,none,
508508
ERROR(sil_member_decl_type_mismatch,none,
509509
"member defined with mismatching type %0 (expected %1)", (Type, Type))
510510
ERROR(sil_substitution_mismatch,none,
511-
"substitution conformances don't match archetype", ())
511+
"substitution replacement type %0 does not conform to protocol %1",
512+
(Type, DeclName))
512513
ERROR(sil_missing_substitutions,none,
513514
"missing substitutions", ())
514515
ERROR(sil_too_many_substitutions,none,

include/swift/AST/Types.h

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -938,13 +938,6 @@ class alignas(1 << TypeAlignInBits) TypeBase {
938938
/// Return whether this type is or can be substituted for a bridgeable
939939
/// object type.
940940
TypeTraitResult canBeClass();
941-
942-
/// Returns true if the type conforms to protocols using witnesses from the
943-
/// environment or from within the value. Generic parameters and existentials
944-
/// meet this criteria. In these cases we represent the
945-
/// conformance as a null ProtocolConformance* pointer, because there is no
946-
/// static conformance associated with the conforming type.
947-
bool hasDependentProtocolConformances();
948941

949942
private:
950943
// Make vanilla new/delete illegal for Types.
@@ -4615,11 +4608,6 @@ inline CanType Type::getCanonicalTypeOrNull() const {
46154608
return isNull() ? CanType() : getPointer()->getCanonicalType();
46164609
}
46174610

4618-
inline bool TypeBase::hasDependentProtocolConformances() {
4619-
return is<SubstitutableType>() || is<GenericTypeParamType>()
4620-
|| isAnyExistentialType();
4621-
}
4622-
46234611
#define TYPE(id, parent)
46244612
#define SUGARED_TYPE(id, parent) \
46254613
template <> \

lib/AST/Substitution.cpp

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -92,15 +92,10 @@ Substitution Substitution::subst(Module *module,
9292
conformance = ProtocolConformanceRef(lookupResults.front());
9393
}
9494

95-
if (conformance) {
96-
if (conformance->isConcrete())
97-
conformancesChanged = true;
98-
substConformances.push_back(*conformance);
99-
} else {
100-
assert(substReplacement->hasDependentProtocolConformances() &&
101-
"couldn't find concrete conformance for concrete type?");
102-
substConformances.push_back(ProtocolConformanceRef(proto));
103-
}
95+
assert(conformance);
96+
if (conformance->isConcrete())
97+
conformancesChanged = true;
98+
substConformances.push_back(*conformance);
10499
}
105100
assert(substConformances.size() == Conformance.size());
106101

lib/Parse/ParseSIL.cpp

Lines changed: 34 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,10 @@ namespace {
217217

218218
/// @{ Type parsing.
219219
bool parseASTType(CanType &result);
220+
bool parseASTType(CanType &result, SourceLoc &TypeLoc) {
221+
TypeLoc = P.Tok.getLoc();
222+
return parseASTType(result);
223+
}
220224
bool parseSILType(SILType &Result,
221225
GenericEnvironment *&genericEnv,
222226
bool IsFuncDecl = false);
@@ -1277,71 +1281,24 @@ bool SILParser::parseSubstitutions(SmallVectorImpl<ParsedSubstitution> &parsed,
12771281
return false;
12781282
}
12791283

1280-
/// Get ProtocolConformance for a replacement type.
1281-
static ProtocolConformance*
1282-
getConformanceOfReplacement(Parser &P, Type subReplacement,
1283-
ProtocolDecl *proto) {
1284-
auto conformance = P.SF.getParentModule()->lookupConformance(
1285-
subReplacement, proto, nullptr);
1286-
if (conformance && conformance->isConcrete())
1287-
return conformance->getConcrete();
1288-
return nullptr;
1289-
}
1290-
1291-
static bool isImpliedBy(ProtocolDecl *proto, ArrayRef<ProtocolDecl*> derived) {
1292-
for (auto derivedProto : derived) {
1293-
if (derivedProto == proto || derivedProto->inheritsFrom(proto))
1294-
return true;
1295-
}
1296-
return false;
1297-
}
1298-
1299-
static bool allowAbstractConformance(Parser &P, Type subReplacement,
1300-
ProtocolDecl *proto) {
1301-
if (!subReplacement->hasDependentProtocolConformances())
1302-
return false;
1303-
1304-
// AnyObject is implicitly conformed to by anything with a class bound.
1305-
if (proto->isSpecificProtocol(KnownProtocolKind::AnyObject) &&
1306-
subReplacement->isAnyClassReferenceType()) {
1307-
return true;
1308-
}
1309-
1310-
if (auto archetype = subReplacement->getAs<ArchetypeType>()) {
1311-
return isImpliedBy(proto, archetype->getConformsTo());
1312-
}
1313-
1314-
SmallVector<ProtocolDecl *, 4> existentialProtos;
1315-
if (subReplacement->isExistentialType(existentialProtos)) {
1316-
return isImpliedBy(proto, existentialProtos);
1317-
}
1318-
1319-
return false;
1320-
}
1321-
13221284
/// Collect conformances by looking up the conformance from replacement
13231285
/// type and protocol decl.
13241286
static bool getConformancesForSubstitution(Parser &P,
13251287
ArrayRef<ProtocolDecl *> protocols,
13261288
Type subReplacement,
13271289
SourceLoc loc,
13281290
SmallVectorImpl<ProtocolConformanceRef> &conformances) {
1329-
for (auto proto : protocols) {
1330-
// Try looking up a concrete conformance.
1331-
if (auto conformance =
1332-
getConformanceOfReplacement(P, subReplacement, proto)) {
1333-
conformances.push_back(ProtocolConformanceRef(conformance));
1334-
continue;
1335-
}
1291+
auto M = P.SF.getParentModule();
13361292

1337-
// If the replacement type has dependent conformances, we might be
1338-
// able to use an abstract conformance.
1339-
if (allowAbstractConformance(P, subReplacement, proto)) {
1340-
conformances.push_back(ProtocolConformanceRef(proto));
1293+
for (auto proto : protocols) {
1294+
auto conformance = M->lookupConformance(subReplacement, proto, nullptr);
1295+
if (conformance) {
1296+
conformances.push_back(*conformance);
13411297
continue;
13421298
}
13431299

1344-
P.diagnose(loc, diag::sil_substitution_mismatch);
1300+
P.diagnose(loc, diag::sil_substitution_mismatch, subReplacement,
1301+
proto->getName());
13451302
return true;
13461303
}
13471304

@@ -1403,25 +1360,20 @@ bool getApplySubstitutionsFromParsed(
14031360
}
14041361

14051362
static ArrayRef<ProtocolConformanceRef>
1406-
collectExistentialConformances(Parser &P,
1407-
CanType conformingType, CanType protocolType) {
1363+
collectExistentialConformances(Parser &P, CanType conformingType, SourceLoc loc,
1364+
CanType protocolType) {
14081365
SmallVector<ProtocolDecl *, 2> protocols;
14091366
bool isExistential = protocolType->isAnyExistentialType(protocols);
14101367
assert(isExistential);
14111368
(void)isExistential;
14121369
if (protocols.empty())
14131370
return {};
1414-
1415-
MutableArrayRef<ProtocolConformanceRef> conformances =
1416-
P.Context.AllocateUninitialized<ProtocolConformanceRef>(protocols.size());
1417-
1418-
for (unsigned i : indices(protocols)) {
1419-
auto proto = protocols[i];
1420-
auto conformance = getConformanceOfReplacement(P, conformingType, proto);
1421-
conformances[i] = ProtocolConformanceRef(proto, conformance);
1422-
}
1423-
1424-
return conformances;
1371+
1372+
SmallVector<ProtocolConformanceRef, 2> conformances;
1373+
getConformancesForSubstitution(P, protocols, conformingType,
1374+
loc, conformances);
1375+
1376+
return P.Context.AllocateCopy(conformances);
14251377
}
14261378

14271379
/// sil-loc ::= 'loc' string-literal ':' [0-9]+ ':' [0-9]+
@@ -3568,10 +3520,11 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB, SILBuilder &B) {
35683520
}
35693521
case ValueKind::InitExistentialAddrInst: {
35703522
CanType Ty;
3523+
SourceLoc TyLoc;
35713524
if (parseTypedValueRef(Val, B) ||
35723525
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
35733526
P.parseToken(tok::sil_dollar, diag::expected_tok_in_sil_instr, "$") ||
3574-
parseASTType(Ty) ||
3527+
parseASTType(Ty, TyLoc) ||
35753528
parseSILDebugLocation(InstLoc, B))
35763529
return true;
35773530

@@ -3586,7 +3539,7 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB, SILBuilder &B) {
35863539

35873540
// Collect conformances for the type.
35883541
ArrayRef<ProtocolConformanceRef> conformances
3589-
= collectExistentialConformances(P, Ty,
3542+
= collectExistentialConformances(P, Ty, TyLoc,
35903543
Val->getType().getSwiftRValueType());
35913544

35923545
ResultVal = B.createInitExistentialAddr(InstLoc, Val, Ty, LoweredTy,
@@ -3596,17 +3549,18 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB, SILBuilder &B) {
35963549
case ValueKind::AllocExistentialBoxInst: {
35973550
SILType ExistentialTy;
35983551
CanType ConcreteFormalTy;
3552+
SourceLoc TyLoc;
35993553

36003554
if (parseSILType(ExistentialTy) ||
36013555
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
36023556
P.parseToken(tok::sil_dollar, diag::expected_tok_in_sil_instr, "$") ||
3603-
parseASTType(ConcreteFormalTy) ||
3557+
parseASTType(ConcreteFormalTy, TyLoc) ||
36043558
parseSILDebugLocation(InstLoc, B))
36053559
return true;
36063560

36073561
// Collect conformances for the type.
36083562
ArrayRef<ProtocolConformanceRef> conformances
3609-
= collectExistentialConformances(P, ConcreteFormalTy,
3563+
= collectExistentialConformances(P, ConcreteFormalTy, TyLoc,
36103564
ExistentialTy.getSwiftRValueType());
36113565

36123566
ResultVal = B.createAllocExistentialBox(InstLoc, ExistentialTy,
@@ -3617,17 +3571,19 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB, SILBuilder &B) {
36173571
case ValueKind::InitExistentialRefInst: {
36183572
CanType FormalConcreteTy;
36193573
SILType ExistentialTy;
3574+
SourceLoc TyLoc;
3575+
36203576
if (parseTypedValueRef(Val, B) ||
36213577
P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":") ||
36223578
P.parseToken(tok::sil_dollar, diag::expected_tok_in_sil_instr, "$") ||
3623-
parseASTType(FormalConcreteTy) ||
3579+
parseASTType(FormalConcreteTy, TyLoc) ||
36243580
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
36253581
parseSILType(ExistentialTy) ||
36263582
parseSILDebugLocation(InstLoc, B))
36273583
return true;
36283584

36293585
ArrayRef<ProtocolConformanceRef> conformances
3630-
= collectExistentialConformances(P, FormalConcreteTy,
3586+
= collectExistentialConformances(P, FormalConcreteTy, TyLoc,
36313587
ExistentialTy.getSwiftRValueType());
36323588

36333589
// FIXME: Conformances in InitExistentialRefInst is currently not included
@@ -3638,10 +3594,11 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB, SILBuilder &B) {
36383594
break;
36393595
}
36403596
case ValueKind::InitExistentialMetatypeInst: {
3597+
SourceLoc TyLoc;
36413598
SILType ExistentialTy;
36423599
if (parseTypedValueRef(Val, B) ||
36433600
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
3644-
parseSILType(ExistentialTy) ||
3601+
parseSILType(ExistentialTy, TyLoc) ||
36453602
parseSILDebugLocation(InstLoc, B))
36463603
return true;
36473604

@@ -3654,7 +3611,7 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB, SILBuilder &B) {
36543611
}
36553612

36563613
ArrayRef<ProtocolConformanceRef> conformances
3657-
= collectExistentialConformances(P, formalConcreteType,
3614+
= collectExistentialConformances(P, formalConcreteType, TyLoc,
36583615
ExistentialTy.getSwiftRValueType());
36593616

36603617
ResultVal = B.createInitExistentialMetatype(InstLoc, Val, ExistentialTy,
@@ -4388,9 +4345,8 @@ static NormalProtocolConformance *parseNormalProtocolConformance(Parser &P,
43884345
// Calling lookupConformance on a BoundGenericType will return a specialized
43894346
// conformance. We use UnboundGenericType to find the normal conformance.
43904347
Type lookupTy = ConformingTy;
4391-
if (auto bound = dyn_cast<BoundGenericType>(lookupTy.getPointer()))
4392-
lookupTy = UnboundGenericType::get(bound->getDecl(), bound->getParent(),
4393-
P.Context);
4348+
if (auto bound = lookupTy->getAs<BoundGenericType>())
4349+
lookupTy = bound->getDecl()->getDeclaredType();
43944350
auto lookup = P.SF.getParentModule()->lookupConformance(
43954351
lookupTy, proto, nullptr);
43964352
if (!lookup) {

lib/Sema/CSApply.cpp

Lines changed: 17 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -108,30 +108,18 @@ Type Solution::computeSubstitutions(
108108
auto lookupConformanceFn =
109109
[&](CanType original, Type replacement, ProtocolType *protoType)
110110
-> ProtocolConformanceRef {
111+
if (replacement->hasError() ||
112+
isOpenedAnyObject(replacement) ||
113+
replacement->is<GenericTypeParamType>()) {
114+
return ProtocolConformanceRef(protoType->getDecl());
115+
}
116+
111117
auto conformance = tc.conformsToProtocol(
112118
replacement,
113119
protoType->getDecl(),
114120
getConstraintSystem().DC,
115121
(ConformanceCheckFlags::InExpression|
116122
ConformanceCheckFlags::Used));
117-
(void)&isOpenedAnyObject;
118-
assert((conformance ||
119-
replacement->hasError() ||
120-
isOpenedAnyObject(replacement) ||
121-
replacement->is<GenericTypeParamType>()) &&
122-
"Constraint system missed a conformance?");
123-
124-
// Put an abstract conformance in place if we don't already have one.
125-
// FIXME: Feels like a hack
126-
if (!conformance &&
127-
(replacement->hasDependentProtocolConformances() ||
128-
replacement->hasError()))
129-
conformance = ProtocolConformanceRef(protoType->getDecl());
130-
131-
assert(conformance->isConcrete() ||
132-
replacement->hasError() ||
133-
replacement->hasDependentProtocolConformances());
134-
135123
return *conformance;
136124
};
137125

@@ -190,11 +178,8 @@ static DeclTy *findNamedWitnessImpl(
190178

191179
// For a type with dependent conformance, just return the requirement from
192180
// the protocol. There are no protocol conformance tables.
193-
if (type->hasDependentProtocolConformances()) {
181+
if (!conformance->isConcrete())
194182
return requirement;
195-
}
196-
197-
if (!conformance->isConcrete()) return nullptr;
198183
auto concrete = conformance->getConcrete();
199184
// FIXME: Dropping substitutions here.
200185
return cast_or_null<DeclTy>(concrete->getWitness(requirement, &tc).getDecl());
@@ -859,11 +844,12 @@ namespace {
859844
}
860845

861846
// Otherwise, we're referring to a member of a type.
862-
863-
// Is it an archetype member?
864-
bool isDependentConformingRef
865-
= isa<ProtocolDecl>(member->getDeclContext()) &&
866-
baseTy->hasDependentProtocolConformances();
847+
Type selfTy;
848+
if (isa<ProtocolDecl>(member->getDeclContext()) &&
849+
(baseTy->is<ArchetypeType>() || baseTy->isExistentialType()))
850+
selfTy = baseTy;
851+
else
852+
selfTy = containerTy;
867853

868854
// References to properties with accessors and storage usually go
869855
// through the accessors, but sometimes are direct.
@@ -875,12 +861,7 @@ namespace {
875861
if (baseIsInstance) {
876862
// Convert the base to the appropriate container type, turning it
877863
// into an lvalue if required.
878-
Type selfTy;
879-
if (isDependentConformingRef)
880-
selfTy = baseTy;
881-
else
882-
selfTy = containerTy;
883-
864+
884865
// If the base is already an lvalue with the right base type, we can
885866
// pass it as an inout qualified type.
886867
if (selfTy->isEqual(baseTy))
@@ -892,9 +873,7 @@ namespace {
892873
} else {
893874
// Convert the base to an rvalue of the appropriate metatype.
894875
base = coerceToType(base,
895-
MetatypeType::get(isDependentConformingRef
896-
? baseTy
897-
: containerTy),
876+
MetatypeType::get(selfTy),
898877
locator.withPathElement(
899878
ConstraintLocator::MemberRefBase));
900879
if (!base)
@@ -5685,8 +5664,7 @@ static Type adjustSelfTypeForMember(Type baseTy, ValueDecl *member,
56855664
// case, the member will be modeled as an inout but ExistentialMemberRef
56865665
// and ArchetypeMemberRef want to take the base as an rvalue.
56875666
if (auto *fd = dyn_cast<FuncDecl>(func))
5688-
if (!fd->isMutating() &&
5689-
baseObjectTy->hasDependentProtocolConformances())
5667+
if (!fd->isMutating() && baseObjectTy->is<ArchetypeType>())
56905668
return baseObjectTy;
56915669

56925670
return InOutType::get(baseObjectTy);
@@ -6223,7 +6201,7 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType,
62236201
// We're constructing a value of nominal type. Look for the constructor or
62246202
// enum element to use.
62256203
assert(ty->getNominalOrBoundGenericNominal() || ty->is<DynamicSelfType>() ||
6226-
ty->hasDependentProtocolConformances());
6204+
ty->isExistentialType() || ty->is<ArchetypeType>());
62276205
auto ctorLocator = cs.getConstraintLocator(
62286206
locator.withPathElement(ConstraintLocator::ApplyFunction)
62296207
.withPathElement(ConstraintLocator::ConstructorMember));

0 commit comments

Comments
 (0)