diff options
author | Douglas Gregor <dgregor@apple.com> | 2015-07-07 03:58:54 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2015-07-07 03:58:54 +0000 |
commit | a34fa683e1295f0d70472e2c551ebe0a2d8f9878 (patch) | |
tree | 8d42f5211745630d3833e9ac89d041c4d809b9aa /lib/Parse | |
parent | ffad82b290ed4622bce0e221f8525eced89db528 (diff) | |
download | clang-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.cpp | 42 |
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, |