summaryrefslogtreecommitdiff
path: root/lib/Parse
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2015-07-07 03:58:54 +0000
committerDouglas Gregor <dgregor@apple.com>2015-07-07 03:58:54 +0000
commita34fa683e1295f0d70472e2c551ebe0a2d8f9878 (patch)
tree8d42f5211745630d3833e9ac89d041c4d809b9aa /lib/Parse
parentffad82b290ed4622bce0e221f8525eced89db528 (diff)
downloadclang-a34fa683e1295f0d70472e2c551ebe0a2d8f9878.tar.gz
Implement variance for Objective-C type parameters.
Introduce co- and contra-variance for Objective-C type parameters, which allows us to express that (for example) an NSArray is covariant in its type parameter. This means that NSArray<NSMutableString *> * is a subtype of NSArray<NSString *> *, which is expected of the immutable Foundation collections. Type parameters can be annotated with __covariant or __contravariant to make them co- or contra-variant, respectively. This feature can be detected by __has_feature(objc_generics_variance). Implements rdar://problem/20217490. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@241549 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Parse')
-rw-r--r--lib/Parse/ParseObjc.cpp42
1 files changed, 35 insertions, 7 deletions
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index 0f90b68468..4f16d47dfa 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -416,11 +416,15 @@ static void addContextSensitiveTypeNullability(Parser &P,
/// '<' objc-type-parameter (',' objc-type-parameter)* '>'
///
/// objc-type-parameter:
-/// identifier objc-type-parameter-bound[opt]
+/// objc-type-parameter-variance? identifier objc-type-parameter-bound[opt]
///
/// objc-type-parameter-bound:
/// ':' type-name
///
+/// objc-type-parameter-variance:
+/// '__covariant'
+/// '__contravariant'
+///
/// \param lAngleLoc The location of the starting '<'.
///
/// \param protocolIdents Will capture the list of identifiers, if the
@@ -444,12 +448,15 @@ ObjCTypeParamList *Parser::parseObjCTypeParamListOrProtocolRefs(
auto makeProtocolIdentsIntoTypeParameters = [&]() {
unsigned index = 0;
for (const auto &pair : protocolIdents) {
- DeclResult typeParam = Actions.actOnObjCTypeParam(getCurScope(),
- index++,
- pair.first,
- pair.second,
- SourceLocation(),
- ParsedType());
+ DeclResult typeParam = Actions.actOnObjCTypeParam(
+ getCurScope(),
+ ObjCTypeParamVariance::Invariant,
+ SourceLocation(),
+ index++,
+ pair.first,
+ pair.second,
+ SourceLocation(),
+ ParsedType());
if (typeParam.isUsable())
typeParams.push_back(typeParam.get());
}
@@ -460,7 +467,26 @@ ObjCTypeParamList *Parser::parseObjCTypeParamListOrProtocolRefs(
bool invalid = false;
lAngleLoc = ConsumeToken();
+
do {
+ // Parse the variance, if any.
+ SourceLocation varianceLoc;
+ ObjCTypeParamVariance variance = ObjCTypeParamVariance::Invariant;
+ if (Tok.is(tok::kw___covariant) || Tok.is(tok::kw___contravariant)) {
+ variance = Tok.is(tok::kw___covariant)
+ ? ObjCTypeParamVariance::Covariant
+ : ObjCTypeParamVariance::Contravariant;
+ varianceLoc = ConsumeToken();
+
+ // Once we've seen a variance specific , we know this is not a
+ // list of protocol references.
+ if (mayBeProtocolList) {
+ // Up until now, we have been queuing up parameters because they
+ // might be protocol references. Turn them into parameters now.
+ makeProtocolIdentsIntoTypeParameters();
+ }
+ }
+
// Parse the identifier.
if (!Tok.is(tok::identifier)) {
// Code completion.
@@ -508,6 +534,8 @@ ObjCTypeParamList *Parser::parseObjCTypeParamListOrProtocolRefs(
// Create the type parameter.
DeclResult typeParam = Actions.actOnObjCTypeParam(getCurScope(),
+ variance,
+ varianceLoc,
typeParams.size(),
paramName,
paramLoc,