Skip to content

Commit 5c205b4

Browse files
authored
Merge pull request #20648 from rjmccall/more-self-conformances-fixes
More fixes for explicit self-conformances
2 parents 2c15dc2 + 4926847 commit 5c205b4

File tree

3 files changed

+109
-66
lines changed

3 files changed

+109
-66
lines changed

lib/IDE/IDETypeChecking.cpp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -441,8 +441,17 @@ struct SynthesizedExtensionAnalyzer::Implementation {
441441
}
442442
};
443443

444+
// We want to visit the protocols of any normal conformances we see, but
445+
// we have to avoid doing this to self-conformances or we can end up with
446+
// a cycle. Otherwise this is cycle-proof on valid code.
447+
auto addConformance = [&](ProtocolConformance *Conf) {
448+
auto RootConf = Conf->getRootConformance();
449+
if (isa<NormalProtocolConformance>(RootConf))
450+
Unhandled.push_back(RootConf->getProtocol());
451+
};
452+
444453
for (auto *Conf : Target->getLocalConformances()) {
445-
Unhandled.push_back(Conf->getProtocol());
454+
addConformance(Conf);
446455
}
447456
if (auto *CD = dyn_cast<ClassDecl>(Target)) {
448457
if (auto Super = CD->getSuperclassDecl())
@@ -455,7 +464,7 @@ struct SynthesizedExtensionAnalyzer::Implementation {
455464
handleExtension(E, true, nullptr, nullptr);
456465
}
457466
for (auto *Conf : Back->getLocalConformances()) {
458-
Unhandled.push_back(Conf->getProtocol());
467+
addConformance(Conf);
459468
}
460469
if (auto *CD = dyn_cast<ClassDecl>(Back)) {
461470
if (auto Super = CD->getSuperclass())
@@ -467,8 +476,11 @@ struct SynthesizedExtensionAnalyzer::Implementation {
467476
for (auto *EnablingE : Target->getExtensions()) {
468477
handleExtension(EnablingE, false, nullptr, nullptr);
469478
for (auto *Conf : EnablingE->getLocalConformances()) {
470-
for (auto E : Conf->getProtocol()->getExtensions())
471-
handleExtension(E, true, EnablingE, Conf->getRootNormalConformance());
479+
auto NormalConf =
480+
dyn_cast<NormalProtocolConformance>(Conf->getRootConformance());
481+
if (!NormalConf) continue;
482+
for (auto E : NormalConf->getProtocol()->getExtensions())
483+
handleExtension(E, true, EnablingE, NormalConf);
472484
}
473485
}
474486

lib/Index/Index.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -704,7 +704,11 @@ bool IndexSwiftASTWalker::handleValueWitnesses(Decl *D, SmallVectorImpl<ValueWit
704704
if (conf->isInvalid())
705705
continue;
706706

707-
auto normal = conf->getRootNormalConformance();
707+
// Ignore self-conformances; they're not interesting to show to users.
708+
auto normal = dyn_cast<NormalProtocolConformance>(conf->getRootConformance());
709+
if (!normal)
710+
continue;
711+
708712
normal->forEachValueWitness(nullptr,
709713
[&](ValueDecl *req, Witness witness) {
710714
if (Cancelled)

lib/ParseSIL/ParseSIL.cpp

Lines changed: 88 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,16 @@ namespace {
145145
SILSpecializeAttr::SpecializationKind kind;
146146
};
147147

148+
enum class ConformanceContext {
149+
/// A normal conformance parse.
150+
Ordinary,
151+
152+
/// We're parsing this for a SIL witness table.
153+
/// Leave any generic parameter clauses in scope, and use an explicit
154+
/// self-conformance instead of an abstract one.
155+
WitnessTable,
156+
};
157+
148158
class SILParser {
149159
friend SILParserTUState;
150160
public:
@@ -178,10 +188,10 @@ namespace {
178188
void convertRequirements(SILFunction *F, ArrayRef<RequirementRepr> From,
179189
SmallVectorImpl<Requirement> &To);
180190

181-
ProtocolConformance *
191+
Optional<ProtocolConformanceRef>
182192
parseProtocolConformanceHelper(ProtocolDecl *&proto,
183193
GenericEnvironment *GenericEnv,
184-
bool localScope,
194+
ConformanceContext context,
185195
ProtocolDecl *defaultForProto);
186196
public:
187197
SILParser(Parser &P)
@@ -410,15 +420,17 @@ namespace {
410420
GenericEnvironment *GenericEnv=nullptr,
411421
ProtocolDecl *defaultForProto = nullptr);
412422

413-
ProtocolConformance *parseProtocolConformance(ProtocolDecl *&proto,
423+
Optional<ProtocolConformanceRef>
424+
parseProtocolConformance(ProtocolDecl *&proto,
414425
GenericEnvironment *&genericEnv,
415-
bool localScope,
426+
ConformanceContext context,
416427
ProtocolDecl *defaultForProto);
417-
ProtocolConformance *parseProtocolConformance(
418-
ProtocolDecl *defaultForProto) {
428+
Optional<ProtocolConformanceRef>
429+
parseProtocolConformance(ProtocolDecl *defaultForProto,
430+
ConformanceContext context) {
419431
ProtocolDecl *dummy;
420432
GenericEnvironment *env;
421-
return parseProtocolConformance(dummy, env, true, defaultForProto);
433+
return parseProtocolConformance(dummy, env, context, defaultForProto);
422434
}
423435

424436
Optional<llvm::coverage::Counter>
@@ -5803,30 +5815,32 @@ static CanType parseAssociatedTypePath(Parser &P, SILParser &SP,
58035815
return CanType();
58045816
}
58055817

5806-
static NormalProtocolConformance *parseNormalProtocolConformance(Parser &P,
5807-
SILParser &SP, Type ConformingTy, ProtocolDecl *&proto) {
5818+
static bool isSelfConformance(Type conformingType, ProtocolDecl *protocol) {
5819+
if (auto protoTy = conformingType->getAs<ProtocolType>())
5820+
return protoTy->getDecl() == protocol;
5821+
return false;
5822+
}
5823+
5824+
static Optional<ProtocolConformanceRef> parseRootProtocolConformance(Parser &P,
5825+
SILParser &SP, Type ConformingTy, ProtocolDecl *&proto,
5826+
ConformanceContext context) {
58085827
Identifier ModuleKeyword, ModuleName;
58095828
SourceLoc Loc, KeywordLoc;
58105829
proto = parseProtocolDecl(P, SP);
58115830
if (!proto)
5812-
return nullptr;
5831+
return None;
58135832

58145833
if (P.parseIdentifier(ModuleKeyword, KeywordLoc,
58155834
diag::expected_tok_in_sil_instr, "module") ||
58165835
SP.parseSILIdentifier(ModuleName, Loc,
58175836
diag::expected_sil_value_name))
5818-
return nullptr;
5837+
return None;
58195838

58205839
if (ModuleKeyword.str() != "module") {
58215840
P.diagnose(KeywordLoc, diag::expected_tok_in_sil_instr, "module");
5822-
return nullptr;
5841+
return None;
58235842
}
58245843

5825-
// FIXME: we currently emit _CocoaArrayType: _CocoaArrayType.
5826-
if (ConformingTy->is<ProtocolType>() &&
5827-
ConformingTy->getAs<ProtocolType>()->getDecl() == proto)
5828-
return nullptr;
5829-
58305844
// Calling lookupConformance on a BoundGenericType will return a specialized
58315845
// conformance. We use UnboundGenericType to find the normal conformance.
58325846
Type lookupTy = ConformingTy;
@@ -5835,13 +5849,17 @@ static NormalProtocolConformance *parseNormalProtocolConformance(Parser &P,
58355849
auto lookup = P.SF.getParentModule()->lookupConformance(lookupTy, proto);
58365850
if (!lookup) {
58375851
P.diagnose(KeywordLoc, diag::sil_witness_protocol_conformance_not_found);
5838-
return nullptr;
5852+
return None;
58395853
}
5840-
if (!lookup->isConcrete()) {
5841-
P.diagnose(KeywordLoc, diag::sil_witness_protocol_conformance_not_found);
5842-
return nullptr;
5854+
5855+
// Use a concrete self-conformance if we're parsing this for a witness table.
5856+
if (context == ConformanceContext::WitnessTable &&
5857+
!lookup->isConcrete() &&
5858+
isSelfConformance(ConformingTy, proto)) {
5859+
lookup = ProtocolConformanceRef(P.Context.getSelfConformance(proto));
58435860
}
5844-
return lookup->getConcrete()->getRootNormalConformance();
5861+
5862+
return lookup;
58455863
}
58465864

58475865
/// protocol-conformance ::= normal-protocol-conformance
@@ -5853,15 +5871,15 @@ static NormalProtocolConformance *parseNormalProtocolConformance(Parser &P,
58535871
/// normal-protocol-conformance ::=
58545872
/// generic-parameter-list? type: protocolName module ModuleName
58555873
/// Note that generic-parameter-list is already parsed before calling this.
5856-
ProtocolConformance *SILParser::parseProtocolConformance(
5874+
Optional<ProtocolConformanceRef> SILParser::parseProtocolConformance(
58575875
ProtocolDecl *&proto,
58585876
GenericEnvironment *&genericEnv,
5859-
bool localScope,
5877+
ConformanceContext context,
58605878
ProtocolDecl *defaultForProto) {
58615879
// Parse generic params for the protocol conformance. We need to make sure
58625880
// they have the right scope.
58635881
Optional<Scope> GenericsScope;
5864-
if (localScope)
5882+
if (context == ConformanceContext::Ordinary)
58655883
GenericsScope.emplace(&P, ScopeKind::Generics);
58665884

58675885
// Make sure we don't leave it uninitialized in the caller
@@ -5872,83 +5890,87 @@ ProtocolConformance *SILParser::parseProtocolConformance(
58725890
genericEnv = handleSILGenericParams(P.Context, genericParams, &P.SF);
58735891
}
58745892

5875-
ProtocolConformance *retVal =
5876-
parseProtocolConformanceHelper(proto, genericEnv, localScope,
5877-
defaultForProto);
5893+
auto retVal = parseProtocolConformanceHelper(proto, genericEnv, context,
5894+
defaultForProto);
58785895

5879-
if (localScope) {
5896+
if (GenericsScope) {
58805897
GenericsScope.reset();
58815898
}
58825899
return retVal;
58835900
}
58845901

5885-
ProtocolConformance *SILParser::parseProtocolConformanceHelper(
5902+
Optional<ProtocolConformanceRef> SILParser::parseProtocolConformanceHelper(
58865903
ProtocolDecl *&proto,
58875904
GenericEnvironment *witnessEnv,
5888-
bool localScope,
5905+
ConformanceContext context,
58895906
ProtocolDecl *defaultForProto) {
58905907
// Parse AST type.
58915908
ParserResult<TypeRepr> TyR = P.parseType();
58925909
if (TyR.isNull())
5893-
return nullptr;
5910+
return None;
58945911
TypeLoc Ty = TyR.get();
58955912
if (defaultForProto) {
58965913
bindProtocolSelfInTypeRepr(Ty, defaultForProto);
58975914
}
58985915

58995916
if (performTypeLocChecking(Ty, /*IsSILType=*/ false, witnessEnv,
59005917
defaultForProto))
5901-
return nullptr;
5918+
return None;
59025919
auto ConformingTy = Ty.getType();
59035920

59045921
if (P.parseToken(tok::colon, diag::expected_sil_witness_colon))
5905-
return nullptr;
5922+
return None;
59065923

59075924
if (P.Tok.is(tok::identifier) && P.Tok.getText() == "specialize") {
59085925
P.consumeToken();
59095926

59105927
// Parse substitutions for specialized conformance.
59115928
SmallVector<ParsedSubstitution, 4> parsedSubs;
59125929
if (parseSubstitutions(parsedSubs, witnessEnv, defaultForProto))
5913-
return nullptr;
5930+
return None;
59145931

59155932
if (P.parseToken(tok::l_paren, diag::expected_sil_witness_lparen))
5916-
return nullptr;
5933+
return None;
59175934
ProtocolDecl *dummy;
59185935
GenericEnvironment *specializedEnv;
59195936
auto genericConform =
5920-
parseProtocolConformance(dummy, specializedEnv, localScope,
5937+
parseProtocolConformance(dummy, specializedEnv,
5938+
ConformanceContext::Ordinary,
59215939
defaultForProto);
5922-
if (!genericConform)
5923-
return nullptr;
5940+
if (!genericConform || !genericConform->isConcrete())
5941+
return None;
59245942
if (P.parseToken(tok::r_paren, diag::expected_sil_witness_rparen))
5925-
return nullptr;
5943+
return None;
59265944

59275945
SubstitutionMap subMap =
59285946
getApplySubstitutionsFromParsed(*this, specializedEnv, parsedSubs);
59295947
if (!subMap)
5930-
return nullptr;
5948+
return None;
59315949

59325950
auto result = P.Context.getSpecializedConformance(
5933-
ConformingTy, genericConform, subMap);
5934-
return result;
5951+
ConformingTy, genericConform->getConcrete(), subMap);
5952+
return ProtocolConformanceRef(result);
59355953
}
59365954

59375955
if (P.Tok.is(tok::identifier) && P.Tok.getText() == "inherit") {
59385956
P.consumeToken();
59395957

59405958
if (P.parseToken(tok::l_paren, diag::expected_sil_witness_lparen))
5941-
return nullptr;
5942-
auto baseConform = parseProtocolConformance(defaultForProto);
5943-
if (!baseConform)
5944-
return nullptr;
5959+
return None;
5960+
auto baseConform = parseProtocolConformance(defaultForProto,
5961+
ConformanceContext::Ordinary);
5962+
if (!baseConform || !baseConform->isConcrete())
5963+
return None;
59455964
if (P.parseToken(tok::r_paren, diag::expected_sil_witness_rparen))
5946-
return nullptr;
5965+
return None;
59475966

5948-
return P.Context.getInheritedConformance(ConformingTy, baseConform);
5967+
auto result = P.Context.getInheritedConformance(ConformingTy,
5968+
baseConform->getConcrete());
5969+
return ProtocolConformanceRef(result);
59495970
}
59505971

5951-
auto retVal = parseNormalProtocolConformance(P, *this, ConformingTy, proto);
5972+
auto retVal =
5973+
parseRootProtocolConformance(P, *this, ConformingTy, proto, context);
59525974
return retVal;
59535975
}
59545976

@@ -5984,13 +6006,14 @@ static bool parseSILVTableEntry(
59846006
return true;
59856007
if (P.parseToken(tok::colon, diag::expected_sil_witness_colon))
59866008
return true;
5987-
ProtocolConformance *conform =
5988-
witnessState.parseProtocolConformance(defaultForProto);
5989-
if (!conform) // Ignore this witness entry for now.
6009+
auto conform =
6010+
witnessState.parseProtocolConformance(defaultForProto,
6011+
ConformanceContext::Ordinary);
6012+
if (!conform || !conform->isConcrete()) // Ignore this witness entry for now.
59906013
return false;
59916014

59926015
witnessEntries.push_back(SILWitnessTable::BaseProtocolWitness{
5993-
proto, conform
6016+
proto, conform->getConcrete()
59946017
});
59956018
return false;
59966019
}
@@ -6032,10 +6055,12 @@ static bool parseSILVTableEntry(
60326055

60336056
ProtocolConformanceRef conformance(proto);
60346057
if (P.Tok.getText() != "dependent") {
6035-
auto concrete = witnessState.parseProtocolConformance(defaultForProto);
6036-
if (!concrete) // Ignore this witness entry for now.
6058+
auto concrete =
6059+
witnessState.parseProtocolConformance(defaultForProto,
6060+
ConformanceContext::Ordinary);
6061+
if (!concrete && !concrete->isConcrete()) // Ignore this for now.
60376062
return false;
6038-
conformance = ProtocolConformanceRef(concrete);
6063+
conformance = *concrete;
60396064
} else {
60406065
P.consumeToken();
60416066
}
@@ -6153,13 +6178,15 @@ bool SILParserTUState::parseSILWitnessTable(Parser &P) {
61536178
GenericEnvironment *witnessEnv;
61546179
auto conf = WitnessState.parseProtocolConformance(proto,
61556180
witnessEnv,
6156-
false/*localScope*/,
6181+
ConformanceContext::WitnessTable,
61576182
nullptr);
61586183
WitnessState.ContextGenericEnv = witnessEnv;
61596184

6160-
// FIXME: support parsing a self-conformance here.
6161-
auto theConformance
6162-
= dyn_cast_or_null<RootProtocolConformance>(conf);
6185+
// FIXME: should we really allow a specialized or inherited conformance here?
6186+
auto theConformance =
6187+
(conf && conf->isConcrete())
6188+
? conf->getConcrete()->getRootConformance()
6189+
: nullptr;
61636190

61646191
SILWitnessTable *wt = nullptr;
61656192
if (theConformance) {

0 commit comments

Comments
 (0)