@@ -145,6 +145,16 @@ namespace {
145
145
SILSpecializeAttr::SpecializationKind kind;
146
146
};
147
147
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
+
148
158
class SILParser {
149
159
friend SILParserTUState;
150
160
public:
@@ -178,10 +188,10 @@ namespace {
178
188
void convertRequirements (SILFunction *F, ArrayRef<RequirementRepr> From,
179
189
SmallVectorImpl<Requirement> &To);
180
190
181
- ProtocolConformance *
191
+ Optional<ProtocolConformanceRef>
182
192
parseProtocolConformanceHelper (ProtocolDecl *&proto,
183
193
GenericEnvironment *GenericEnv,
184
- bool localScope ,
194
+ ConformanceContext context ,
185
195
ProtocolDecl *defaultForProto);
186
196
public:
187
197
SILParser (Parser &P)
@@ -410,15 +420,17 @@ namespace {
410
420
GenericEnvironment *GenericEnv=nullptr ,
411
421
ProtocolDecl *defaultForProto = nullptr );
412
422
413
- ProtocolConformance *parseProtocolConformance (ProtocolDecl *&proto,
423
+ Optional<ProtocolConformanceRef>
424
+ parseProtocolConformance (ProtocolDecl *&proto,
414
425
GenericEnvironment *&genericEnv,
415
- bool localScope ,
426
+ ConformanceContext context ,
416
427
ProtocolDecl *defaultForProto);
417
- ProtocolConformance *parseProtocolConformance (
418
- ProtocolDecl *defaultForProto) {
428
+ Optional<ProtocolConformanceRef>
429
+ parseProtocolConformance (ProtocolDecl *defaultForProto,
430
+ ConformanceContext context) {
419
431
ProtocolDecl *dummy;
420
432
GenericEnvironment *env;
421
- return parseProtocolConformance (dummy, env, true , defaultForProto);
433
+ return parseProtocolConformance (dummy, env, context , defaultForProto);
422
434
}
423
435
424
436
Optional<llvm::coverage::Counter>
@@ -5803,30 +5815,32 @@ static CanType parseAssociatedTypePath(Parser &P, SILParser &SP,
5803
5815
return CanType ();
5804
5816
}
5805
5817
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) {
5808
5827
Identifier ModuleKeyword, ModuleName;
5809
5828
SourceLoc Loc, KeywordLoc;
5810
5829
proto = parseProtocolDecl (P, SP);
5811
5830
if (!proto)
5812
- return nullptr ;
5831
+ return None ;
5813
5832
5814
5833
if (P.parseIdentifier (ModuleKeyword, KeywordLoc,
5815
5834
diag::expected_tok_in_sil_instr, " module" ) ||
5816
5835
SP.parseSILIdentifier (ModuleName, Loc,
5817
5836
diag::expected_sil_value_name))
5818
- return nullptr ;
5837
+ return None ;
5819
5838
5820
5839
if (ModuleKeyword.str () != " module" ) {
5821
5840
P.diagnose (KeywordLoc, diag::expected_tok_in_sil_instr, " module" );
5822
- return nullptr ;
5841
+ return None ;
5823
5842
}
5824
5843
5825
- // FIXME: we currently emit _CocoaArrayType: _CocoaArrayType.
5826
- if (ConformingTy->is <ProtocolType>() &&
5827
- ConformingTy->getAs <ProtocolType>()->getDecl () == proto)
5828
- return nullptr ;
5829
-
5830
5844
// Calling lookupConformance on a BoundGenericType will return a specialized
5831
5845
// conformance. We use UnboundGenericType to find the normal conformance.
5832
5846
Type lookupTy = ConformingTy;
@@ -5835,13 +5849,17 @@ static NormalProtocolConformance *parseNormalProtocolConformance(Parser &P,
5835
5849
auto lookup = P.SF .getParentModule ()->lookupConformance (lookupTy, proto);
5836
5850
if (!lookup) {
5837
5851
P.diagnose (KeywordLoc, diag::sil_witness_protocol_conformance_not_found);
5838
- return nullptr ;
5852
+ return None ;
5839
5853
}
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));
5843
5860
}
5844
- return lookup->getConcrete ()->getRootNormalConformance ();
5861
+
5862
+ return lookup;
5845
5863
}
5846
5864
5847
5865
// / protocol-conformance ::= normal-protocol-conformance
@@ -5853,15 +5871,15 @@ static NormalProtocolConformance *parseNormalProtocolConformance(Parser &P,
5853
5871
// / normal-protocol-conformance ::=
5854
5872
// / generic-parameter-list? type: protocolName module ModuleName
5855
5873
// / Note that generic-parameter-list is already parsed before calling this.
5856
- ProtocolConformance * SILParser::parseProtocolConformance (
5874
+ Optional<ProtocolConformanceRef> SILParser::parseProtocolConformance (
5857
5875
ProtocolDecl *&proto,
5858
5876
GenericEnvironment *&genericEnv,
5859
- bool localScope ,
5877
+ ConformanceContext context ,
5860
5878
ProtocolDecl *defaultForProto) {
5861
5879
// Parse generic params for the protocol conformance. We need to make sure
5862
5880
// they have the right scope.
5863
5881
Optional<Scope> GenericsScope;
5864
- if (localScope )
5882
+ if (context == ConformanceContext::Ordinary )
5865
5883
GenericsScope.emplace (&P, ScopeKind::Generics);
5866
5884
5867
5885
// Make sure we don't leave it uninitialized in the caller
@@ -5872,83 +5890,87 @@ ProtocolConformance *SILParser::parseProtocolConformance(
5872
5890
genericEnv = handleSILGenericParams (P.Context , genericParams, &P.SF );
5873
5891
}
5874
5892
5875
- ProtocolConformance *retVal =
5876
- parseProtocolConformanceHelper (proto, genericEnv, localScope,
5877
- defaultForProto);
5893
+ auto retVal = parseProtocolConformanceHelper (proto, genericEnv, context,
5894
+ defaultForProto);
5878
5895
5879
- if (localScope ) {
5896
+ if (GenericsScope ) {
5880
5897
GenericsScope.reset ();
5881
5898
}
5882
5899
return retVal;
5883
5900
}
5884
5901
5885
- ProtocolConformance * SILParser::parseProtocolConformanceHelper (
5902
+ Optional<ProtocolConformanceRef> SILParser::parseProtocolConformanceHelper (
5886
5903
ProtocolDecl *&proto,
5887
5904
GenericEnvironment *witnessEnv,
5888
- bool localScope ,
5905
+ ConformanceContext context ,
5889
5906
ProtocolDecl *defaultForProto) {
5890
5907
// Parse AST type.
5891
5908
ParserResult<TypeRepr> TyR = P.parseType ();
5892
5909
if (TyR.isNull ())
5893
- return nullptr ;
5910
+ return None ;
5894
5911
TypeLoc Ty = TyR.get ();
5895
5912
if (defaultForProto) {
5896
5913
bindProtocolSelfInTypeRepr (Ty, defaultForProto);
5897
5914
}
5898
5915
5899
5916
if (performTypeLocChecking (Ty, /* IsSILType=*/ false , witnessEnv,
5900
5917
defaultForProto))
5901
- return nullptr ;
5918
+ return None ;
5902
5919
auto ConformingTy = Ty.getType ();
5903
5920
5904
5921
if (P.parseToken (tok::colon, diag::expected_sil_witness_colon))
5905
- return nullptr ;
5922
+ return None ;
5906
5923
5907
5924
if (P.Tok .is (tok::identifier) && P.Tok .getText () == " specialize" ) {
5908
5925
P.consumeToken ();
5909
5926
5910
5927
// Parse substitutions for specialized conformance.
5911
5928
SmallVector<ParsedSubstitution, 4 > parsedSubs;
5912
5929
if (parseSubstitutions (parsedSubs, witnessEnv, defaultForProto))
5913
- return nullptr ;
5930
+ return None ;
5914
5931
5915
5932
if (P.parseToken (tok::l_paren, diag::expected_sil_witness_lparen))
5916
- return nullptr ;
5933
+ return None ;
5917
5934
ProtocolDecl *dummy;
5918
5935
GenericEnvironment *specializedEnv;
5919
5936
auto genericConform =
5920
- parseProtocolConformance (dummy, specializedEnv, localScope,
5937
+ parseProtocolConformance (dummy, specializedEnv,
5938
+ ConformanceContext::Ordinary,
5921
5939
defaultForProto);
5922
- if (!genericConform)
5923
- return nullptr ;
5940
+ if (!genericConform || !genericConform-> isConcrete () )
5941
+ return None ;
5924
5942
if (P.parseToken (tok::r_paren, diag::expected_sil_witness_rparen))
5925
- return nullptr ;
5943
+ return None ;
5926
5944
5927
5945
SubstitutionMap subMap =
5928
5946
getApplySubstitutionsFromParsed (*this , specializedEnv, parsedSubs);
5929
5947
if (!subMap)
5930
- return nullptr ;
5948
+ return None ;
5931
5949
5932
5950
auto result = P.Context .getSpecializedConformance (
5933
- ConformingTy, genericConform, subMap);
5934
- return result;
5951
+ ConformingTy, genericConform-> getConcrete () , subMap);
5952
+ return ProtocolConformanceRef ( result) ;
5935
5953
}
5936
5954
5937
5955
if (P.Tok .is (tok::identifier) && P.Tok .getText () == " inherit" ) {
5938
5956
P.consumeToken ();
5939
5957
5940
5958
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;
5945
5964
if (P.parseToken (tok::r_paren, diag::expected_sil_witness_rparen))
5946
- return nullptr ;
5965
+ return None ;
5947
5966
5948
- return P.Context .getInheritedConformance (ConformingTy, baseConform);
5967
+ auto result = P.Context .getInheritedConformance (ConformingTy,
5968
+ baseConform->getConcrete ());
5969
+ return ProtocolConformanceRef (result);
5949
5970
}
5950
5971
5951
- auto retVal = parseNormalProtocolConformance (P, *this , ConformingTy, proto);
5972
+ auto retVal =
5973
+ parseRootProtocolConformance (P, *this , ConformingTy, proto, context);
5952
5974
return retVal;
5953
5975
}
5954
5976
@@ -5984,13 +6006,14 @@ static bool parseSILVTableEntry(
5984
6006
return true ;
5985
6007
if (P.parseToken (tok::colon, diag::expected_sil_witness_colon))
5986
6008
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.
5990
6013
return false ;
5991
6014
5992
6015
witnessEntries.push_back (SILWitnessTable::BaseProtocolWitness{
5993
- proto, conform
6016
+ proto, conform-> getConcrete ()
5994
6017
});
5995
6018
return false ;
5996
6019
}
@@ -6032,10 +6055,12 @@ static bool parseSILVTableEntry(
6032
6055
6033
6056
ProtocolConformanceRef conformance (proto);
6034
6057
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.
6037
6062
return false ;
6038
- conformance = ProtocolConformanceRef ( concrete) ;
6063
+ conformance = * concrete;
6039
6064
} else {
6040
6065
P.consumeToken ();
6041
6066
}
@@ -6153,13 +6178,15 @@ bool SILParserTUState::parseSILWitnessTable(Parser &P) {
6153
6178
GenericEnvironment *witnessEnv;
6154
6179
auto conf = WitnessState.parseProtocolConformance (proto,
6155
6180
witnessEnv,
6156
- false /* localScope */ ,
6181
+ ConformanceContext::WitnessTable ,
6157
6182
nullptr );
6158
6183
WitnessState.ContextGenericEnv = witnessEnv;
6159
6184
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 ;
6163
6190
6164
6191
SILWitnessTable *wt = nullptr ;
6165
6192
if (theConformance) {
0 commit comments