[cfe-commits] r139275 - in /cfe/trunk: docs/ include/clang/AST/ include/clang/Basic/ include/clang/Parse/ include/clang/Sema/ include/clang/Serialization/ lib/AST/ lib/Lex/ lib/Parse/ lib/Sema/ lib/Serialization/ test/PCH/ test/SemaObjC/

Douglas Gregor dgregor at apple.com
Wed Sep 7 18:46:35 PDT 2011


Author: dgregor
Date: Wed Sep  7 20:46:34 2011
New Revision: 139275

URL: http://llvm.org/viewvc/llvm-project?rev=139275&view=rev
Log:
Implement the Objective-C 'instancetype' type, which is an alias of
'id' that can be used (only!) via a contextual keyword as the result
type of an Objective-C message send. 'instancetype' then gives the
method a related result type, which we have already been inferring for
a variety of methods (new, alloc, init, self, retain). Addresses
<rdar://problem/9267640>.


Added:
    cfe/trunk/test/SemaObjC/instancetype.m
Modified:
    cfe/trunk/docs/LanguageExtensions.html
    cfe/trunk/include/clang/AST/ASTContext.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/include/clang/Serialization/ASTBitCodes.h
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/Lex/PPMacroExpansion.cpp
    cfe/trunk/lib/Parse/ParseObjc.cpp
    cfe/trunk/lib/Parse/Parser.cpp
    cfe/trunk/lib/Sema/SemaDeclObjC.cpp
    cfe/trunk/lib/Sema/SemaExprObjC.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/lib/Serialization/ASTReader.cpp
    cfe/trunk/lib/Serialization/ASTWriter.cpp
    cfe/trunk/test/PCH/objc_methods.h
    cfe/trunk/test/PCH/objc_methods.m

Modified: cfe/trunk/docs/LanguageExtensions.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/LanguageExtensions.html?rev=139275&r1=139274&r2=139275&view=diff
==============================================================================
--- cfe/trunk/docs/LanguageExtensions.html (original)
+++ cfe/trunk/docs/LanguageExtensions.html Wed Sep  7 20:46:34 2011
@@ -723,7 +723,19 @@
 <code>init</code> has a related result type and its receiver is known
 to have the type <code>NSArray *</code>. If neither <code>alloc</code> nor <code>init</code> had a related result type, the expressions would have had type <code>id</code>, as declared in the method signature.</p>
 
-<p>To determine whether a method has a related result type, the first
+<p>A method with a related result type can be declared by using the
+type <tt>instancetype</tt> as its result type. <tt>instancetype</tt>
+is a contextual keyword that is only permitted in the result type of
+an Objective-C method, e.g.</p>
+
+<pre>
+ at interface A
++ (<b>instancetype</b>)constructAnA;
+ at end
+</pre>
+
+<p>The related result type can also be inferred for some methods.
+To determine whether a method has an inferred related result type, the first
 word in the camel-case selector (e.g., "init" in "initWithObjects") is
 considered, and the method will a related result type if its return
 type is compatible with the type of its class and if</p>
@@ -752,8 +764,8 @@
 
 <p>Related result types only affect the type of a message send or
 property access via the given method. In all other respects, a method
-with a related result type is treated the same way as method without a
-related result type.</p>
+with a related result type is treated the same way as method that
+returns <tt>id</tt>.</p>
 
 <!-- ======================================================================= -->
 <h2 id="objc_arc">Automatic reference counting </h2>

Modified: cfe/trunk/include/clang/AST/ASTContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=139275&r1=139274&r2=139275&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Wed Sep  7 20:46:34 2011
@@ -211,6 +211,9 @@
   QualType ObjCConstantStringType;
   mutable RecordDecl *CFConstantStringTypeDecl;
 
+  /// \brief The typedef declaration for the Objective-C "instancetype" type.
+  TypedefDecl *ObjCInstanceTypeDecl;
+  
   /// \brief The type for the C FILE type.
   TypeDecl *FILEDecl;
 
@@ -884,6 +887,16 @@
     ObjCSelRedefinitionType = RedefType;
   }
 
+  /// \brief Retrieve the Objective-C "instancetype" type, if already known;
+  /// otherwise, returns a NULL type;
+  QualType getObjCInstanceType() {
+    return getTypeDeclType(getObjCInstanceTypeDecl());
+  }
+
+  /// \brief Retrieve the typedef declaration corresponding to the Objective-C
+  /// "instancetype" type.
+  TypedefDecl *getObjCInstanceTypeDecl();
+  
   /// \brief Set the type for the C FILE type.
   void setFILEDecl(TypeDecl *FILEDecl) { this->FILEDecl = FILEDecl; }
 

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=139275&r1=139274&r2=139275&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Sep  7 20:46:34 2011
@@ -4696,9 +4696,12 @@
 def warn_related_result_type_compatibility_protocol : Warning<
   "protocol method is expected to return an instance of the implementing "
   "class, but is declared to return %0">;
-def note_related_result_type_overridden : Note<
+def note_related_result_type_overridden_family : Note<
   "overridden method is part of the '%select{|alloc|copy|init|mutableCopy|"
-  "new|autorelease|dealloc|release|retain|retainCount|self}0' method family">;
+  "new|autorelease|dealloc|finalize|release|retain|retainCount|self}0' method "
+  "family">;
+def note_related_result_type_overridden : Note<
+  "overridden method returns an instance of its class type">;
 def note_related_result_type_inferred : Note<
   "%select{class|instance}0 method %1 is assumed to return an instance of "
   "its receiver type (%2)">;

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=139275&r1=139274&r2=139275&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Wed Sep  7 20:46:34 2011
@@ -120,6 +120,9 @@
   IdentifierInfo *Ident_vector;
   IdentifierInfo *Ident_pixel;
 
+  /// Objective-C contextual keywords.
+  mutable IdentifierInfo *Ident_instancetype;
+  
   /// \brief Identifier for "introduced".
   IdentifierInfo *Ident_introduced;
 

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=139275&r1=139274&r2=139275&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Wed Sep  7 20:46:34 2011
@@ -832,6 +832,10 @@
 
   TypeResult ActOnTypeName(Scope *S, Declarator &D);
   
+  /// \brief The parser has parsed the context-sensitive type 'instancetype'
+  /// in an Objective-C message declaration. Return the appropriate type.
+  ParsedType ActOnObjCInstanceType(SourceLocation Loc);
+  
   bool RequireCompleteType(SourceLocation Loc, QualType T,
                            const PartialDiagnostic &PD,
                            std::pair<SourceLocation, PartialDiagnostic> Note);

Modified: cfe/trunk/include/clang/Serialization/ASTBitCodes.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTBitCodes.h?rev=139275&r1=139274&r2=139275&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTBitCodes.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTBitCodes.h Wed Sep  7 20:46:34 2011
@@ -693,14 +693,17 @@
       PREDEF_DECL_INT_128_ID = 5,
 
       /// \brief The unsigned 128-bit integer type.
-      PREDEF_DECL_UNSIGNED_INT_128_ID = 6
+      PREDEF_DECL_UNSIGNED_INT_128_ID = 6,
+      
+      /// \brief The internal 'instancetype' typedef.
+      PREDEF_DECL_OBJC_INSTANCETYPE_ID = 7
     };
 
     /// \brief The number of declaration IDs that are predefined.
     ///
     /// For more information about predefined declarations, see the
     /// \c PredefinedDeclIDs type and the PREDEF_DECL_*_ID constants.
-    const unsigned int NUM_PREDEF_DECL_IDS = 7;
+    const unsigned int NUM_PREDEF_DECL_IDS = 8;
     
     /// \brief Record codes for each kind of declaration.
     ///

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=139275&r1=139274&r2=139275&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Wed Sep  7 20:46:34 2011
@@ -225,7 +225,7 @@
     GlobalNestedNameSpecifier(0), 
     Int128Decl(0), UInt128Decl(0),
     ObjCIdDecl(0), ObjCSelDecl(0), ObjCClassDecl(0),
-    CFConstantStringTypeDecl(0),
+    CFConstantStringTypeDecl(0), ObjCInstanceTypeDecl(0),
     FILEDecl(0), 
     jmp_bufDecl(0), sigjmp_bufDecl(0), BlockDescriptorType(0), 
     BlockDescriptorExtendedType(0), cudaConfigureCallDecl(0),
@@ -3844,6 +3844,17 @@
   return getPointerType(getTagDeclType(T));
 }
 
+TypedefDecl *ASTContext::getObjCInstanceTypeDecl() {
+  if (!ObjCInstanceTypeDecl)
+    ObjCInstanceTypeDecl = TypedefDecl::Create(*this, 
+                                               getTranslationUnitDecl(),
+                                               SourceLocation(), 
+                                               SourceLocation(),
+                                               &Idents.get("instancetype"), 
+                                     getTrivialTypeSourceInfo(getObjCIdType()));
+  return ObjCInstanceTypeDecl;
+}
+
 // This returns true if a type has been typedefed to BOOL:
 // typedef <type> BOOL;
 static bool isTypeTypedefedAsBOOL(QualType T) {

Modified: cfe/trunk/lib/Lex/PPMacroExpansion.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPMacroExpansion.cpp?rev=139275&r1=139274&r2=139275&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPMacroExpansion.cpp (original)
+++ cfe/trunk/lib/Lex/PPMacroExpansion.cpp Wed Sep  7 20:46:34 2011
@@ -599,6 +599,7 @@
            .Case("objc_arc", LangOpts.ObjCAutoRefCount)
            .Case("objc_arc_weak", LangOpts.ObjCAutoRefCount && 
                  LangOpts.ObjCRuntimeHasWeak)
+           .Case("objc_instancetype", LangOpts.ObjC2)
            .Case("objc_nonfragile_abi", LangOpts.ObjCNonFragileABI)
            .Case("objc_weak_class", LangOpts.ObjCNonFragileABI)
            .Case("ownership_holds", true)

Modified: cfe/trunk/lib/Parse/ParseObjc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseObjc.cpp?rev=139275&r1=139274&r2=139275&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseObjc.cpp (original)
+++ cfe/trunk/lib/Parse/ParseObjc.cpp Wed Sep  7 20:46:34 2011
@@ -801,8 +801,16 @@
       ParseTypeName(0, Declarator::ObjCPrototypeContext, &DS);
     if (!TypeSpec.isInvalid())
       Ty = TypeSpec.get();
+  } else if (Context == OTN_ResultType && Tok.is(tok::identifier)) {
+    if (!Ident_instancetype)
+      Ident_instancetype = PP.getIdentifierInfo("instancetype");
+    
+    if (Tok.getIdentifierInfo() == Ident_instancetype) {
+      Ty = Actions.ActOnObjCInstanceType(Tok.getLocation());
+      ConsumeToken();
+    }
   }
-  
+
   if (Tok.is(tok::r_paren))
     ConsumeParen();
   else if (Tok.getLocation() == TypeStartLoc) {

Modified: cfe/trunk/lib/Parse/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=139275&r1=139274&r2=139275&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/Parser.cpp (original)
+++ cfe/trunk/lib/Parse/Parser.cpp Wed Sep  7 20:46:34 2011
@@ -443,6 +443,7 @@
     ObjCTypeQuals[objc_byref] = &PP.getIdentifierTable().get("byref");
   }
 
+  Ident_instancetype = 0;
   Ident_final = 0;
   Ident_override = 0;
 

Modified: cfe/trunk/lib/Sema/SemaDeclObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclObjC.cpp?rev=139275&r1=139274&r2=139275&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp Wed Sep  7 20:46:34 2011
@@ -148,8 +148,13 @@
         << ResultTypeRange;
     }
     
-    Diag(Overridden->getLocation(), diag::note_related_result_type_overridden)
-      << Overridden->getMethodFamily();
+    if (ObjCMethodFamily Family = Overridden->getMethodFamily())
+      Diag(Overridden->getLocation(), 
+           diag::note_related_result_type_overridden_family)
+        << Family;
+    else
+      Diag(Overridden->getLocation(), 
+           diag::note_related_result_type_overridden);
   }
   
   return false;
@@ -2261,16 +2266,22 @@
   return false;
 }
 
+namespace  {
+  /// \brief Describes the compatibility of a result type with its method.
+  enum ResultTypeCompatibilityKind {
+    RTC_Compatible,
+    RTC_Incompatible,
+    RTC_Unknown
+  };
+}
+
 /// \brief Check whether the declared result type of the given Objective-C
 /// method declaration is compatible with the method's class.
 ///
-static bool 
+static ResultTypeCompatibilityKind 
 CheckRelatedResultTypeCompatibility(Sema &S, ObjCMethodDecl *Method,
                                     ObjCInterfaceDecl *CurrentClass) {
   QualType ResultType = Method->getResultType();
-  SourceRange ResultTypeRange;
-  if (const TypeSourceInfo *ResultTypeInfo = Method->getResultTypeSourceInfo())
-    ResultTypeRange = ResultTypeInfo->getTypeLoc().getSourceRange();
   
   // If an Objective-C method inherits its related result type, then its 
   // declared result type must be compatible with its own class type. The
@@ -2280,23 +2291,27 @@
     //   - it is id or qualified id, or
     if (ResultObjectType->isObjCIdType() ||
         ResultObjectType->isObjCQualifiedIdType())
-      return false;
+      return RTC_Compatible;
   
     if (CurrentClass) {
       if (ObjCInterfaceDecl *ResultClass 
                                       = ResultObjectType->getInterfaceDecl()) {
         //   - it is the same as the method's class type, or
         if (CurrentClass == ResultClass)
-          return false;
+          return RTC_Compatible;
         
         //   - it is a superclass of the method's class type
         if (ResultClass->isSuperClassOf(CurrentClass))
-          return false;
+          return RTC_Compatible;
       }      
+    } else {
+      // Any Objective-C pointer type might be acceptable for a protocol
+      // method; we just don't know.
+      return RTC_Unknown;
     }
   }
   
-  return true;
+  return RTC_Incompatible;
 }
 
 namespace {
@@ -2457,6 +2472,7 @@
   Decl *ClassDecl = cast<Decl>(OCD); 
   QualType resultDeclType;
 
+  bool HasRelatedResultType = false;
   TypeSourceInfo *ResultTInfo = 0;
   if (ReturnType) {
     resultDeclType = GetTypeFromParser(ReturnType, &ResultTInfo);
@@ -2468,6 +2484,8 @@
         << 0 << resultDeclType;
       return 0;
     }    
+    
+    HasRelatedResultType = (resultDeclType == Context.getObjCInstanceType());
   } else { // get the type for "id".
     resultDeclType = Context.getObjCIdType();
     Diag(MethodLoc, diag::warn_missing_method_return_type)
@@ -2484,7 +2502,7 @@
                            MethodDeclKind == tok::objc_optional 
                              ? ObjCMethodDecl::Optional
                              : ObjCMethodDecl::Required,
-                           false);
+                           HasRelatedResultType);
 
   SmallVector<ParmVarDecl*, 16> Params;
 
@@ -2604,9 +2622,8 @@
       CurrentClass = CatImpl->getClassInterface();
   }
 
-  bool isRelatedResultTypeCompatible =
-    (getLangOptions().ObjCInferRelatedResultType &&
-     !CheckRelatedResultTypeCompatibility(*this, ObjCMethod, CurrentClass));
+  ResultTypeCompatibilityKind RTC
+    = CheckRelatedResultTypeCompatibility(*this, ObjCMethod, CurrentClass);
 
   // Search for overridden methods and merge information down from them.
   OverrideSearch overrides(*this, ObjCMethod);
@@ -2615,7 +2632,7 @@
     ObjCMethodDecl *overridden = *i;
 
     // Propagate down the 'related result type' bit from overridden methods.
-    if (isRelatedResultTypeCompatible && overridden->hasRelatedResultType())
+    if (RTC != RTC_Incompatible && overridden->hasRelatedResultType())
       ObjCMethod->SetRelatedResultType();
 
     // Then merge the declarations.
@@ -2633,8 +2650,10 @@
   if (getLangOptions().ObjCAutoRefCount)
     ARCError = CheckARCMethodDecl(*this, ObjCMethod);
 
-  if (!ARCError && isRelatedResultTypeCompatible &&
-      !ObjCMethod->hasRelatedResultType()) {
+  // Infer the related result type when possible.
+  if (!ARCError && RTC == RTC_Compatible &&
+      !ObjCMethod->hasRelatedResultType() &&
+      LangOpts.ObjCInferRelatedResultType) {
     bool InferRelatedResultType = false;
     switch (ObjCMethod->getMethodFamily()) {
     case OMF_None:

Modified: cfe/trunk/lib/Sema/SemaExprObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprObjC.cpp?rev=139275&r1=139274&r2=139275&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprObjC.cpp Wed Sep  7 20:46:34 2011
@@ -328,6 +328,10 @@
                                      MsgSend->getType()))
     return;
   
+  if (!Context.hasSameUnqualifiedType(Method->getResultType(), 
+                                      Context.getObjCInstanceType()))
+    return;
+  
   Diag(Method->getLocation(), diag::note_related_result_type_inferred)
     << Method->isInstanceMethod() << Method->getSelector()
     << MsgSend->getType();

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=139275&r1=139274&r2=139275&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Wed Sep  7 20:46:34 2011
@@ -3053,6 +3053,13 @@
   return CreateParsedType(T, TInfo);
 }
 
+ParsedType Sema::ActOnObjCInstanceType(SourceLocation Loc) {
+  QualType T = Context.getObjCInstanceType();
+  TypeSourceInfo *TInfo = Context.getTrivialTypeSourceInfo(T, Loc);
+  return CreateParsedType(T, TInfo);
+}
+
+
 //===----------------------------------------------------------------------===//
 // Type Attribute Processing
 //===----------------------------------------------------------------------===//

Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=139275&r1=139274&r2=139275&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Wed Sep  7 20:46:34 2011
@@ -4126,6 +4126,10 @@
     case PREDEF_DECL_UNSIGNED_INT_128_ID:
       assert(Context && "No context available?");
       return Context->getUInt128Decl();
+        
+    case PREDEF_DECL_OBJC_INSTANCETYPE_ID:
+      assert(Context && "No context available?");
+      return Context->getObjCInstanceTypeDecl();
     }
     
     return 0;

Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=139275&r1=139274&r2=139275&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Wed Sep  7 20:46:34 2011
@@ -2880,6 +2880,8 @@
     DeclIDs[Context.Int128Decl] = PREDEF_DECL_INT_128_ID;
   if (Context.UInt128Decl)
     DeclIDs[Context.UInt128Decl] = PREDEF_DECL_UNSIGNED_INT_128_ID;
+  if (Context.ObjCInstanceTypeDecl)
+    DeclIDs[Context.ObjCInstanceTypeDecl] = PREDEF_DECL_OBJC_INSTANCETYPE_ID;
   
   if (!Chain) {
     // Make sure that we emit IdentifierInfos (and any attached

Modified: cfe/trunk/test/PCH/objc_methods.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/objc_methods.h?rev=139275&r1=139274&r2=139275&view=diff
==============================================================================
--- cfe/trunk/test/PCH/objc_methods.h (original)
+++ cfe/trunk/test/PCH/objc_methods.h Wed Sep  7 20:46:34 2011
@@ -2,7 +2,7 @@
 
 @interface TestPCH
 + alloc;
-- (id)init;
+- (instancetype)instMethod;
 @end
 
 @class TestForwardClassDecl;

Modified: cfe/trunk/test/PCH/objc_methods.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/objc_methods.m?rev=139275&r1=139274&r2=139275&view=diff
==============================================================================
--- cfe/trunk/test/PCH/objc_methods.m (original)
+++ cfe/trunk/test/PCH/objc_methods.m Wed Sep  7 20:46:34 2011
@@ -12,5 +12,5 @@
 // AliasForTestPCH *zz;
  
  xx = [TestPCH alloc];
- [xx init];
+ [xx instMethod];
 }

Added: cfe/trunk/test/SemaObjC/instancetype.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/instancetype.m?rev=139275&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjC/instancetype.m (added)
+++ cfe/trunk/test/SemaObjC/instancetype.m Wed Sep  7 20:46:34 2011
@@ -0,0 +1,190 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+#if !__has_feature(objc_instancetype)
+# error Missing 'instancetype' feature macro.
+#endif
+
+ at interface Root
++ (instancetype)alloc;
+- (instancetype)init; // expected-note{{overridden method is part of the 'init' method family}}
+- (instancetype)self;
+- (Class)class;
+
+ at property (assign) Root *selfProp;
+- (instancetype)selfProp;
+ at end
+
+ at protocol Proto1
+ at optional
+- (instancetype)methodInProto1;
+ at end
+
+ at protocol Proto2
+ at optional
+- (instancetype)methodInProto2; // expected-note{{overridden method returns an instance of its class type}}
+- (instancetype)otherMethodInProto2; // expected-note{{overridden method returns an instance of its class type}}
+ at end
+
+ at interface Subclass1 : Root
+- (instancetype)initSubclass1;
+- (void)methodOnSubclass1;
++ (instancetype)allocSubclass1;
+ at end
+
+ at interface Subclass2 : Root
+- (instancetype)initSubclass2;
+- (void)methodOnSubclass2;
+ at end
+
+// Sanity check: the basic initialization pattern.
+void test_instancetype_alloc_init_simple() {
+  Root *r1 = [[Root alloc] init];
+  Subclass1 *sc1 = [[Subclass1 alloc] init];
+}
+
+// Test that message sends to instancetype methods have the right type.
+void test_instancetype_narrow_method_search() {
+  // instancetype on class methods
+  Subclass1 *sc1 = [[Subclass1 alloc] initSubclass2]; // expected-warning{{'Subclass1' may not respond to 'initSubclass2'}}
+  Subclass2 *sc2 = [[Subclass2 alloc] initSubclass2]; // okay
+
+  // instancetype on instance methods
+  [[[Subclass1 alloc] init] methodOnSubclass2]; // expected-warning{{'Subclass1' may not respond to 'methodOnSubclass2'}}
+  [[[Subclass2 alloc] init] methodOnSubclass2];
+  
+  // instancetype on class methods using protocols
+  typedef Subclass1<Proto1> SC1Proto1;
+  typedef Subclass1<Proto2> SC1Proto2;
+  [[SC1Proto1 alloc] methodInProto2]; // expected-warning{{method '-methodInProto2' not found (return type defaults to 'id')}}
+  [[SC1Proto2 alloc] methodInProto2];
+
+  // instancetype on instance methods
+  Subclass1<Proto1> *sc1proto1 = 0;
+  [[sc1proto1 self] methodInProto2]; // expected-warning{{method '-methodInProto2' not found (return type defaults to 'id')}}
+  Subclass1<Proto2> *sc1proto2 = 0;
+  [[sc1proto2 self] methodInProto2];
+
+  // Exact type checks
+  typeof([[Subclass1 alloc] init]) *ptr1 = (Subclass1 **)0;
+  typeof([[Subclass2 alloc] init]) *ptr2 = (Subclass2 **)0;
+
+  // Message sends to Class.
+  Subclass1<Proto1> *sc1proto1_2 = [[[sc1proto1 class] alloc] init];
+
+  // Property access
+  [sc1proto1.self methodInProto2]; // expected-warning{{method '-methodInProto2' not found (return type defaults to 'id')}}
+  [sc1proto2.self methodInProto2];
+  [Subclass1.alloc initSubclass2]; // expected-warning{{'Subclass1' may not respond to 'initSubclass2'}}
+  [Subclass2.alloc initSubclass2];
+
+  [sc1proto1.selfProp methodInProto2]; // expected-warning{{method '-methodInProto2' not found (return type defaults to 'id')}}
+  [sc1proto2.selfProp methodInProto2];
+}
+
+// Test that message sends to super methods have the right type.
+ at interface Subsubclass1 : Subclass1
+- (instancetype)initSubclass1;
++ (instancetype)allocSubclass1;
+
+- (void)onlyInSubsubclass1;
+ at end
+
+ at implementation Subsubclass1
+- (instancetype)initSubclass1 {
+  // Check based on method search.
+  [[super initSubclass1] methodOnSubclass2]; // expected-warning{{'Subsubclass1' may not respond to 'methodOnSubclass2'}}
+  [super.initSubclass1 methodOnSubclass2]; // expected-warning{{'Subsubclass1' may not respond to 'methodOnSubclass2'}}
+
+  self = [super init]; // common pattern
+
+  // Exact type check.
+  typeof([super initSubclass1]) *ptr1 = (Subsubclass1**)0;
+
+  return self;
+}
+
++ (instancetype)allocSubclass1 {
+  // Check based on method search.
+  [[super allocSubclass1] methodOnSubclass2]; // expected-warning{{'Subsubclass1' may not respond to 'methodOnSubclass2'}}
+
+  // The ASTs don't model super property accesses well enough to get this right
+  [super.allocSubclass1 methodOnSubclass2]; // expected-warning{{'Subsubclass1' may not respond to 'methodOnSubclass2'}}
+
+  // Exact type check.
+  typeof([super allocSubclass1]) *ptr1 = (Subsubclass1**)0;
+  
+  return [super allocSubclass1];
+}
+
+- (void)onlyInSubsubclass1 {}
+ at end
+
+// Check compatibility rules for inheritance of related return types.
+ at class Subclass4;
+
+ at interface Subclass3 <Proto1, Proto2>
+- (Subclass3 *)methodInProto1;
+- (Subclass4 *)methodInProto2; // expected-warning{{method is expected to return an instance of its class type 'Subclass3', but is declared to return 'Subclass4 *'}}
+ at end
+
+ at interface Subclass4 : Root
++ (Subclass4 *)alloc; // okay
+- (Subclass3 *)init; // expected-warning{{method is expected to return an instance of its class type 'Subclass4', but is declared to return 'Subclass3 *'}}
+- (id)self; // expected-note{{overridden method is part of the 'self' method family}}
+- (instancetype)initOther;
+ at end
+
+ at protocol Proto3 <Proto1, Proto2>
+ at optional
+- (id)methodInProto1;
+- (Subclass1 *)methodInProto2;
+- (int)otherMethodInProto2; // expected-warning{{protocol method is expected to return an instance of the implementing class, but is declared to return 'int'}}
+ at end
+
+ at implementation Subclass4
++ (id)alloc {
+  return self; // expected-warning{{incompatible pointer types returning 'Class' from a function with result type 'Subclass4 *'}}
+}
+
+- (Subclass3 *)init { return 0; } // don't complain: we lost the related return type
+
+- (Subclass3 *)self { return 0; } // expected-warning{{method is expected to return an instance of its class type 'Subclass4', but is declared to return 'Subclass3 *'}}
+
+- (Subclass4 *)initOther { return 0; }
+
+ at end
+
+// Check that inherited related return types influence the types of
+// message sends.
+void test_instancetype_inherited() {
+  [[Subclass4 alloc] initSubclass1]; // expected-warning{{'Subclass4' may not respond to 'initSubclass1'}}
+  [[Subclass4 alloc] initOther];
+}
+
+// Check that related return types tighten up the semantics of
+// Objective-C method implementations.
+ at implementation Subclass2
+- (instancetype)initSubclass2 {
+  Subclass1 *sc1 = [[Subclass1 alloc] init];
+  return sc1; // expected-warning{{incompatible pointer types returning 'Subclass1 *' from a function with result type 'Subclass2 *'}}
+}
+- (void)methodOnSubclass2 {}
+- (id)self {
+  Subclass1 *sc1 = [[Subclass1 alloc] init];
+  return sc1; // expected-warning{{incompatible pointer types returning 'Subclass1 *' from a function with result type 'Subclass2 *'}}
+}
+ at end
+
+ at interface MyClass : Root
++ (int)myClassMethod;
+ at end
+
+ at implementation MyClass
++ (int)myClassMethod { return 0; }
+
+- (void)blah {
+  int i = [[MyClass self] myClassMethod];
+}
+
+ at end
+





More information about the cfe-commits mailing list