From 1ac1b63c9ca898e66aae9775cca6045082907b9a Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Tue, 7 Jul 2015 03:58:54 +0000 Subject: 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 * is a subtype of NSArray *, 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. llvm-svn: 241549 --- clang/lib/Parse/ParseObjc.cpp | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) (limited to 'clang/lib/Parse/ParseObjc.cpp') diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index 0f90b684685..4f16d47dfa7 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/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, -- cgit v1.2.3