Better constant expression acyclic check error messages

Makes constant expression acyclic check error messages look like
type acyclic check.

ex:
enum E {
  A = D,
  B,
  C,
  D
}

previous cycle print:
  A at ...
  B at ...
  C at ...
  D at ...

new cycle print:
  D in A at ...
  A in B at ...
  B in C at ...
  C in D at ...

Test: mma
Test: local test with moved lookups

Change-Id: I091792d4de049509708cb91331e8504e0edf14b9
diff --git a/ConstantExpression.cpp b/ConstantExpression.cpp
index a593025..5388acf 100644
--- a/ConstantExpression.cpp
+++ b/ConstantExpression.cpp
@@ -440,6 +440,10 @@
     return this->cast<size_t>();
 }
 
+bool ConstantExpression::isReferenceConstantExpression() const {
+    return false;
+}
+
 std::vector<ConstantExpression*> ConstantExpression::getConstantExpressions() {
     const auto& constRet = static_cast<const ConstantExpression*>(this)->getConstantExpressions();
     std::vector<ConstantExpression*> ret(constRet.size());
@@ -514,18 +518,24 @@
     return OK;
 }
 
-ConstantExpression::CheckAcyclicStatus::CheckAcyclicStatus(status_t status,
-                                                           const ConstantExpression* cycleEnd)
-    : status(status), cycleEnd(cycleEnd) {
+ConstantExpression::CheckAcyclicStatus::CheckAcyclicStatus(
+    status_t status, const ConstantExpression* cycleEnd,
+    const ReferenceConstantExpression* lastReference)
+    : status(status), cycleEnd(cycleEnd), lastReference(lastReference) {
     CHECK(cycleEnd == nullptr || status != OK);
+    CHECK((cycleEnd == nullptr) == (lastReference == nullptr));
 }
 
 ConstantExpression::CheckAcyclicStatus ConstantExpression::checkAcyclic(
     std::unordered_set<const ConstantExpression*>* visited,
     std::unordered_set<const ConstantExpression*>* stack) const {
     if (stack->find(this) != stack->end()) {
+        CHECK(isReferenceConstantExpression())
+            << "Only reference constant expression could be the cycle end";
+
         std::cerr << "ERROR: Cyclic declaration:\n";
-        return CheckAcyclicStatus(UNKNOWN_ERROR, this);
+        return CheckAcyclicStatus(UNKNOWN_ERROR, this,
+                                  static_cast<const ReferenceConstantExpression*>(this));
     }
 
     if (visited->find(this) != visited->end()) return CheckAcyclicStatus(OK);
@@ -548,18 +558,18 @@
             if (err.cycleEnd == nullptr) return err;
 
             // Only ReferenceConstantExpression has references,
-            // mExpr is defined explicitly before evaluation
+            CHECK(isReferenceConstantExpression())
+                << "Only reference constant expression could have refereneces";
 
-            std::cerr << "  ";
-            if (!mTrivialDescription) {
-                std::cerr << "  '" << mExpr << "' ";
-            };
-            std::cerr << "at " << nextRef->location() << "\n";
+            // mExpr is defined explicitly before evaluation
+            std::cerr << "  '" << err.lastReference->mExpr << "' in '" << mExpr << "' at "
+                      << nextRef->location() << "\n";
 
             if (err.cycleEnd == this) {
                 return CheckAcyclicStatus(err.status);
             }
-            return err;
+            return CheckAcyclicStatus(err.status, err.cycleEnd,
+                                      static_cast<const ReferenceConstantExpression*>(this));
         }
     }
 
@@ -608,6 +618,10 @@
     mTrivialDescription = mExpr.empty();
 }
 
+bool ReferenceConstantExpression::isReferenceConstantExpression() const {
+    return true;
+}
+
 std::vector<const ConstantExpression*> ReferenceConstantExpression::getConstantExpressions() const {
     // Returns reference instead
     return {};