← Back to team overview

zorba-coders team mailing list archive

[Merge] lp:~zorba-coders/zorba/markos-scratch into lp:zorba

 

Markos Zaharioudakis has proposed merging lp:~zorba-coders/zorba/markos-scratch into lp:zorba.

Commit message:
further optimizations of the FoldConsts and EliminateUnusedLetVars rules

Requested reviews:
  Markos Zaharioudakis (markos-za)

For more details, see:
https://code.launchpad.net/~zorba-coders/zorba/markos-scratch/+merge/131673

further optimizations of the FoldConsts and EliminateUnusedLetVars rules
-- 
https://code.launchpad.net/~zorba-coders/zorba/markos-scratch/+merge/131673
Your team Zorba Coders is subscribed to branch lp:zorba.
=== modified file 'ChangeLog'
--- ChangeLog	2012-10-25 00:18:28 +0000
+++ ChangeLog	2012-10-26 18:28:41 +0000
@@ -7,8 +7,7 @@
   * (bug #1039284) Implemented jn:json-doc().
 
 Optimizations:
-  * Optimized the MarkExpr and EliminateFlworVariables rules of the optimizer
-  * Optimized the MarkFreeVars optimizer rule
+  * Various optimizations in the implementation of the optimizer rules.
 
 Bug Fixes/Other Changes:
   * Change XQXQ (XQuery-for-XQuery) module now part of Zorba core

=== modified file 'src/common/shared_types.h'
--- src/common/shared_types.h	2012-09-19 21:16:15 +0000
+++ src/common/shared_types.h	2012-10-26 18:28:41 +0000
@@ -96,8 +96,10 @@
 class var_expr;
 class flwor_clause;
 class forletwin_clause;
-class for_clause;
-class let_clause;
+class forlet_clause;
+
+typedef forlet_clause for_clause;
+typedef forlet_clause let_clause;
 
 class ItemVariableIterator;
 typedef rchandle<ItemVariableIterator> ItemVariableIterator_t;

=== modified file 'src/compiler/codegen/plan_visitor.cpp'
--- src/compiler/codegen/plan_visitor.cpp	2012-10-24 11:32:56 +0000
+++ src/compiler/codegen/plan_visitor.cpp	2012-10-26 18:28:41 +0000
@@ -897,7 +897,7 @@
           {
             ++numForClauses;
 
-            const for_clause* fc = static_cast<const for_clause*>(c);
+            const forlet_clause* fc = static_cast<const forlet_clause*>(c);
 
             if (fc->get_expr()->is_sequential())
             {
@@ -910,7 +910,7 @@
           }
           else if (c->get_kind() == flwor_clause::let_clause)
           {
-            const let_clause* lc = static_cast<const let_clause*>(c);
+            const forlet_clause* lc = static_cast<const forlet_clause*>(c);
 
             if (lc->get_expr()->is_sequential())
             {
@@ -1061,20 +1061,12 @@
     {
 
     case flwor_clause::for_clause:
-    {
-      visit_flwor_clause(c, isGeneral);
-
-      const for_clause* fc = reinterpret_cast<const for_clause*>(c);
-      fc->get_expr()->accept(*this);
-      break;
-    }
-
     case flwor_clause::let_clause:
     {
       visit_flwor_clause(c, isGeneral);
 
-      const for_clause* fc = reinterpret_cast<const for_clause*>(c);
-      fc->get_expr()->accept(*this);
+      const forlet_clause* flc = reinterpret_cast<const forlet_clause*>(c);
+      flc->get_expr()->accept(*this);
       break;
     }
 
@@ -1860,10 +1852,19 @@
         std::vector<PlanIter_t>& posVarRefs =
         clauseVarMap->theVarRebinds[1]->theOutputVarRefs;
 
-        forletClauses.push_back(flwor::ForLetClause(var->get_name(),
-                                                    varRefs,
-                                                    posVarRefs,
-                                                    domainIter));
+        if (!posVarRefs.empty())
+        {
+          forletClauses.push_back(flwor::ForLetClause(var->get_name(),
+                                                      varRefs,
+                                                      posVarRefs,
+                                                      domainIter));
+        }
+        else
+        {
+          forletClauses.push_back(flwor::ForLetClause(var->get_name(),
+                                                      varRefs,
+                                                      domainIter));
+        }
       }
       else
       {

=== modified file 'src/compiler/expression/expr_base.cpp'
--- src/compiler/expression/expr_base.cpp	2012-10-24 11:32:56 +0000
+++ src/compiler/expression/expr_base.cpp	2012-10-26 18:28:41 +0000
@@ -315,10 +315,18 @@
     setIgnoresDuplicateNodes(ANNOTATION_UNKNOWN);
 
   if (getNonDiscardable() != ANNOTATION_TRUE_FIXED)
-    setNonDiscardable(ANNOTATION_UNKNOWN);
+    setNonDiscardable(ANNOTATION_FALSE);
 
   if (getUnfoldable() != ANNOTATION_TRUE_FIXED)
-    setUnfoldable(ANNOTATION_UNKNOWN);
+    setUnfoldable(ANNOTATION_FALSE);
+
+  setContainsRecursiveCall(ANNOTATION_FALSE);
+
+  if (getConstructsNodes() != ANNOTATION_TRUE_FIXED)
+    setConstructsNodes(ANNOTATION_FALSE);
+
+  if (getDereferencesNodes() != ANNOTATION_TRUE_FIXED)
+    setDereferencesNodes(ANNOTATION_FALSE);
 
   //theFlags1 = 0;
   //setNonDiscardable(ANNOTATION_FALSE);
@@ -897,7 +905,7 @@
         if (found)
           break;
 
-        const for_clause* fc = static_cast<const for_clause*>(clause);
+        const forlet_clause* fc = static_cast<const forlet_clause*>(clause);
 
         if (fc->get_expr()->is_map_internal(e, found) && found)
         {
@@ -915,7 +923,7 @@
         if (found)
           break;
 
-        const let_clause* lc = static_cast<const let_clause*>(clause);
+        const forlet_clause* lc = static_cast<const forlet_clause*>(clause);
 
         if (lc->get_expr()->contains_expr(e))
           return false;

=== modified file 'src/compiler/expression/expr_base.h'
--- src/compiler/expression/expr_base.h	2012-10-24 11:32:56 +0000
+++ src/compiler/expression/expr_base.h	2012-10-26 18:28:41 +0000
@@ -126,8 +126,7 @@
 {
   friend class ExprIterator;
   friend class forletwin_clause;
-  friend class for_clause;
-  friend class let_clause;
+  friend class forlet_clause;
   friend class where_clause;
   friend class function_trace_expr;
 

=== modified file 'src/compiler/expression/expr_manager.cpp'
--- src/compiler/expression/expr_manager.cpp	2012-10-24 11:32:56 +0000
+++ src/compiler/expression/expr_manager.cpp	2012-10-26 18:28:41 +0000
@@ -885,7 +885,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-for_clause* ExprManager::create_for_clause(
+forlet_clause* ExprManager::create_for_clause(
     static_context* sctx,
     const QueryLoc& loc,
     var_expr* varExpr,
@@ -894,19 +894,26 @@
     var_expr* scoreVarExpr,
     bool isOuter)
 {
-  CREATE_AND_RETURN(for_clause,
-          sctx, theCCB, loc, varExpr, domainExpr, posVarExpr, scoreVarExpr, isOuter);
+  CREATE_AND_RETURN(forlet_clause,
+                    sctx, theCCB, loc,
+                    flwor_clause::for_clause,
+                    varExpr, domainExpr, posVarExpr, scoreVarExpr,
+                    isOuter, false);
 }
 
 
-let_clause* ExprManager::create_let_clause(
+forlet_clause* ExprManager::create_let_clause(
     static_context* sctx,
     const QueryLoc& loc,
     var_expr* varExpr,
     expr* domainExpr,
     bool lazy)
 {
-  CREATE_AND_RETURN(let_clause, sctx, theCCB, loc, varExpr, domainExpr, lazy);
+  CREATE_AND_RETURN(forlet_clause,
+                    sctx, theCCB, loc,
+                    flwor_clause::let_clause,
+                    varExpr, domainExpr, NULL, NULL,
+                    false, lazy);
 }
 
 
@@ -921,7 +928,9 @@
     bool lazy)
 {
   CREATE_AND_RETURN(window_clause,
-          sctx, theCCB, loc, winKind, varExpr, domainExpr, winStart, winStop, lazy);
+                    sctx, theCCB, loc,
+                    winKind, varExpr, domainExpr, winStart, winStop,
+                    lazy);
 }
 
 

=== modified file 'src/compiler/expression/expr_manager.h'
--- src/compiler/expression/expr_manager.h	2012-10-24 11:32:56 +0000
+++ src/compiler/expression/expr_manager.h	2012-10-26 18:28:41 +0000
@@ -39,6 +39,7 @@
 class catch_clause;
 class pragma;
 class flwor_clause;
+class forlet_clause;
 class flwor_wincond;
 class copy_clause;
 class window_clause;
@@ -540,7 +541,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-  for_clause* create_for_clause(
+  forlet_clause* create_for_clause(
       static_context* sctx,
       const QueryLoc& loc,
       var_expr* varExpr,
@@ -549,7 +550,7 @@
       var_expr* scoreVarExpr = NULL,
       bool isOuter = false);
 
-  let_clause* create_let_clause(
+  forlet_clause* create_let_clause(
       static_context* sctx,
       const QueryLoc& loc,
       var_expr* varExpr,

=== modified file 'src/compiler/expression/expr_put.cpp'
--- src/compiler/expression/expr_put.cpp	2012-10-24 11:32:56 +0000
+++ src/compiler/expression/expr_put.cpp	2012-10-26 18:28:41 +0000
@@ -204,61 +204,37 @@
 
 ostream& for_clause::put(ostream& os) const
 {
-#if VERBOSE
-  BEGIN_PUT( FOR );
-
-  theVarExpr->put(os);
-  PUT_SUB( "AT", thePosVarExpr );
-  PUT_SUB( "SCORE", theScoreVarExpr );
-
-  PUT_SUB("IN", theDomainExpr);
-
-#else
-  os << indent << "FOR" << expr_addr(this) << " ";
-
-  put_qname(theVarExpr->get_name(), os);
-
-  os << expr_addr(theVarExpr);
-
-  if (thePosVarExpr != NULL)
-  {
-    os << " AT ";
-    put_qname(thePosVarExpr->get_name(), os);
-    os << expr_addr(thePosVarExpr);
-  }
-  os << endl << indent << "[\n" << inc_indent;
-
-  theDomainExpr->put(os);
-#endif
-
-  END_PUT();
-}
-
-
-ostream& let_clause::put(ostream& os) const
-{
-#if VERBOSE
-  BEGIN_PUT(LET);
-
-  theVarExpr->put(os);
-  PUT_SUB("SCORE", theScoreVarExpr);
-
-  PUT_SUB(":=", theDomainExpr);
-
-#else
-  os << indent << "LET" << expr_addr(this) << " ";
-
-  put_qname(theVarExpr->get_name(), os);
-
-  os << expr_addr(theVarExpr);
-
-  os << endl << indent << "[\n" << inc_indent;
-
-  theDomainExpr->put(os);
-#endif
-
-  END_PUT();
-}
+  if (theKind == flwor_clause::for_clause)
+  {
+    os << indent << "FOR" << expr_addr(this) << " ";
+
+    put_qname(theVarExpr->get_name(), os);
+
+    os << expr_addr(theVarExpr);
+
+    if (thePosVarExpr != NULL)
+    {
+      os << " AT ";
+      put_qname(thePosVarExpr->get_name(), os);
+      os << expr_addr(thePosVarExpr);
+    }
+  }
+  else
+  {
+    os << indent << "LET" << expr_addr(this) << " ";
+
+    put_qname(theVarExpr->get_name(), os);
+
+    os << expr_addr(theVarExpr);
+  }
+
+  os << endl << indent << "[\n" << inc_indent;
+    
+  theDomainExpr->put(os);
+
+  END_PUT();
+}
+
 
 ostream& window_clause::put(ostream& os) const
 {

=== modified file 'src/compiler/expression/flwor_expr.cpp'
--- src/compiler/expression/flwor_expr.cpp	2012-10-24 11:32:56 +0000
+++ src/compiler/expression/flwor_expr.cpp	2012-10-26 18:28:41 +0000
@@ -122,20 +122,23 @@
 /*******************************************************************************
 
 ********************************************************************************/
-for_clause::for_clause(
+forlet_clause::forlet_clause(
     static_context* sctx,
     CompilerCB* ccb,
     const QueryLoc& loc,
+    flwor_clause::ClauseKind kind,
     var_expr* varExpr,
     expr* domainExpr,
     var_expr* posVarExpr,
     var_expr* scoreVarExpr,
-    bool isAllowingEmpty)
+    bool isAllowingEmpty,
+    bool lazy)
   :
-  forletwin_clause(sctx, ccb, loc, flwor_clause::for_clause, varExpr, domainExpr),
+  forletwin_clause(sctx, ccb, loc, kind, varExpr, domainExpr),
   thePosVarExpr(posVarExpr),
   theScoreVarExpr(scoreVarExpr),
-  theAllowingEmpty(isAllowingEmpty)
+  theAllowingEmpty(isAllowingEmpty),
+  theLazyEval(lazy)
 {
   if (thePosVarExpr != NULL)
     thePosVarExpr->set_flwor_clause(this);
@@ -149,9 +152,10 @@
     TypeManager* tm = sctx->get_typemanager();
 
     xqtref_t declaredType = varExpr->get_type();
+
     if (declaredType != NULL)
     {
-      if (declaredType->is_empty())
+      if (kind == flwor_clause::for_clause && declaredType->is_empty())
       {
         RAISE_ERROR(err::XPTY0004, loc,
         ERROR_PARAMS(ZED(BadType_23o), "empty-sequence"));
@@ -159,20 +163,19 @@
 
       xqtref_t domainType = domainExpr->get_return_type();
 
-      if (!TypeOps::is_subtype(tm, *rtm.ITEM_TYPE_STAR, *declaredType, loc))
+      if (!TypeOps::is_equal(tm, *rtm.ITEM_TYPE_STAR, *declaredType, loc))
       {
-        declaredType = tm->create_type(*declaredType, TypeConstants::QUANT_STAR);
+        if (kind == flwor_clause::for_clause)
+          declaredType = tm->create_type(*declaredType, domainType->get_quantifier());
 
         if (!TypeOps::is_subtype(tm, *domainType, *declaredType, loc))
         {
           xqtref_t varType = TypeOps::intersect_type(*domainType, *declaredType, tm);
+
           if (TypeOps::is_equal(tm, *varType, *rtm.NONE_TYPE, loc))
           {
             RAISE_ERROR(err::XPTY0004, loc,
-            ERROR_PARAMS(ZED(BadType_23o),
-                         *domainType,
-                         ZED(NoTreatAs_4),
-                         *declaredType));
+            ERROR_PARAMS(ZED(BadType_23o), *domainType, ZED(NoTreatAs_4), *declaredType));
           }
 
           domainExpr = theCCB->theEM->
@@ -191,7 +194,7 @@
 }
 
 
-for_clause::~for_clause()
+forlet_clause::~forlet_clause()
 {
   if (thePosVarExpr != NULL)
     thePosVarExpr->set_flwor_clause(NULL);
@@ -201,19 +204,19 @@
 }
 
 
-var_expr* for_clause::get_pos_var() const
+var_expr* forlet_clause::get_pos_var() const
 {
   return thePosVarExpr;
 }
 
 
-var_expr* for_clause::get_score_var() const
+var_expr* forlet_clause::get_score_var() const
 {
   return theScoreVarExpr;
 }
 
 
-void for_clause::set_pos_var(var_expr* v)
+void forlet_clause::set_pos_var(var_expr* v)
 {
   thePosVarExpr = v;
   if (thePosVarExpr != NULL)
@@ -221,7 +224,7 @@
 }
 
 
-void for_clause::set_score_var(var_expr* v)
+void forlet_clause::set_score_var(var_expr* v)
 {
   theScoreVarExpr = v;
   if (theScoreVarExpr != NULL)
@@ -229,7 +232,7 @@
 }
 
 
-flwor_clause* for_clause::clone(user_function* udf, expr::substitution_t& subst) const
+flwor_clause* forlet_clause::clone(user_function* udf, expr::substitution_t& subst) const
 {
   expr* domainCopy = theDomainExpr->clone(udf, subst);
 
@@ -245,123 +248,31 @@
   }
 
   var_expr* scorevarCopy = NULL;
-  var_expr* score_var_ptr = theScoreVarExpr;
-  if (score_var_ptr)
-  {
-    scorevarCopy = theCCB->theEM->create_var_expr(udf, *score_var_ptr);
-    subst[score_var_ptr] = scorevarCopy;
-  }
-
-  return theCCB->theEM->create_for_clause(theContext,
-                                          get_loc(),
-                                          varCopy,
-                                          domainCopy,
-                                          posvarCopy,
-                                          scorevarCopy,
-                                          theAllowingEmpty);
-}
-
-
-/*******************************************************************************
-
-********************************************************************************/
-let_clause::let_clause(
-    static_context* sctx,
-    CompilerCB* ccb,
-    const QueryLoc& loc,
-    var_expr* varExpr,
-    expr* domainExpr,
-    bool lazy)
-  :
-  forletwin_clause(sctx, ccb, loc, flwor_clause::let_clause, varExpr, domainExpr),
-  theScoreVarExpr(NULL),
-  theLazyEval(lazy)
-{
-  if (theScoreVarExpr != NULL)
-    theScoreVarExpr->set_flwor_clause(this);
-
-  if (varExpr != NULL && sctx != NULL)
-  {
-    RootTypeManager& rtm = GENV_TYPESYSTEM;
-    TypeManager* tm = sctx->get_typemanager();
-
-    xqtref_t declaredType = varExpr->get_type();
-
-    if (declaredType != NULL)
-    {
-      xqtref_t domainType = domainExpr->get_return_type();
-
-      if (!TypeOps::is_subtype(tm, *rtm.ITEM_TYPE_STAR, *declaredType, loc) &&
-          !TypeOps::is_subtype(tm, *domainType, *declaredType, loc))
-      {
-        xqtref_t varType = TypeOps::intersect_type(*domainType, *declaredType, tm);
-
-        if (TypeOps::is_equal(tm, *varType, *rtm.NONE_TYPE, loc))
-        {
-          RAISE_ERROR(err::XPTY0004, loc,
-          ERROR_PARAMS(ZED(BadType_23o), *domainType, ZED(NoTreatAs_4), *declaredType));
-        }
-
-        domainExpr = theCCB->theEM->
-        create_treat_expr(sctx,
-                          domainExpr->get_udf(),
-                          loc,
-                          domainExpr,
-                          declaredType,
-                          TREAT_TYPE_MATCH);
-
-        set_expr(domainExpr);
-      }
-    }
-  }
-}
-
-
-let_clause::~let_clause()
-{
-  if (theScoreVarExpr != NULL)
-    theScoreVarExpr->set_flwor_clause(NULL);
-}
-
-
-var_expr* let_clause::get_score_var() const
-{
-  return theScoreVarExpr;
-}
-
-
-void let_clause::set_score_var(var_expr* v)
-{
-  theScoreVarExpr = v;
-  if (theScoreVarExpr != NULL)
-    theScoreVarExpr->set_flwor_clause(this);
-}
-
-
-flwor_clause* let_clause::clone(user_function* udf, expr::substitution_t& subst) const
-{
-  expr* domainCopy = theDomainExpr->clone(udf, subst);
-
-  var_expr* varCopy = theCCB->theEM->create_var_expr(udf, *theVarExpr);
-  subst[theVarExpr] = varCopy;
-
-#if 0
-  var_expr* scorevarCopy = NULL;
-  var_expr* score_var_ptr = theScoreVarExpr;
-  if (score_var_ptr)
-  {
-    scorevarCopy = theCCB->theEM->create_var_expr(*score_var_ptr);
-    subst->get(score_var_ptr) = scorevarCopy;
-  }
-#endif
-
-  return theCCB->theEM->create_let_clause(theContext,
-                                          get_loc(),
-                                          varCopy,
-                                          domainCopy,
-                                          theLazyEval);
-}
-
+  if (theScoreVarExpr)
+  {
+    scorevarCopy = theCCB->theEM->create_var_expr(udf, *theScoreVarExpr);
+    subst[theScoreVarExpr] = scorevarCopy;
+  }
+
+  if (theKind == flwor_clause::for_clause)
+  {
+    return theCCB->theEM->create_for_clause(theContext,
+                                            get_loc(),
+                                            varCopy,
+                                            domainCopy,
+                                            posvarCopy,
+                                            scorevarCopy,
+                                            theAllowingEmpty);
+  }
+  else
+  {
+    return theCCB->theEM->create_let_clause(theContext,
+                                            get_loc(),
+                                            varCopy,
+                                            domainCopy,
+                                            theLazyEval);
+  }
+}
 
 
 /*******************************************************************************

=== modified file 'src/compiler/expression/flwor_expr.h'
--- src/compiler/expression/flwor_expr.h	2012-10-24 11:32:56 +0000
+++ src/compiler/expression/flwor_expr.h	2012-10-26 18:28:41 +0000
@@ -30,9 +30,6 @@
 class ExprManager;
 
 class order_modifier;
-class flwor_clause;
-class for_clause;
-class let_clause;
 class window_clause;
 class flwor_wincond;
 class orderby_clause;
@@ -96,6 +93,8 @@
 
   ClauseKind get_kind() const { return theKind; }
 
+  void set_kind(ClauseKind k) { theKind = k; }
+
   flwor_expr* get_flwor_expr() const { return theFlworExpr; }
 
   virtual void set_expr(expr* v) { }
@@ -172,7 +171,7 @@
 /***************************************************************************//**
 
 ********************************************************************************/
-class for_clause : public forletwin_clause
+class forlet_clause : public forletwin_clause
 {
   friend class flwor_expr;
   friend class ExprManager;
@@ -182,25 +181,32 @@
   var_expr    * thePosVarExpr;
   var_expr    * theScoreVarExpr;
   bool          theAllowingEmpty;
+  bool          theLazyEval;
 
 protected:
-  for_clause(
+  forlet_clause(
         static_context* sctx,
         CompilerCB* ccb,
         const QueryLoc& loc,
+        flwor_clause::ClauseKind kind,
         var_expr* varExpr,
         expr* domainExpr,
-        var_expr* posVarExpr = NULL,
-        var_expr* scoreVarExpr = NULL,
-        bool isOuter = false);
+        var_expr* posVarExpr,
+        var_expr* scoreVarExpr,
+        bool isOuter,
+        bool lazy);
 
 public:
-  ~for_clause();
+  ~forlet_clause();
 
   bool is_allowing_empty() const { return theAllowingEmpty; }
 
   void set_allowing_empty(bool allowing_empty) { theAllowingEmpty = allowing_empty; }
 
+  void setLazyEval(bool v) { theLazyEval = v; }
+
+  bool lazyEval() const { return theLazyEval; }
+
   var_expr* get_pos_var() const;
 
   var_expr* get_score_var() const;
@@ -216,47 +222,6 @@
 
 
 /***************************************************************************//**
-  theScoreVarExpr :
-  theLazyEval     : Whether the window var can be materilized lazily or not.
-********************************************************************************/
-class let_clause : public forletwin_clause
-{
-  friend class expr;
-  friend class flwor_expr;
-  friend class ExprManager;
-  friend class ExprIterator;
-
-protected:
-  var_expr  * theScoreVarExpr;
-  bool        theLazyEval;
-
-protected:
-  let_clause(
-        static_context* sctx,
-        CompilerCB* ccb,
-        const QueryLoc& loc,
-        var_expr* varExpr,
-        expr* domainExpr,
-        bool lazy = false);
-
-public:
-  ~let_clause();
-
-  var_expr* get_score_var() const;
-
-  void set_score_var(var_expr* v);
-
-  void setLazyEval(bool v) { theLazyEval = v; }
-
-  bool lazyEval() const { return theLazyEval; }
-
-  flwor_clause* clone(user_function* udf, expr::substitution_t& substitution) const;
-
-  std::ostream& put(std::ostream&) const;
-};
-
-
-/***************************************************************************//**
   theWindowKind   :
   theWinStartCond :
   theWinStopCond  :

=== modified file 'src/compiler/expression/var_expr.cpp'
--- src/compiler/expression/var_expr.cpp	2012-10-19 20:42:38 +0000
+++ src/compiler/expression/var_expr.cpp	2012-10-26 18:28:41 +0000
@@ -284,9 +284,12 @@
 /*******************************************************************************
 
 ********************************************************************************/
-for_clause* var_expr::get_for_clause() const
+forlet_clause* var_expr::get_forlet_clause() const
 {
-  return dynamic_cast<for_clause*>(theFlworClause);
+  assert(theFlworClause->get_kind() == flwor_clause::for_clause ||
+         theFlworClause->get_kind() == flwor_clause::let_clause);
+
+  return static_cast<forlet_clause*>(theFlworClause);
 }
 
 

=== modified file 'src/compiler/expression/var_expr.h'
--- src/compiler/expression/var_expr.h	2012-10-09 14:06:08 +0000
+++ src/compiler/expression/var_expr.h	2012-10-26 18:28:41 +0000
@@ -24,7 +24,7 @@
 
 class flwor_clause;
 class forletwin_clause;
-class for_clause;
+class forlet_clause;
 class copy_clause;
 class var_expr;
 class VarInfo;
@@ -230,7 +230,7 @@
 
   forletwin_clause* get_forletwin_clause() const;
 
-  for_clause* get_for_clause() const;
+  forlet_clause* get_forlet_clause() const;
 
   copy_clause* get_copy_clause() const { return theCopyClause; }
 

=== modified file 'src/compiler/rewriter/framework/rewriter_context.cpp'
--- src/compiler/rewriter/framework/rewriter_context.cpp	2012-10-10 13:05:50 +0000
+++ src/compiler/rewriter/framework/rewriter_context.cpp	2012-10-26 18:28:41 +0000
@@ -72,7 +72,7 @@
 }
 
 
-expr* RewriterContext::getRoot()
+expr* RewriterContext::getRoot() const
 {
   return theRoot;
 }

=== modified file 'src/compiler/rewriter/framework/rewriter_context.h'
--- src/compiler/rewriter/framework/rewriter_context.h	2012-10-10 13:05:50 +0000
+++ src/compiler/rewriter/framework/rewriter_context.h	2012-10-26 18:28:41 +0000
@@ -107,7 +107,7 @@
 
   CompilerCB* getCompilerCB() const { return theCCB; }
 
-  expr* getRoot();
+  expr* getRoot() const;
 
   void setRoot(expr* root);
 

=== modified file 'src/compiler/rewriter/rewriters/default_optimizer.cpp'
--- src/compiler/rewriter/rewriters/default_optimizer.cpp	2012-10-24 11:32:56 +0000
+++ src/compiler/rewriter/rewriters/default_optimizer.cpp	2012-10-26 18:28:41 +0000
@@ -38,7 +38,7 @@
   {
     ADD_RULE(MarkExprs);
     ADD_RULE(MarkFreeVars);
-    ADD_RULE(FoldConst(false));
+    ADD_RULE(FoldConst);
     ADD_RULE(PartialEval);
     ADD_RULE(RefactorPredFLWOR);
     ADD_RULE(EliminateUnusedLetVars);

=== modified file 'src/compiler/rewriter/rules/flwor_rules.cpp'
--- src/compiler/rewriter/rules/flwor_rules.cpp	2012-10-24 11:32:56 +0000
+++ src/compiler/rewriter/rules/flwor_rules.cpp	2012-10-26 18:28:41 +0000
@@ -43,16 +43,6 @@
 
 static bool is_trivial_expr(const expr*);
 
-static bool 
-safe_to_fold_single_use(
-    var_expr*,
-    TypeConstants::quantifier_t,
-    const flwor_expr&,
-    const std::vector<const expr*>&);
-
-static bool 
-var_in_try_or_loop(const var_expr*, const expr*, bool, bool, bool&);
-
 static void 
 rewrite_positional_pred(
     RewriterContext&,
@@ -181,6 +171,24 @@
 
 
 /*******************************************************************************
+  This is actually 4 rules bundled together:
+
+  1. trivial-FLWOR-elimination :
+
+  "for $x in E return $x"  --> "E"
+  "let $x := E return $x"  --> "E"
+
+
+  2. where-clause-to-if-then-else :
+
+  "for $x in ... where E ... return ...", and E doesn't depend on FLWOR vars -->
+  "if E then flwor else ()", where flwor is the original flwor expr without the
+  where clause.
+
+
+  3. LET-FOR-variable-folding-or-elimination :
+
+  4. non-grouping-variable-elimination :
 
 *******************************************************************************/
 RULE_REWRITE_PRE(EliminateUnusedLetVars)
@@ -195,48 +203,42 @@
 
   assert(udf == rCtx.theUDF);
 
-  flwor_expr* flworp = static_cast<flwor_expr *>(node);
-  flwor_expr& flwor = *flworp;
+  theFlwor = static_cast<flwor_expr *>(node);
 
-  csize numClauses = flwor.num_clauses();
+  csize numClauses = theFlwor->num_clauses();
 
   // numClauses may be 0 in the case this flwor became a common sub-expression
   // due to var-inlining inside an if-then-else expr (see test
   // zorba/optim/flwor_vars_02.xq)
   if (numClauses == 0)
   {
-    return flwor.get_return_expr();
+    return theFlwor->get_return_expr();
   }
 
-  // "for $x in E return $x"  --> "E"
-  // "let $x := E return $x"  --> "E"
-  // Single windowing clauses are left alone
+  // 1. trivial-FLWOR-elimination
   if (numClauses == 1 &&
-      flwor.get_clause(0)->get_kind() != flwor_clause::window_clause)
+      theFlwor->get_clause(0)->get_kind() != flwor_clause::window_clause)
   {
-    assert(flwor.get_clause(0)->get_kind() == flwor_clause::for_clause ||
-           flwor.get_clause(0)->get_kind() == flwor_clause::let_clause);
+    assert(theFlwor->get_clause(0)->get_kind() == flwor_clause::for_clause ||
+           theFlwor->get_clause(0)->get_kind() == flwor_clause::let_clause);
 
     const forletwin_clause* flwc =
-    static_cast<const forletwin_clause *>(flwor.get_clause(0));
+    static_cast<const forletwin_clause *>(theFlwor->get_clause(0));
 
-    if (flwor.get_return_expr()->get_var() == flwc->get_var())
+    if (theFlwor->get_return_expr()->get_var() == flwc->get_var())
     {
       return flwc->get_expr();
     }
   }
 
-  // "for $x in ... where E ... return ...", and E doesn't depend on FLWOR vars
-  // --> "if E then flwor else ()", where flwor is the original flwor expr
-  // without the where clause.
-  if (!flwor.has_sequential_clauses())
+  // 2. where-clause-to-if-then-else
+  if (!theFlwor->has_sequential_clauses())
   {
-    expr::FreeVars myVars;
     expr* whereExpr = NULL;
 
     for (csize i = 0; i < numClauses; ++i)
     {
-      flwor_clause* clause = flwor.get_clause(i);
+      flwor_clause* clause = theFlwor->get_clause(i);
 
       if (clause->get_kind() == flwor_clause::where_clause)
       {
@@ -249,7 +251,7 @@
         for (; ite != end; ++ite)
         {
           flwor_clause* vc = (*ite)->get_flwor_clause();
-          if (vc != NULL && vc->get_flwor_expr() == flworp)
+          if (vc != NULL && vc->get_flwor_expr() == theFlwor)
             break;
 
           ++k;
@@ -257,14 +259,14 @@
 
         if (k == whereVars.size())
         {
-          flwor.remove_clause(i);
+          theFlwor->remove_clause(i);
 
           if_expr* ifExpr = rCtx.theEM->
           create_if_expr(sctx,
                          udf,
                          loc,
                          whereExpr,
-                         flworp,
+                         theFlwor,
                          rCtx.theEM->create_seq(sctx, udf, loc));
           
           fix_if_annotations(ifExpr);
@@ -285,11 +287,13 @@
   // (d) Remove any unused non-group variables from GROUP BY clauses.
   for (csize i = 0; i < numClauses; ++i)
   {
-    bool substitute = false;
-
-    flwor_clause* c = flwor.get_clause(i);
-
-    if (c->get_kind() == flwor_clause::group_clause)
+    int isReferenced;
+
+    flwor_clause* c = theFlwor->get_clause(i);
+
+    switch (c->get_kind())
+    {
+    case flwor_clause::group_clause:
     {
       group_clause* gc = static_cast<group_clause *>(c);
 
@@ -299,7 +303,7 @@
       for(; ite != end; ++ite)
       {
         var_expr* var = ite->second;
-        int uses = expr_tools::count_variable_uses(&flwor, var, 1, NULL);
+        int uses = expr_tools::count_variable_uses(theFlwor, var, 1, NULL);
 
         if (uses == 0 && !ite->first->isNonDiscardable())
         {
@@ -308,8 +312,10 @@
           end = gc->endNonGroupVars();
         }
       }
+
+      break;
     }
-    else if (c->get_kind() == flwor_clause::for_clause)
+    case flwor_clause::for_clause:
     {
       for_clause* fc = static_cast<for_clause *>(c);
 
@@ -321,7 +327,7 @@
       var_expr* pvar = fc->get_pos_var();
 
       if (pvar != NULL &&
-          expr_tools::count_variable_uses(&flwor, pvar, 1, NULL) == 0)
+          expr_tools::count_variable_uses(theFlwor, pvar, 1, NULL) == 0)
       {
         fc->set_pos_var(NULL);
         pvar = NULL;
@@ -352,132 +358,88 @@
 
           expr* emptyExpr = rCtx.theEM->create_seq(sctx, udf, LOC(node));
           MODIFY(subst_vars(rCtx, node, var, emptyExpr));
-          substitute = true;
+
+          MODIFY(theFlwor->remove_clause(i));
+          --numClauses;
+          --i;
+
+          theFlwor->compute_return_type(false, NULL);
         }
       }
-
       // FOR clause with cardinality 0 or 1
       else
       {
-        if (pvar != NULL)
-        {
-          if (domainQuant == TypeConstants::QUANT_ONE || 
-              ! fc->is_allowing_empty())
-          {
-            expr* constExpr = rCtx.theEM->
-            create_const_expr(sctx, udf, loc, xs_integer::one());
-
-            MODIFY(subst_vars(rCtx, node, pvar, constExpr));
-            fc->set_pos_var(NULL);
-          }
-        }
-
-        std::vector<const expr*> refpath(16);
-        int uses = expr_tools::count_variable_uses(&flwor, var, 2, &refpath);
-
-        if (uses > 1 &&
-            is_trivial_expr(domainExpr) &&
-            (domainQuant == TypeConstants::QUANT_ONE ||
-             fc->is_allowing_empty()))
-        {
-          subst_vars(rCtx, node, var, domainExpr);
-          substitute = true;
-        }
-        else if (uses == 1 &&
-                 (domainQuant == TypeConstants::QUANT_ONE || i == numClauses -1) &&
-                 ((is_trivial_expr(domainExpr) &&
-                   domainQuant == TypeConstants::QUANT_ONE) ||
-                  safe_to_fold_single_use(var, domainQuant, flwor, refpath)))
-        {
-          subst_vars(rCtx, node, var, domainExpr);
-          substitute = true;
-        }
-        else if (uses == 0 &&
-                 !domainExpr->isNonDiscardable() &&
-                 (domainQuant == TypeConstants::QUANT_ONE ||
-                  fc->is_allowing_empty()))
-        {
-          substitute = true;
-        }
-      }
-
-      if (substitute)
-      {
-        MODIFY(flwor.remove_clause(i));
-        --numClauses;
-        --i;
-
-        flwor.compute_return_type(true, NULL);
-      }
+        if (pvar != NULL &&
+            (domainQuant == TypeConstants::QUANT_ONE || 
+             ! fc->is_allowing_empty()))
+        {
+          expr* constExpr = rCtx.theEM->
+          create_const_expr(sctx, udf, loc, xs_integer::one());
+
+          MODIFY(subst_vars(rCtx, node, pvar, constExpr));
+          fc->set_pos_var(NULL);
+        }
+
+        if (safe_to_fold_var(i, isReferenced))
+        {
+          if (isReferenced != 0)
+            subst_vars(rCtx, node, var, domainExpr);
+
+          MODIFY(theFlwor->remove_clause(i));
+          --numClauses;
+          --i;
+
+#if 0
+          std::cout << rCtx.theMessage << std::endl
+                    << "After subst " << var << " :" << std::endl;
+          rCtx.getRoot()->put(std::cout) << std::endl;
+#endif
+          theFlwor->compute_return_type(false, NULL);
+        }
+      }
+
+      break;
     }
-    else if (c->get_kind() == flwor_clause::let_clause)
+    case flwor_clause::let_clause:
     {
       let_clause* lc = static_cast<let_clause *>(c);
-
+      var_expr* var = lc->get_var();
       expr* domainExpr = lc->get_expr();
-      xqtref_t domainType = domainExpr->get_return_type();
-      TypeConstants::quantifier_t domainQuant = domainType->get_quantifier();
-      var_expr* var = lc->get_var();
-
-      if (domainExpr->is_sequential())
-        continue;
-
-      std::vector<const expr*> refpath(16);
-      int uses = expr_tools::count_variable_uses(&flwor, var, 2, &refpath);
-
-      if (uses > 1 && is_trivial_expr(domainExpr))
-      {
-        subst_vars(rCtx, node, var, domainExpr);
-        substitute = true;
-      }
-      else if (uses == 1 &&
-               (is_trivial_expr(domainExpr) ||
-                safe_to_fold_single_use(var, TypeConstants::QUANT_ONE, flwor, refpath)))
-      {
-        subst_vars(rCtx, node, var, domainExpr);
-        substitute = true;
-      }
-      else if (uses == 0 && !domainExpr->isNonDiscardable())
-      {
-        substitute = true;
+      TypeConstants::quantifier_t domainQuant = 
+      domainExpr->get_return_type()->get_quantifier();
+
+      if (safe_to_fold_var(i, isReferenced))
+      {
+        if (isReferenced != 0)
+          subst_vars(rCtx, node, var, domainExpr);
+
+        MODIFY(theFlwor->remove_clause(i));
+        --numClauses;
+        --i;
+
 #if 0
-        rCtx.getCompilerCB()->theXQueryDiagnostics->add_warning(
-          NEW_XQUERY_WARNING(zwarn::ZWST0001_UNUSED_VARIABLE,
-          WARN_PARAMS(var->get_name()->getStringValue()),
-          WARN_LOC(var->get_loc())));
+        std::cout << rCtx.theMessage << std::endl
+                  << "After subst " << var << " :" << std::endl;
+        rCtx.getRoot()->put(std::cout) << std::endl;
 #endif
       }
-
-      if (substitute)
-      {
-        MODIFY(flwor.remove_clause(i));
-        --numClauses;
-        --i;
-      }
       else if (domainQuant == TypeConstants::QUANT_ONE)
       {
-        MODIFY(flwor.remove_clause(i));
-        const QueryLoc& loc = var->get_loc();
-        var_expr* fvar = rCtx.theEM->
-        create_var_expr(sctx, udf, loc, var_expr::for_var, var->get_name());
-
-        fvar->getFreeVars().insert(fvar);
-
-        for_clause* fc = rCtx.theEM->
-        create_for_clause(sctx, loc, fvar, domainExpr);
-
-        flwor.add_clause(i, fc);
-
-        subst_vars(rCtx, node, var, fvar);
+        lc->set_kind(flwor_clause::for_clause);
+        var->set_kind(var_expr::for_var);
+        modified = true;
       }
     }
+    default:
+      break;
+    }
   }
 
   expr* whereCond = NULL;
 
-  while (flwor.num_clauses() > 0)
+  while (theFlwor->num_clauses() > 0)
   {
-    flwor_clause* clause = flwor.get_clause(0);
+    flwor_clause* clause = theFlwor->get_clause(0);
 
     if (clause->get_kind() == flwor_clause::for_clause ||
         clause->get_kind() == flwor_clause::let_clause ||
@@ -502,7 +464,7 @@
         let_clause* letClause = rCtx.theEM->
         create_let_clause(sctx, gVar->get_loc(), gVar, inputExpr);
 
-        flwor.add_clause(1, letClause);
+        theFlwor->add_clause(1, letClause);
       }
 
       const flwor_clause::rebind_list_t& ngVars = gc->get_nongrouping_vars();
@@ -518,10 +480,10 @@
         let_clause* letClause = rCtx.theEM->
         create_let_clause(sctx, ngVar->get_loc(), ngVar, inputExpr);
 
-        flwor.add_clause(1, letClause);
+        theFlwor->add_clause(1, letClause);
       }
 
-      flwor.remove_clause(0);
+      theFlwor->remove_clause(0);
       continue;
     }
     else if (clause->get_kind() == flwor_clause::where_clause)
@@ -553,28 +515,28 @@
       }
 
       //as soon as whereCond is not NULL we don't need to mark as modified
-      flwor.remove_clause(0);
+      theFlwor->remove_clause(0);
       continue;
     }
     else if (clause->get_kind() == flwor_clause::count_clause)
     {
       // since one value is still returned, count variables are changed to 1
       subst_vars(rCtx,
-                 flworp,
+                 theFlwor,
                  static_cast<count_clause*>(clause)->get_var(),
                  rCtx.theEM->create_const_expr(sctx, udf, loc, xs_integer::one()));
 
-      flwor.remove_clause(0);
+      theFlwor->remove_clause(0);
       continue;
     }
     else if (clause->get_kind() == flwor_clause::order_clause)
     {
-      flwor.remove_clause(0);
+      theFlwor->remove_clause(0);
       continue;
     }
     else if (clause->get_kind() == flwor_clause::materialize_clause)
     {
-      flwor.remove_clause(0);
+      theFlwor->remove_clause(0);
       continue;
     }
     else
@@ -585,7 +547,7 @@
 
   if (whereCond != NULL)
   {
-    expr* result = (flwor.num_clauses() > 0 ? flworp : flwor.get_return_expr());
+    expr* result = (theFlwor->num_clauses() > 0 ? theFlwor : theFlwor->get_return_expr());
 
     if_expr* ifExpr = rCtx.theEM->
     create_if_expr(sctx,
@@ -600,8 +562,8 @@
     return ifExpr;
   }
 
-  if (flwor.num_clauses() == 0)
-    return flwor.get_return_expr();
+  if (theFlwor->num_clauses() == 0)
+    return theFlwor->get_return_expr();
 
   return modified ? node : NULL;
 }
@@ -613,43 +575,6 @@
 }
 
 
-/******************************************************************************
-
-******************************************************************************/
-static bool is_trivial_expr(const expr* e)
-{
-  switch (e->get_expr_kind())
-  {
-  case const_expr_kind:
-  {
-    return true;
-  }
-  case var_expr_kind:
-  {
-    const var_expr* ve = static_cast<const var_expr*>(e);
-    enum var_expr::var_kind k = ve->get_kind();
-
-    // NOTE: An arg var is not materialized, and as a result, it cannot be
-    // referenced more than once or be refeneced inside a loop or try block.
-    // Therefore, an arg var that appears as the domain expr of a LET var
-    // cannot trivially substitute the LET var.
-    if (k == var_expr::arg_var ||
-        k == var_expr::local_var ||
-        (k == var_expr::prolog_var && ve->is_mutable()))
-      return false;
-
-    return true;
-  }
-  case wrapper_expr_kind:
-  {
-    return is_trivial_expr(static_cast<const wrapper_expr*>(e)->get_input());
-  }
-  default:
-    return false;
-  }
-}
-
-
 /*****************************************************************************
   Check if it is OK to fold (inline) a FOR/LET var X that we know is referenced
   only once withing its flwor expr.
@@ -659,86 +584,100 @@
   For a FOR var, varQuant is the quantifier of the type of the domain expr.
   It can be either QUANT_ONE or QUANT_QUESTION.
 ******************************************************************************/
-static bool safe_to_fold_single_use(
-    var_expr* var,
-    TypeConstants::quantifier_t varQuant,
-    const flwor_expr& flwor,
-    const std::vector<const expr*>& refpath)
+bool EliminateUnusedLetVars::safe_to_fold_var(csize varPos, int& numRefs)
 {
-  TypeManager* tm = var->get_type_manager();
-
-  if (flwor.dereferencesNodes() && var->get_domain_expr()->constructsNodes())
+  TypeManager* tm = theFlwor->get_type_manager();
+
+  // if set to true, then it is unsafe to fold, but we may still be able to
+  // completely eliminate the var if it not referenced anywhere.
+  bool unsafe = false; 
+
+  theRefPath.clear();
+  numRefs = 0;
+
+  forletwin_clause* varClause = 
+  static_cast<forletwin_clause*>(theFlwor->get_clause(varPos));
+
+  var_expr* var = varClause->get_var();
+  expr* varDomExpr = varClause->get_expr();
+
+  bool isSafeVar = 
+  (varClause->get_kind() == flwor_clause::let_clause ||
+   static_cast<for_clause*>(varClause)->is_allowing_empty() ||
+   varDomExpr->get_return_type()->get_quantifier() == TypeConstants::QUANT_ONE);
+
+  if (is_trivial_expr(varDomExpr))
+  {
+    numRefs = 1;
+    return isSafeVar;
+  }
+
+  if (varDomExpr->is_sequential())
     return false;
 
-  bool declared = false;
-  expr* referencingExpr = NULL;
-  csize numClauses = flwor.num_clauses();
-
-  for (csize i = 0; i < numClauses && referencingExpr == NULL; ++i)
+  if (theFlwor->dereferencesNodes() && varDomExpr->constructsNodes())
+    unsafe = true;
+
+  csize numClauses = theFlwor->num_clauses();
+
+  for (csize i = varPos+1; i < numClauses; ++i)
   {
-    const flwor_clause* clause = flwor.get_clause(i);
+    const flwor_clause* clause = theFlwor->get_clause(i);
     flwor_clause::ClauseKind kind = clause->get_kind();
 
+    std::vector<const expr*>* path = (numRefs > 0 ? NULL : &theRefPath);
+    int maxUses = 2 - numRefs;
+
     switch (kind)
     {
     case flwor_clause::for_clause:
     case flwor_clause::let_clause:
     {
       const forletwin_clause* flc = static_cast<const forletwin_clause *>(clause);
-      var_expr* varExpr = flc->get_var();
       expr* domExpr = flc->get_expr();
 
-      if (! declared)
-      {
-        declared = (varExpr == var);
-        continue;
-      }
-
-      assert(varQuant == TypeConstants::QUANT_ONE);
-
-      if (domExpr->is_sequential())
-        return false;
-
-      // If X is referenced in the current FOR clause .....
-      if (std::find(refpath.begin(), refpath.end(), domExpr) != refpath.end())
-      {
-        referencingExpr = domExpr;
-        break;
-      }
-
-      // If X is referenced after this FOR clause. In this case, we don't want
-      // to inline X because its domain expr will be computed once per iteration
-      // instead of just once.
-      if (kind == flwor_clause::for_clause &&
-          domExpr->get_return_type()->max_card() >= 2)
-        return false;
+      int uses = expr_tools::count_variable_uses(domExpr, var, maxUses, path);
+
+      if (uses > 0)
+      {
+        if (uses + numRefs > 1 || unsafe || !isSafeVar || domExpr->is_sequential())
+          return false;
+
+        numRefs = 1;
+      }
+      else if (numRefs == 0)
+      {
+        if (domExpr->is_sequential())
+          unsafe = true;
+
+        // If X is referenced after this FOR clause. In this case, we don't want
+        // to inline X because its domain expr will be computed once per iteration
+        // instead of just once.
+        if (kind == flwor_clause::for_clause &&
+            domExpr->get_return_type()->max_card() >= 2)
+          unsafe = true;
+      }
 
       break;
     }
     case flwor_clause::where_clause:
     {
-      if (!declared)
-        continue;
-
-      assert(varQuant == TypeConstants::QUANT_ONE);
-
       expr* whereExpr = static_cast<const where_clause*>(clause)->get_expr();
 
-      if (std::find(refpath.begin(), refpath.end(), whereExpr) != refpath.end())
+      int uses = expr_tools::count_variable_uses(whereExpr, var, maxUses, path);
+
+      if (uses > 0)
       {
-        referencingExpr = whereExpr;
-        break;
+        if (uses + numRefs > 1 || unsafe || !isSafeVar)
+          return false;
+
+        numRefs = 1;
       }
 
       break;
     }
     case flwor_clause::order_clause:
     {
-      if (!declared)
-        continue;
-
-      assert(varQuant == TypeConstants::QUANT_ONE);
-
       const orderby_clause* oc = static_cast<const orderby_clause*>(clause);
 
       std::vector<expr*>::const_iterator ite = oc->begin();
@@ -746,10 +685,14 @@
 
       for (; ite != end; ++ite)
       {
-        if (std::find(refpath.begin(), refpath.end(), *ite) != refpath.end())
+        int uses = expr_tools::count_variable_uses(*ite, var, maxUses, path);
+
+        if (uses > 0)
         {
-          referencingExpr = *ite;
-          break;
+          if (uses + numRefs > 1 || unsafe || !isSafeVar)
+            return false;
+
+          numRefs = 1;
         }
       }
 
@@ -757,11 +700,6 @@
     }
     case flwor_clause::group_clause:
     {
-      if (!declared)
-        continue;
-
-      assert(varQuant == TypeConstants::QUANT_ONE);
-
       const group_clause* gc = static_cast<const group_clause*>(clause);
 
       flwor_clause::rebind_list_t::const_iterator ite = gc->beginGroupVars();
@@ -770,10 +708,15 @@
       for (; ite != end; ++ite)
       {
         expr* inputExpr = ite->first;
-        if (std::find(refpath.begin(), refpath.end(), inputExpr) != refpath.end())
+
+        int uses = expr_tools::count_variable_uses(inputExpr, var, maxUses, path);
+
+        if (uses > 0)
         {
-          referencingExpr = inputExpr;
-          break;
+          if (uses + numRefs > 1 || unsafe || !isSafeVar)
+            return false;
+
+          numRefs = 1;
         }
       }
 
@@ -783,10 +726,15 @@
       for (; ite != end; ++ite)
       {
         expr* inputExpr = ite->first;
-        if (std::find(refpath.begin(), refpath.end(), inputExpr) != refpath.end())
+
+        int uses = expr_tools::count_variable_uses(inputExpr, var, maxUses, path);
+
+        if (uses > 0)
         {
-          referencingExpr = inputExpr;
-          break;
+          if (uses + numRefs > 1 || unsafe || !isSafeVar)
+            return false;
+
+          numRefs = 1;
         }
       }
 
@@ -794,47 +742,51 @@
     }
     case flwor_clause::window_clause:
     {
-      if (!declared)
-        continue;
-
-      assert(varQuant == TypeConstants::QUANT_ONE);
-
       const window_clause* wc = static_cast<const window_clause*>(clause);
       expr* domExpr = wc->get_expr();
       flwor_wincond* startCond = wc->get_win_start();
       flwor_wincond* stopCond = wc->get_win_stop();
-      expr* startExpr = (startCond == NULL ? NULL : startCond->get_cond());
-      expr* stopExpr = (stopCond == NULL ? NULL : stopCond->get_cond());
-
-      if (domExpr->is_sequential())
-        return false;
-
-      if (std::find(refpath.begin(), refpath.end(), domExpr) != refpath.end())
-      {
-        referencingExpr = domExpr;
-        break;
-      }
-
-      if (domExpr->get_return_type()->max_card() > 1)
-        return false;
-
-      if (std::find(refpath.begin(), refpath.end(), startExpr) != refpath.end())
-      {
-        referencingExpr = domExpr;
-        break;
-      }
-
-      if (std::find(refpath.begin(), refpath.end(), stopExpr) != refpath.end())
-      {
-        referencingExpr = domExpr;
-        break;
+
+      int uses = expr_tools::count_variable_uses(domExpr, var, maxUses, path);
+
+      if (uses > 0)
+      {
+        if (uses + numRefs > 1 || unsafe || !isSafeVar || domExpr->is_sequential())
+          return false;
+
+        numRefs = 1;
+      }
+      else if (numRefs == 0)
+      {
+        if (domExpr->is_sequential())
+          unsafe = true;
+
+        if (domExpr->get_return_type()->max_card() >= 2)
+          unsafe = true;
+      }
+
+      if (startCond != NULL)
+      {
+        int uses = expr_tools::count_variable_uses(startCond->get_cond(), var, 1, NULL);
+
+        if (uses > 0)
+          return false;
+      }
+
+      if (stopCond != NULL)
+      {
+        int uses = expr_tools::count_variable_uses(stopCond->get_cond(), var, 1, NULL);
+
+        if (uses > 0)
+          return false;
       }
 
       break;
     }
     case flwor_clause::materialize_clause:
     {
-      return false;
+      unsafe = true;
+      break;
     }
     case flwor_clause::count_clause:
     {
@@ -847,46 +799,54 @@
     }
   }
 
-  if (referencingExpr == NULL)
-  {
-    expr* retExpr = flwor.get_return_expr();
-
-    if (retExpr->is_sequential())
-      return false;
-
-    if (std::find(refpath.begin(), refpath.end(), retExpr) != refpath.end())
-    {
-      if (varQuant != TypeConstants::QUANT_ONE)
-      {
-        // We are considering folding a FOR var whose domain expr may be the
-        // empty sequence. We can fold only if doing so will cause the result
-        // of the flwor expr to be the empty sequence in the case where the
-        // domain expr will indeed be equal to the empty sequence.
-        xqtref_t type = retExpr->get_return_type_with_empty_input(var);
-
-        if (TypeOps::is_equal(tm, *type, *GENV_TYPESYSTEM.EMPTY_TYPE, retExpr->get_loc()))
-        {
-          referencingExpr = retExpr;
-        }
-        else
-        {
-          return false;
-        }
-      }
-      else
-      {
-        referencingExpr = retExpr;
-      }
-    }
-  }
-
-  assert(referencingExpr != NULL);
-
-  if (referencingExpr == NULL)
-    return false;
-
-  bool found = false;
-  return !var_in_try_or_loop(var, referencingExpr, false, false, found);
+  expr* retExpr = theFlwor->get_return_expr();
+
+  std::vector<const expr*>* path = (numRefs > 0 ? NULL : &theRefPath);
+  int maxUses = 2 - numRefs;
+
+  int uses = expr_tools::count_variable_uses(retExpr, var, maxUses, path);
+
+  if (uses > 0)
+  {
+    if (uses + numRefs > 1 || unsafe || retExpr->is_sequential())
+      return false;
+
+    numRefs = 1;
+
+    if (varClause->get_kind() == flwor_clause::for_clause &&
+        varDomExpr->get_return_type()->get_quantifier() != TypeConstants::QUANT_ONE)
+    {
+      // We are considering folding a FOR var whose domain expr may be the
+      // empty sequence. We can fold only if doing so will cause the result
+      // of the flwor expr to be the empty sequence in the case where the
+      // domain expr will indeed be equal to the empty sequence.
+      xqtref_t type = retExpr->get_return_type_with_empty_input(var);
+
+      if (!TypeOps::is_equal(tm, *type, *GENV_TYPESYSTEM.EMPTY_TYPE, retExpr->get_loc()))
+      {
+        return false;
+      }
+    }
+  }
+  else if (numRefs == 0)
+  {
+    if (varDomExpr->isNonDiscardable() || !isSafeVar)
+    {
+      return false;
+    }
+    else
+    {
+#if 0
+      rCtx.getCompilerCB()->theXQueryDiagnostics->add_warning(
+          NEW_XQUERY_WARNING(zwarn::ZWST0001_UNUSED_VARIABLE,
+          WARN_PARAMS(var->get_name()->getStringValue()),
+          WARN_LOC(var->get_loc())));
+#endif
+      return true;
+    }
+  }
+
+  return !var_in_try_or_loop(theRefPath);
 }
 
 
@@ -896,324 +856,195 @@
   (a) for-loop within E, or
   (b) try expr within E, or
   (c) while expr within E
-
-  The method traverses recursively the subtree of E looking for variable V and
-  checking whether it crosses a loop or try expr. If it finds V and there is a
-  loop or try expr in the path from E to V, it returns true; otherwise it returns
-  false.
-
-  Note: On the 1st (non-recursive) call, we know that E references V exactly
-  once. But during a recursive call on a subexpr, the subexpr may or may not
-  reference V.
 ********************************************************************************/
-static bool var_in_try_or_loop(
-    const var_expr* v,
-    const expr* e,
-    bool inTryOrLoop,
-    bool hasNodeConstr,
-    bool& found)
+bool EliminateUnusedLetVars::var_in_try_or_loop(const std::vector<const expr*>& path)
 {
-  if (found)
-    return false;
-
-  expr_kind_t kind = e->get_expr_kind();
-
-  if (kind == trycatch_expr_kind)
-  {
-    const trycatch_expr* tce = static_cast<const trycatch_expr *>(e);
-
-    if (var_in_try_or_loop(v, tce->get_try_expr(), true, hasNodeConstr, found))
-    {
-      assert(found);
-      return true;
-    }
-
-    ZORBA_ASSERT(!found);
-
-    csize numClauses = tce->clause_count();
-
-    for (csize i = 0; i < numClauses; ++i)
-    {
-      if (var_in_try_or_loop(v,
-                             tce->get_catch_expr(i),
-                             inTryOrLoop, 
-                             hasNodeConstr,
-                             found))
-      {
-        assert(found);
-        return true;
-      }
-    }
-
-    return false;
-  }
-  else if (kind == while_expr_kind)
-  {
-    const while_expr* we = static_cast<const while_expr *>(e);
-
-    if (var_in_try_or_loop(v, we->get_body(), true, hasNodeConstr, found))
-    {
-      assert(found);
-      return true;
-    }
-
-    ZORBA_ASSERT(!found);
-
-    return false;
-  }
-  else if (kind == flwor_expr_kind || kind == gflwor_expr_kind)
-  {
-    const flwor_expr& flwor = *static_cast<const flwor_expr *>(e);
-
-    for (csize i = 0; i < flwor.num_clauses(); ++i)
-    {
-      const flwor_clause* c = flwor.get_clause(i);
-
-      switch (c->get_kind())
-      {
-      case flwor_clause::for_clause:
-      case flwor_clause::let_clause:
-      {
-        const forletwin_clause* flc = static_cast<const forletwin_clause*>(c);
-        expr* domExpr = flc->get_expr();
-
-        if (var_in_try_or_loop(v, domExpr, inTryOrLoop, hasNodeConstr, found))
-        {
-          assert(found);
-          return true;
-        }
-
-        if (found)
-          return false;
-
-        if (c->get_kind() == flwor_clause::for_clause &&
-            domExpr->get_return_type()->max_card() >= 2)
-        {
-          inTryOrLoop = true;
-        }
-
-        // test rbkt/zorba/extern/5890.xq illustrates why this check is needed
-        //if (hasNodeConstr && domExpr->contains_node_construction())
-        //{
-        //  return true;
-        //}
-
-        break;
-      }
-      case flwor_clause::window_clause:
-      {
-        const window_clause* wc = static_cast<const window_clause*>(c);
-        expr* domExpr = wc->get_expr();
-
-        if (var_in_try_or_loop(v, domExpr, inTryOrLoop, hasNodeConstr, found))
-        {
-          assert(found);
-          return true;
-        }
-
-        if (found)
-          return false;
-
-        inTryOrLoop = true;
-
-        flwor_wincond* startCond = wc->get_win_start();
-        flwor_wincond* stopCond = wc->get_win_stop();
-        expr* startExpr = startCond == NULL ? NULL : startCond->get_cond();
-        expr* stopExpr = stopCond == NULL ? NULL : stopCond->get_cond();
-
-        if (startExpr &&
-            var_in_try_or_loop(v, startExpr, inTryOrLoop, hasNodeConstr, found))
-        {
-          assert(found);
-          return true;
-        }
-
-        if (found)
-          return false;
-
-        if (stopExpr &&
-            var_in_try_or_loop(v, stopExpr, inTryOrLoop, hasNodeConstr, found))
-        {
-          assert(found);
-          return true;
-        }
-
-        if (found)
-          return false;
-
-        break;
-      }
-      case flwor_clause::group_clause:
-      {
-        const group_clause* gc = static_cast<const group_clause*>(c);
-
-        flwor_clause::rebind_list_t::const_iterator ite = gc->beginGroupVars();
-        flwor_clause::rebind_list_t::const_iterator end = gc->endGroupVars();
-
-        for (; ite != end; ++ite)
-        {
-          expr* gExpr = (*ite).first;
-
-          if (var_in_try_or_loop(v, gExpr, inTryOrLoop, hasNodeConstr, found))
-          {
-            assert(found);
-            return true;
-          }
-
-          if (found)
-            return false;
-        }
-
-        ite = gc->beginNonGroupVars();
-        end = gc->endNonGroupVars();
-
-        for (; ite != end; ++ite)
-        {
-          expr* ngExpr = (*ite).first;
-
-          if (var_in_try_or_loop(v, ngExpr, inTryOrLoop, hasNodeConstr, found))
-          {
-            assert(found);
-            return true;
-          }
-
-          if (found)
-            return false;
-        }
-
-        break; // TODO
-      }
-      case flwor_clause::where_clause:
-      {
-        const where_clause* wc = static_cast<const where_clause*>(c);
-
-        if (var_in_try_or_loop(v, wc->get_expr(), inTryOrLoop, hasNodeConstr, found))
-        {
-          assert(found);
-          return true;
-        }
-
-        if (found)
-          return false;
-
-        break;
-      }
-      case flwor_clause::order_clause:
-      {
-        const orderby_clause* oc = static_cast<const orderby_clause*>(c);
-
-        std::vector<expr*>::const_iterator ite = oc->begin();
-        std::vector<expr*>::const_iterator end = oc->end();
-
-        for (; ite != end; ++ite)
-        {
-          if (var_in_try_or_loop(v, *ite, inTryOrLoop, hasNodeConstr, found))
-          {
-            assert(found);
-            return true;
-          }
-          
-          if (found)
-            return false;
-        }
-
-        break;
-      }
-      case flwor_clause::count_clause:
-      {
-        break;
-      }
-      case flwor_clause::materialize_clause:
-      {
-        ZORBA_ASSERT(false);
-      }
-      default:
-      {
-        ZORBA_ASSERT(false);
-      }
-      }
-    }
-
-    return var_in_try_or_loop(v,
-                              flwor.get_return_expr(),
-                              inTryOrLoop,
-                              hasNodeConstr,
-                              found);
-  }
-  else if (e == v)
-  {
-    found = true;
-    return inTryOrLoop;
-  }
-  else if (kind == if_expr_kind)
-  {
-    const if_expr* ifExpr = static_cast<const if_expr*>(e);
-    const expr* condExpr = ifExpr->get_cond_expr();
-
-    if (var_in_try_or_loop(v, condExpr, inTryOrLoop, hasNodeConstr, found))
-      return true;
-
-    if (found)
-      return false;
-
-    // The var may actually be referenced in both the then and the else branches.
-    // So, if we find it in the then branch and is not in try-or-loop in there,
-    // we must still check the else branch.
-
-    bool thenFound = false;
-    bool elseFound = false;
-    const expr* thenExpr = ifExpr->get_then_expr();
-    const expr* elseExpr = ifExpr->get_else_expr();
-
-    if (var_in_try_or_loop(v, thenExpr, inTryOrLoop, hasNodeConstr, thenFound))
-    {
-      assert(thenFound);
-      found = true;
-      return true;
-    }
-
-    if (var_in_try_or_loop(v, elseExpr, inTryOrLoop, hasNodeConstr, elseFound))
-    {
-      assert(elseFound);
-      found = true;
-      return true;
-    }
-
-    found = (thenFound || elseFound);
-    return false;
-  }
-#if 0
-  else if (kind == elem_expr_kind ||
-           kind == attr_expr_kind ||
-           kind == pi_expr_kind ||
-           kind == text_expr_kind ||
-           kind == doc_expr_kind)
-  {
-    // test rbkt/zorba/extern/5890.xq illustrates why this check is needed
-    if (hasNodeConstr)
-      return true;
-  }
-#endif
-
-  // Or else navigate down all children
-  ExprConstIterator ei(e);
-  while (!ei.done())
-  {
-    if (var_in_try_or_loop(v, ei.get_expr(), inTryOrLoop, hasNodeConstr, found))
-    {
-      return true;
-    }
-
-    if (found)
-      return false;
-
-    ei.next();
-  }
-
+  csize numSteps = path.size();
+
+  for (csize n = 0; n < numSteps; ++n)
+  {
+    const expr* node = path[n];
+
+    switch (node->get_expr_kind())
+    {
+    case trycatch_expr_kind:
+    case while_expr_kind:
+    {
+      return true;
+    }
+    case flwor_expr_kind:
+    case gflwor_expr_kind:
+    {
+      const expr* nextNode = path[n+1];
+
+      const flwor_expr* flwor = static_cast<const flwor_expr*>(node);
+
+      bool foundRefClause = false;
+      csize numClauses = flwor->num_clauses();
+
+      for (csize i = 0; i < numClauses && ! foundRefClause; ++i)
+      {
+        flwor_clause* c = flwor->get_clause(i);
+        flwor_clause::ClauseKind ckind = c->get_kind();
+
+        switch (ckind)
+        {
+        case flwor_clause::for_clause:
+        case flwor_clause::let_clause:
+        case flwor_clause::window_clause:
+        {
+          forletwin_clause* flwc = static_cast<forletwin_clause*>(c);
+          expr* domExpr = flwc->get_expr();
+            
+          if (nextNode == domExpr)
+          {
+            foundRefClause = true;
+            break;
+          }
+
+          if (ckind == flwor_clause::window_clause ||
+              (ckind == flwor_clause::for_clause &&
+               domExpr->get_return_type()->max_card() >= 2))
+          {
+            return true;
+          }
+          
+          break;
+        }
+        case flwor_clause::group_clause:
+        {
+          group_clause* gc = static_cast<group_clause*>(c);
+            
+          flwor_clause::rebind_list_t::const_iterator ite = gc->beginGroupVars();
+          flwor_clause::rebind_list_t::const_iterator end = gc->endGroupVars();
+          
+          for (; ite != end; ++ite)
+          {
+            expr* gExpr = (*ite).first;
+            
+            if (nextNode == gExpr)
+            {
+              foundRefClause = true;
+              break;
+            }
+          }
+          
+          if (foundRefClause)
+            break;
+
+          ite = gc->beginNonGroupVars();
+          end = gc->endNonGroupVars();
+          
+          for (; ite != end; ++ite)
+          {
+            expr* ngExpr = (*ite).first;
+            
+            if (nextNode == ngExpr)
+            {
+              foundRefClause = true;
+              break;
+            }
+          }
+          
+          break;
+        }
+        case flwor_clause::where_clause:
+        {
+          where_clause* wc = static_cast<where_clause*>(c);
+            
+          if (nextNode == wc->get_expr())
+            foundRefClause = true;
+          
+          break;
+        }
+        case flwor_clause::order_clause:
+        {
+          orderby_clause* oc = static_cast<orderby_clause*>(c);
+          
+          std::vector<expr*>::const_iterator ite = oc->begin();
+          std::vector<expr*>::const_iterator end = oc->end();
+
+          for (; ite != end; ++ite)
+          {
+            if (nextNode == *ite)
+            {
+              foundRefClause = true;
+              break;
+            }
+          }
+          
+          break;
+        }
+        case flwor_clause::count_clause:
+        {
+          break;
+        }
+        case flwor_clause::materialize_clause:
+        {
+          ZORBA_ASSERT(false);
+        }
+        default:
+        {
+          ZORBA_ASSERT(false);
+        }
+        }
+      } // for each clause
+
+      if (!foundRefClause)
+      {
+        ZORBA_ASSERT(nextNode == flwor->get_return_expr()); 
+      }
+
+      break;
+    }
+    default:
+      break;
+    }
+  } // for each path step
+    
   return false;
 }
 
 
+/******************************************************************************
+
+******************************************************************************/
+static bool is_trivial_expr(const expr* e)
+{
+  switch (e->get_expr_kind())
+  {
+  case const_expr_kind:
+  {
+    return true;
+  }
+  case var_expr_kind:
+  {
+    const var_expr* ve = static_cast<const var_expr*>(e);
+    enum var_expr::var_kind k = ve->get_kind();
+
+    // NOTE: An arg var is not materialized, and as a result, it cannot be
+    // referenced more than once or be refeneced inside a loop or try block.
+    // Therefore, an arg var that appears as the domain expr of a LET var
+    // cannot trivially substitute the LET var.
+    if (k == var_expr::arg_var ||
+        k == var_expr::local_var ||
+        (k == var_expr::prolog_var && ve->is_mutable()))
+      return false;
+
+    assert(!e->isNonDiscardable());
+    return true;
+  }
+  case wrapper_expr_kind:
+  {
+    return is_trivial_expr(static_cast<const wrapper_expr*>(e)->get_input());
+  }
+  default:
+    return false;
+  }
+}
+
+
+
 ////////////////////////////////////////////////////////////////////////////////
 //                                                                            //
 //  RefactorPredFLWOR                                                         //
@@ -1410,7 +1241,7 @@
 
   assert(udf == rCtx.theUDF);
 
-  for_clause* forClause = posVar->get_for_clause();
+  for_clause* forClause = posVar->get_forlet_clause();
   expr* domainExpr = forClause->get_expr();
 
   fo_expr* result;
@@ -1658,7 +1489,7 @@
     }
     }
 
-    for_clause* forClause = posVar->get_for_clause();
+    for_clause* forClause = posVar->get_forlet_clause();
 
     if (forClause->is_allowing_empty())
       return false;

=== modified file 'src/compiler/rewriter/rules/fold_rules.cpp'
--- src/compiler/rewriter/rules/fold_rules.cpp	2012-10-24 11:32:56 +0000
+++ src/compiler/rewriter/rules/fold_rules.cpp	2012-10-26 18:28:41 +0000
@@ -51,11 +51,9 @@
 
 namespace zorba {
 
-static bool standalone_expr(expr*);
-
-static bool already_folded(expr*, RewriterContext&);
-
-static expr* partial_eval_fo (RewriterContext&, fo_expr*);
+static bool execute(CompilerCB*, expr* node, store::Item_t& result);
+
+static expr* partial_eval_fo(RewriterContext&, fo_expr*);
 
 static expr* partial_eval_logic(fo_expr*, bool, RewriterContext&);
 
@@ -67,86 +65,6 @@
 
 
 /*******************************************************************************
-
-********************************************************************************/
-static expr* execute(
-    CompilerCB* compilercb,
-    expr* node,
-    std::vector<store::Item_t>& result)
-{
-  ulong nextVarId = 1;
-  PlanIter_t plan = codegen("const-folded expr", node, compilercb, nextVarId);
-
-  QueryLoc loc = LOC (node);
-  store::Item_t item;
-
-  CompilerCB expr_ccb(*compilercb);
-  expr_ccb.theRootSctx = node->get_sctx();
-
-  try
-  {
-    //std::cout << "Const folding expr : " << std::endl;
-    //node->put(std::cout);
-    //std::cout << std::endl;
-
-    PlanWrapperHolder pw(new PlanWrapper(plan,
-                                         &expr_ccb,
-                                         0,      // dynamic ctx
-                                         NULL,   // xquery
-                                         0,      // stack depth
-                                         expr_ccb.theHaveTimeout,
-                                         expr_ccb.theTimeout));
-    for (;;)
-    {
-      if (!pw->next(item))
-      {
-        break;
-      }
-
-      if (item->isError())
-      {
-        node->setUnfoldable(ANNOTATION_TRUE_FIXED);
-        node->setNonDiscardable(ANNOTATION_TRUE_FIXED);
-        return node;
-      }
-
-      result.push_back(item);
-    }
-
-    return NULL;
-  }
-  catch (ZorbaException const&)
-  {
-    node->setUnfoldable(ANNOTATION_TRUE_FIXED);
-    node->setNonDiscardable(ANNOTATION_TRUE_FIXED);
-    return node;
-    // TODO:
-    // we had to disable folding of errors because the FnErrorIterator
-    // was erroneously used. It always raises a ZorbaUserError (which is not correct).
-#if 0
-    Error lErrorCode = e.theErrorCode;
-    QueryLoc loc;
-    loc.setLineBegin(e.theQueryLine);
-    loc.setColumnBegin(e.theQueryColumn);
-    store::Item_t qname;
-    ITEM_FACTORY->createQName(qname,
-                              "http://www.w3.org/2005/xqt-errors";,
-                              "err",
-                              error::ZorbaError::toString(lErrorCode).c_str());
-    expr* err_expr = rCtx.theEM->create_fo_expr(node->get_sctx_id(),
-                                  loc,
-                                  BUILTIN_FUNC(FN_ERROR_2),
-                                  rCtx.theEM->create_const_expr(node->get_sctx_id(), loc, qname),
-                                  rCtx.theEM->create_const_expr(node->get_sctx_id(), loc, e.theDescription));
-    err_expr->setUnfoldable(ANNOTATION_TRUE_FIXED);
-    err_expr->setNonDiscardable(ANNOTATION_TRUE_FIXED);
-    return err_expr;
-#endif
-  }
-}
-
-
-/*******************************************************************************
   Compute the NON_DISCARDABLE and UNFOLDABLE properties of expressions
 
   The meaning/purpose of the NON_DISCARDABLE property is as follows:
@@ -457,64 +375,158 @@
   fn:concatenate expr, if no item is returned by the evaluation of the const
   expr.
 ********************************************************************************/
-
-RULE_REWRITE_PRE(FoldConst)
-{
-  xqtref_t rtype = node->get_return_type();
-
-  if (standalone_expr(node) &&
-      ! already_folded(node, rCtx) &&
-      node->getFreeVars().empty() &&
-      ! node->isUnfoldable() &&
-      rtype->max_card() <= 1)
-  {
-    std::vector<store::Item_t> result;
-    expr* folded = execute(rCtx.getCompilerCB(), node, result);
-    if (folded == NULL)
-    {
-      ZORBA_ASSERT (result.size () <= 1);
-
-      if (result.size () == 1)
-      {
-        folded = rCtx.theEM->
-        create_const_expr(node->get_sctx(), node->get_udf(), LOC(node), result[0]);
-      }
-      else
-      {
-        folded  = rCtx.theEM->
-        create_seq(node->get_sctx(), node->get_udf(), LOC(node));
-      }
-    }
-    return folded;
-  }
-  return NULL;
-}
-
-
-RULE_REWRITE_POST(FoldConst)
-{
-  return NULL;
-}
-
-
-static bool standalone_expr(expr* e)
-{
-  expr_kind_t k = e->get_expr_kind();
-  return k != match_expr_kind && k != axis_step_expr_kind;
-}
-
-
-static bool already_folded(expr* e, RewriterContext& rCtx)
-{
-  if (e->get_expr_kind () == const_expr_kind)
+expr* FoldConst::apply(RewriterContext& rCtx, expr* node, bool& modified)
+{
+  expr_kind_t k = node->get_expr_kind();
+  xqtref_t rtype = node->get_return_type(); // DO NOT MOVE THIS !!!!
+
+  switch (k)
+  {
+  case const_expr_kind:
+  case match_expr_kind:
+  case axis_step_expr_kind:
+  {
+    break;
+  }
+  case fo_expr_kind:
+  {
+    fo_expr* fo = static_cast<fo_expr*>(node);
+
+    if (fo->get_func()->getKind() == FunctionConsts::OP_CONCATENATE_N &&
+        fo->num_args() == 0)
+      break;
+  }
+   
+  default:
+  {
+    if (node->getFreeVars().empty() &&
+        ! node->isUnfoldable() &&
+        rtype->max_card() <= 1)
+    {
+      store::Item_t result;
+      bool folded = execute(rCtx.getCompilerCB(), node, result);
+
+      if (folded)
+      {
+        expr* foldedExpr;
+
+        if (result)
+        {
+          foldedExpr = rCtx.theEM->
+          create_const_expr(node->get_sctx(), node->get_udf(), LOC(node), result);
+        }
+        else
+        {
+          foldedExpr  = rCtx.theEM->
+          create_seq(node->get_sctx(), node->get_udf(), LOC(node));
+        }
+
+        modified = true;
+        return foldedExpr;
+      }
+    }
+
+    break;
+  }
+  }
+
+  ExprIterator iter(node);
+
+  while (!iter.done())
+  {
+    expr* new_e = apply(rCtx, **iter, modified);
+    if (new_e != NULL)
+    {
+      **iter = new_e;
+    }
+    
+    iter.next();
+  }
+
+  return NULL;
+}
+
+
+/*******************************************************************************
+
+********************************************************************************/
+static bool execute(
+    CompilerCB* compilercb,
+    expr* node,
+    store::Item_t& result)
+{
+  ulong nextVarId = 1;
+  PlanIter_t plan = codegen("const-folded expr", node, compilercb, nextVarId);
+
+  QueryLoc loc = LOC (node);
+  store::Item_t item;
+
+  CompilerCB expr_ccb(*compilercb);
+  expr_ccb.theRootSctx = node->get_sctx();
+
+  try
+  {
+    //std::cout << "Const folding expr : " << std::endl;
+    //node->put(std::cout);
+    //std::cout << std::endl;
+
+    PlanWrapperHolder pw(new PlanWrapper(plan,
+                                         &expr_ccb,
+                                         0,      // dynamic ctx
+                                         NULL,   // xquery
+                                         0,      // stack depth
+                                         expr_ccb.theHaveTimeout,
+                                         expr_ccb.theTimeout));
+    if (pw->next(item))
+    {
+      if (item->isError())
+      {
+        node->setUnfoldable(ANNOTATION_TRUE_FIXED);
+        node->setNonDiscardable(ANNOTATION_TRUE_FIXED);
+        return false;
+      }
+
+      result.transfer(item);
+
+      ZORBA_ASSERT(!pw->next(item));
+    }
+    else
+    {
+      result = NULL;
+    }
+
     return true;
-  if (e->get_expr_kind () != fo_expr_kind)
+  }
+  catch (ZorbaException const&)
+  {
+    node->setUnfoldable(ANNOTATION_TRUE_FIXED);
+    node->setNonDiscardable(ANNOTATION_TRUE_FIXED);
     return false;
 
-  const fo_expr* fo = dynamic_cast<fo_expr*>(e);
-
-  return (fo->get_func()->getKind() == FunctionConsts::OP_CONCATENATE_N &&
-          fo->num_args() == 0);
+    // TODO:
+    // we had to disable folding of errors because the FnErrorIterator
+    // was erroneously used. It always raises a ZorbaUserError (which is not correct).
+#if 0
+    Error lErrorCode = e.theErrorCode;
+    QueryLoc loc;
+    loc.setLineBegin(e.theQueryLine);
+    loc.setColumnBegin(e.theQueryColumn);
+    store::Item_t qname;
+    ITEM_FACTORY->createQName(qname,
+                              "http://www.w3.org/2005/xqt-errors";,
+                              "err",
+                              error::ZorbaError::toString(lErrorCode).c_str());
+    expr* err_expr = rCtx.theEM->
+    create_fo_expr(node->get_sctx_id(),
+                   loc,
+                   BUILTIN_FUNC(FN_ERROR_2),
+                   rCtx.theEM->create_const_expr(node->get_sctx(), loc, qname),
+                   rCtx.theEM->create_const_expr(node->get_sctx(), loc, e.theDescription));
+    err_expr->setUnfoldable(ANNOTATION_TRUE_FIXED);
+    err_expr->setNonDiscardable(ANNOTATION_TRUE_FIXED);
+    return err_expr;
+#endif
+  }
 }
 
 

=== modified file 'src/compiler/rewriter/rules/hoist_rules.cpp'
--- src/compiler/rewriter/rules/hoist_rules.cpp	2012-10-24 11:32:56 +0000
+++ src/compiler/rewriter/rules/hoist_rules.cpp	2012-10-26 18:28:41 +0000
@@ -485,7 +485,7 @@
   create_fo_expr(sctx, udf, loc, BUILTIN_FUNC(OP_HOIST_1), e);
 
   hoisted->setFlags(e->getFlags());
-  letvar->setFlags(e->getFlags());
+  //letvar->setFlags(e->getFlags());
 
   let_clause* flref(rCtx.theEM->create_let_clause(sctx, loc, letvar, hoisted));
 

=== modified file 'src/compiler/rewriter/rules/index_join_rule.cpp'
--- src/compiler/rewriter/rules/index_join_rule.cpp	2012-10-24 11:32:56 +0000
+++ src/compiler/rewriter/rules/index_join_rule.cpp	2012-10-26 18:28:41 +0000
@@ -286,7 +286,7 @@
     return false;
 
   // The expr that defines the inner var must not depend on the outer var.
-  expr* innerDomainExpr = predInfo.theInnerVar->get_for_clause()->get_expr();
+  expr* innerDomainExpr = predInfo.theInnerVar->get_forlet_clause()->get_expr();
   if (checkVarDependency(rCtx, innerDomainExpr, outerVarId))
     return false;
 
@@ -457,7 +457,7 @@
   const QueryLoc& loc = predInfo.thePredicate->get_loc();
   static_context* sctx = predInfo.thePredicate->get_sctx();
   user_function* udf = predInfo.thePredicate->get_udf();
-  for_clause* fc = predInfo.theInnerVar->get_for_clause();
+  for_clause* fc = predInfo.theInnerVar->get_forlet_clause();
 
   assert(udf == rCtx.theUDF);
 

=== modified file 'src/compiler/rewriter/rules/ruleset.h'
--- src/compiler/rewriter/rules/ruleset.h	2012-10-24 11:32:56 +0000
+++ src/compiler/rewriter/rules/ruleset.h	2012-10-26 18:28:41 +0000
@@ -41,14 +41,10 @@
 
 PREPOST_RULE(EliminateTypeEnforcingOperations);
 
-PREPOST_RULE(EliminateUnusedLetVars);
-
 PREPOST_RULE(RefactorPredFLWOR);
 
 PREPOST_RULE(MergeFLWOR);
 
-  //PREPOST_RULE(MarkFreeVars);
-
 PREPOST_RULE(EliminateExtraneousPathSteps);
 
 PREPOST_RULE(InlineFunctions);
@@ -59,23 +55,45 @@
 /*******************************************************************************
 
 ********************************************************************************/
-class FoldConst : public PrePostRewriteRule
+class EliminateUnusedLetVars : public PrePostRewriteRule
 {
 protected:
-  bool  theFoldExpensiveOps;
+  flwor_expr                * theFlwor;
+  std::vector<const expr*>    theRefPath;
 
 public:
-  FoldConst(bool fold_expensive_ops)
+  EliminateUnusedLetVars()
     :
-    PrePostRewriteRule(RewriteRule::FoldConst, "FoldConst"),
-    theFoldExpensiveOps(fold_expensive_ops)
+    PrePostRewriteRule(RewriteRule::EliminateUnusedLetVars, "EliminateUnusedLetVars"),
+    theFlwor(NULL)
   {
+    theRefPath.reserve(32);
   }
 
 protected:
   expr* rewritePre(expr* node, RewriterContext& rCtx);
 
   expr* rewritePost(expr* node, RewriterContext& rCtx);
+
+  bool safe_to_fold_var(csize varClausePos, int& numRefs);
+
+  bool var_in_try_or_loop(const std::vector<const expr*>& path);
+};
+
+
+/*******************************************************************************
+
+********************************************************************************/
+class FoldConst : public RewriteRule
+{
+public:
+  FoldConst()
+    :
+    RewriteRule(RewriteRule::FoldConst, "FoldConst")
+  {
+  }
+
+  expr* apply(RewriterContext& rCtx, expr* node, bool& modified);
 };
 
 

=== modified file 'src/compiler/rewriter/tools/expr_tools.cpp'
--- src/compiler/rewriter/tools/expr_tools.cpp	2012-10-24 11:32:56 +0000
+++ src/compiler/rewriter/tools/expr_tools.cpp	2012-10-26 18:28:41 +0000
@@ -81,7 +81,7 @@
       return false;
     }
 
-    int thenCount = 0;
+    int thenCount = count;
     std::vector<const expr*>* thenPath = (count == 0 ? path : NULL);
 
     if (!count_var_uses_rec(ifExpr->get_then_expr(), var, limit, thenPath, thenCount))
@@ -91,7 +91,7 @@
       return false;
     }
 
-    int elseCount = 0;
+    int elseCount = count;
     std::vector<const expr*>* elsePath = (count == 0 ? path : NULL);
 
     if (!count_var_uses_rec(ifExpr->get_else_expr(), var, limit, elsePath, elseCount))
@@ -101,7 +101,7 @@
       return false;
     }
 
-    count += (thenCount > elseCount ? thenCount : elseCount);
+    count = (thenCount > elseCount ? thenCount : elseCount);
   }
   else
   {

=== modified file 'src/compiler/translator/translator.cpp'
--- src/compiler/translator/translator.cpp	2012-10-24 12:49:43 +0000
+++ src/compiler/translator/translator.cpp	2012-10-26 18:28:41 +0000
@@ -1619,12 +1619,11 @@
   Create a LET clause for the given LET variable "lv", with the given expr "e" as
   its defining expression.
 ********************************************************************************/
-let_clause* wrap_in_letclause(expr* e, var_expr* lv)
+forlet_clause* wrap_in_letclause(expr* e, var_expr* lv)
 {
   assert (lv->get_kind () == var_expr::let_var);
 
-  return theExprManager->
-  create_let_clause(theRootSctx, e->get_loc(), lv, e);
+  return theExprManager->create_let_clause(theRootSctx, e->get_loc(), lv, e);
 }
 
 
@@ -1633,7 +1632,7 @@
   local sctx obj. Then, create a LET clause for this new var_expr, with the given
   expr "e" as its defining expression.
 ********************************************************************************/
-let_clause* wrap_in_letclause(
+forlet_clause* wrap_in_letclause(
     expr* e,
     const QueryLoc& loc,
     const QName* qname)
@@ -1647,7 +1646,7 @@
   this new var_expr, with the given expr "e" as its defining expression. NOTE:
   the internal var is not registered in the sctx.
 ********************************************************************************/
-let_clause* wrap_in_letclause(expr* e)
+forlet_clause* wrap_in_letclause(expr* e)
 {
   return wrap_in_letclause(e, create_temp_var(e->get_loc(), var_expr::let_var));
 }
@@ -1657,7 +1656,7 @@
   Create a FOR clause for the given FOR variable "fv" and its associated POS var
   "pv" (pv may be NULL). Use the given expr "e" as the defining expr for "fv".
 ********************************************************************************/
-for_clause* wrap_in_forclause(expr* e, var_expr* fv, var_expr* pv)
+forlet_clause* wrap_in_forclause(expr* e, var_expr* fv, var_expr* pv)
 {
   assert(fv->get_kind () == var_expr::for_var);
   if (pv != NULL)
@@ -1665,8 +1664,7 @@
     assert(pv->get_kind() == var_expr::pos_var);
   }
 
-  return theExprManager->
-  create_for_clause(theRootSctx, e->get_loc(), fv, e, pv);
+  return theExprManager->create_for_clause(theRootSctx, e->get_loc(), fv, e, pv);
 }
 
 
@@ -1676,7 +1674,7 @@
   Then, create a FOR clause for these new var_exprs, with the given expr as the
   defining expression of the FOR var.
 ********************************************************************************/
-for_clause* wrap_in_forclause(
+forlet_clause* wrap_in_forclause(
     expr* expr,
     const QueryLoc& loc,
     const QName* fv_qname,
@@ -1693,7 +1691,7 @@
   this new var_expr, with the given expr as its defining expression. NOTE:
   the internal var is not registered in the sctx.
 ********************************************************************************/
-for_clause* wrap_in_forclause(expr* expr, bool add_posvar)
+forlet_clause* wrap_in_forclause(expr* expr, bool add_posvar)
 {
   var_expr* fv = create_temp_var(expr->get_loc(), var_expr::for_var);
 
@@ -1769,13 +1767,13 @@
 
     normalize_fo(countExpr);
 
-    let_clause* lcLast = wrap_in_letclause(countExpr, loc, LAST_IDX_VARNAME);
+    forlet_clause* lcLast = wrap_in_letclause(countExpr, loc, LAST_IDX_VARNAME);
 
     // Iterate over the input seq
     for_clause* fcDot = wrap_in_forclause(lcInputSeq->get_var(),
-                                           loc,
-                                           DOT_VARNAME,
-                                           DOT_POS_VARNAME);
+                                          loc,
+                                          DOT_VARNAME,
+                                          DOT_POS_VARNAME);
     flworExpr->add_clause(lcInputSeq);
     flworExpr->add_clause(lcLast);
     flworExpr->add_clause(fcDot);
@@ -1784,9 +1782,9 @@
   {
     // Iterate over the input seq
     for_clause* fcDot = wrap_in_forclause(inputExpr,
-                                           loc,
-                                           DOT_VARNAME,
-                                           DOT_POS_VARNAME);
+                                          loc,
+                                          DOT_VARNAME,
+                                          DOT_POS_VARNAME);
     flworExpr->add_clause(fcDot);
   }
 

=== modified file 'test/rbkt/Queries/zorba/nodes/path.xq'
--- test/rbkt/Queries/zorba/nodes/path.xq	2012-07-13 18:51:36 +0000
+++ test/rbkt/Queries/zorba/nodes/path.xq	2012-10-26 18:28:41 +0000
@@ -7,3 +7,11 @@
     $f := $a//@ns:f
 return
   ( path($doc), path($b), path($d), path($f) )
+
+(:
+let 
+    $a := <a><b/><b><c/></b><ns:e/></a>,
+    $b := $a/b[c]
+return
+  ( path($b) )
+:)


Follow ups