Add a typeName() method to each type for error printing purposes.

Test: compiles with mma
Change-Id: I1283c395440282fde1106ad47aa185bdeda75880
diff --git a/EnumType.cpp b/EnumType.cpp
index d636a2b..e228d5a 100644
--- a/EnumType.cpp
+++ b/EnumType.cpp
@@ -64,6 +64,10 @@
     return mStorageType->resolveToScalarType();
 }
 
+std::string EnumType::typeName() const {
+    return "enum " + localName();
+}
+
 bool EnumType::isEnum() const {
     return true;
 }
diff --git a/EnumType.h b/EnumType.h
index ccdf384..09ad24d 100644
--- a/EnumType.h
+++ b/EnumType.h
@@ -40,6 +40,7 @@
 
     const ScalarType *resolveToScalarType() const override;
 
+    std::string typeName() const override;
     bool isEnum() const override;
 
     std::string getCppType(StorageMode mode,
diff --git a/Interface.cpp b/Interface.cpp
index 52e9a98..36179e7 100644
--- a/Interface.cpp
+++ b/Interface.cpp
@@ -57,6 +57,10 @@
     mReservedMethods.push_back(createSyspropsChangedMethod());
 }
 
+std::string Interface::typeName() const {
+    return "interface " + localName();
+}
+
 Method *Interface::createSyspropsChangedMethod() const {
     return new Method("notifySyspropsChanged",
             new std::vector<TypedVar *>() /*args */,
diff --git a/Interface.h b/Interface.h
index 02b04dc..a786ce3 100644
--- a/Interface.h
+++ b/Interface.h
@@ -35,6 +35,7 @@
     bool isBinder() const override;
     bool isRootType() const { return mSuperType == nullptr; }
     bool isIBase() const { return fqName() == gIBaseFqName; }
+    std::string typeName() const override;
 
     const Interface *superType() const;
 
diff --git a/RefType.cpp b/RefType.cpp
index dd5b0d2..aba064b 100644
--- a/RefType.cpp
+++ b/RefType.cpp
@@ -24,6 +24,14 @@
 RefType::RefType() {
 }
 
+std::string RefType::typeName() const {
+    return "ref" + (mElementType == nullptr ? "" : (" of " + mElementType->typeName()));
+}
+
+bool RefType::isCompatibleElementType(Type *elementType) const {
+    return !elementType->isBinder();
+}
+
 /* return something like "T const *".
  * The reason we don't return "const T *" is to handle cases like
  * ref<ref<ref<T>>> t_3ptr;
diff --git a/RefType.h b/RefType.h
index afbfb16..f8176b6 100644
--- a/RefType.h
+++ b/RefType.h
@@ -25,6 +25,9 @@
 struct RefType : public TemplatedType {
     RefType();
 
+    std::string typeName() const override;
+    bool isCompatibleElementType(Type *elementType) const override;
+
     void addNamedTypesToSet(std::set<const FQName> &set) const override;
     std::string getCppType(StorageMode mode,
                            bool specifyNamespaces) const override;
diff --git a/ScalarType.cpp b/ScalarType.cpp
index 0e4beaf..a60215a 100644
--- a/ScalarType.cpp
+++ b/ScalarType.cpp
@@ -37,6 +37,10 @@
     // do nothing
 }
 
+std::string ScalarType::typeName() const {
+    return getCppStackType();
+}
+
 std::string ScalarType::getCppType(StorageMode, bool) const {
     static const char *const kName[] = {
         "bool",
diff --git a/ScalarType.h b/ScalarType.h
index f7890f5..d1e40b5 100644
--- a/ScalarType.h
+++ b/ScalarType.h
@@ -41,6 +41,7 @@
 
     const ScalarType *resolveToScalarType() const override;
 
+    std::string typeName() const override;
     bool isValidEnumStorageType() const;
 
     void addNamedTypesToSet(std::set<const FQName> &set) const override;
diff --git a/Type.cpp b/Type.cpp
index 924caed..e3825db 100644
--- a/Type.cpp
+++ b/Type.cpp
@@ -78,6 +78,10 @@
     return false;
 }
 
+std::string Type::typeName() const {
+    return "";
+}
+
 const ScalarType *Type::resolveToScalarType() const {
     return NULL;
 }
@@ -431,8 +435,10 @@
 
 TemplatedType::TemplatedType() : mElementType(nullptr) {
 }
+
 void TemplatedType::setElementType(Type *elementType) {
     CHECK(mElementType == nullptr); // can only be set once.
+    CHECK(isCompatibleElementType(elementType));
     mElementType = elementType;
 }
 
diff --git a/Type.h b/Type.h
index 1983cfb..bb7d673 100644
--- a/Type.h
+++ b/Type.h
@@ -48,6 +48,8 @@
 
     virtual const ScalarType *resolveToScalarType() const;
 
+    virtual std::string typeName() const;
+
     bool isValidEnumStorageType() const;
 
     enum StorageMode {
@@ -241,6 +243,7 @@
 /* Base type for VectorType and RefType. */
 struct TemplatedType : public Type {
     void setElementType(Type *elementType);
+    virtual bool isCompatibleElementType(Type *elementType) const = 0;
 protected:
     TemplatedType();
     Type *mElementType;
diff --git a/VectorType.cpp b/VectorType.cpp
index 1443697..5854f54 100644
--- a/VectorType.cpp
+++ b/VectorType.cpp
@@ -26,6 +26,14 @@
 VectorType::VectorType() {
 }
 
+std::string VectorType::typeName() const {
+    return "vector" + (mElementType == nullptr ? "" : (" of " + mElementType->typeName()));
+}
+
+bool VectorType::isCompatibleElementType(Type *) const {
+    return true;
+}
+
 void VectorType::addNamedTypesToSet(std::set<const FQName> &set) const {
     mElementType->addNamedTypesToSet(set);
 }
diff --git a/VectorType.h b/VectorType.h
index 91ac811..cc18342 100644
--- a/VectorType.h
+++ b/VectorType.h
@@ -27,6 +27,8 @@
 
     bool isVector() const override;
     bool isVectorOfBinders() const;
+    std::string typeName() const override;
+    bool isCompatibleElementType(Type *elementType) const override;
 
     void addNamedTypesToSet(std::set<const FQName> &set) const override;
 
diff --git a/hidl-gen_y.yy b/hidl-gen_y.yy
index 85c0b8e..e44e488 100644
--- a/hidl-gen_y.yy
+++ b/hidl-gen_y.yy
@@ -940,9 +940,9 @@
     : fqtype { $$ = $1; }
     | TEMPLATED '<' type '>'
       {
-          if (!$1->isVector() && $3->isBinder()) {
-              std::cerr << "ERROR: TemplatedType of interface types are not "
-                        << "supported. at " << @3 << "\n";
+          if (!$1->isCompatibleElementType($3)) {
+              std::cerr << "ERROR: " << $1->typeName() << " of " << $3->typeName()
+                        << " is not supported. at " << @3 << "\n";
 
               YYERROR;
           }
@@ -951,13 +951,19 @@
       }
     | TEMPLATED '<' TEMPLATED '<' type RSHIFT
       {
-          if ($5->isBinder()) {
-              std::cerr << "ERROR: TemplatedType of interface types are not "
-                        << "supported. at " << @5 << "\n";
+          if (!$3->isCompatibleElementType($5)) {
+              std::cerr << "ERROR: " << $3->typeName() << " of " << $5->typeName()
+                        << " is not supported. at " << @3 << "\n";
 
               YYERROR;
           }
           $3->setElementType($5);
+          if (!$1->isCompatibleElementType($3)) {
+              std::cerr << "ERROR: " << $1->typeName() << " of " << $3->typeName()
+                        << " is not supported. at " << @3 << "\n";
+
+              YYERROR;
+          }
           $1->setElementType($3);
           $$ = $1;
       }