support static/dyanmic recursive casting for collections

git-svn-id: https://asterixdb.googlecode.com/svn/branches/asterix_opentype@323 eaa15691-b419-025a-1212-ee371bd00084
diff --git a/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/IntroduceStaticTypeCastRule.java b/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/IntroduceStaticTypeCastRule.java
index 0b429a9..845e4d3 100644
--- a/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/IntroduceStaticTypeCastRule.java
+++ b/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/IntroduceStaticTypeCastRule.java
@@ -15,9 +15,11 @@
 import edu.uci.ics.asterix.om.types.ARecordType;
 import edu.uci.ics.asterix.om.types.ATypeTag;
 import edu.uci.ics.asterix.om.types.AUnionType;
+import edu.uci.ics.asterix.om.types.AbstractCollectionType;
 import edu.uci.ics.asterix.om.types.BuiltinType;
 import edu.uci.ics.asterix.om.types.IAType;
 import edu.uci.ics.asterix.om.util.NonTaggedFormatUtil;
+import edu.uci.ics.asterix.runtime.accessors.base.DefaultOpenFieldType;
 import edu.uci.ics.hyracks.algebricks.common.exceptions.AlgebricksException;
 import edu.uci.ics.hyracks.algebricks.core.algebra.base.ILogicalExpression;
 import edu.uci.ics.hyracks.algebricks.core.algebra.base.ILogicalOperator;
@@ -25,7 +27,6 @@
 import edu.uci.ics.hyracks.algebricks.core.algebra.base.LogicalExpressionTag;
 import edu.uci.ics.hyracks.algebricks.core.algebra.base.LogicalOperatorTag;
 import edu.uci.ics.hyracks.algebricks.core.algebra.base.LogicalVariable;
-import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression;
 import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.ConstantExpression;
 import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.IVariableTypeEnvironment;
 import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression;
@@ -37,10 +38,6 @@
 
 public class IntroduceStaticTypeCastRule implements IAlgebraicRewriteRule {
 
-    // nested open field rec type
-    private static ARecordType nestedOpenRecType = new ARecordType("nested-open", new String[] {}, new IAType[] {},
-            true);
-
     @Override
     public boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context) throws AlgebricksException {
         return false;
@@ -112,7 +109,7 @@
                         ScalarFunctionCallExpression funcExpr = (ScalarFunctionCallExpression) expr;
                         if (TypeComputerUtilities.getRequiredType(funcExpr) != null)
                             return false;
-                        rewriteFuncExpr(funcExpr, requiredRecordType, inputRecordType);
+                        rewriteRecordFuncExpr(funcExpr, requiredRecordType, inputRecordType);
                     }
                     context.computeAndSetTypeEnvironmentForOperator(originalAssign);
                 }
@@ -125,27 +122,47 @@
         return true;
     }
 
-    private void rewriteFuncExpr(ScalarFunctionCallExpression funcExpr, ARecordType requiredRecordType,
+    private void rewriteRecordFuncExpr(ScalarFunctionCallExpression funcExpr, ARecordType requiredRecordType,
             ARecordType inputRecordType) {
+        if (TypeComputerUtilities.getRequiredType(funcExpr) != null)
+            return;
         TypeComputerUtilities.setRequiredAndInputTypes(funcExpr, requiredRecordType, inputRecordType);
-        staticTypeCast(funcExpr, requiredRecordType, inputRecordType);
+        staticRecordTypeCast(funcExpr, requiredRecordType, inputRecordType);
+    }
+
+    private void rewriteFuncExpr(ScalarFunctionCallExpression funcExpr, IAType reqType, IAType inputType) {
+        if (funcExpr.getFunctionIdentifier() == AsterixBuiltinFunctions.UNORDERED_LIST_CONSTRUCTOR) {
+            rewriteListFuncExpr(funcExpr, (AbstractCollectionType) reqType, (AbstractCollectionType) inputType);
+        }
+        if (funcExpr.getFunctionIdentifier() == AsterixBuiltinFunctions.UNORDERED_LIST_CONSTRUCTOR) {
+            rewriteListFuncExpr(funcExpr, (AbstractCollectionType) reqType, (AbstractCollectionType) inputType);
+        } else if (reqType.getTypeTag().equals(ATypeTag.RECORD)) {
+            rewriteRecordFuncExpr(funcExpr, (ARecordType) reqType, (ARecordType) inputType);
+        }
+    }
+
+    private void rewriteListFuncExpr(ScalarFunctionCallExpression funcExpr, AbstractCollectionType requiredListType,
+            AbstractCollectionType inputListType) {
+        if (TypeComputerUtilities.getRequiredType(funcExpr) != null)
+            return;
+
+        TypeComputerUtilities.setRequiredAndInputTypes(funcExpr, requiredListType, inputListType);
         List<Mutable<ILogicalExpression>> args = funcExpr.getArguments();
-        int openPartStart = requiredRecordType.getFieldTypes().length * 2;
-        if (requiredRecordType.isOpen()) {
-            for (int j = openPartStart; j < args.size(); j++) {
-                ILogicalExpression arg = args.get(j).getValue();
-                if (arg.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
-                    AbstractFunctionCallExpression argFunc = (AbstractFunctionCallExpression) arg;
-                    if (argFunc.getFunctionIdentifier() == AsterixBuiltinFunctions.UNORDERED_LIST_CONSTRUCTOR
-                            || argFunc.getFunctionIdentifier() == AsterixBuiltinFunctions.ORDERED_LIST_CONSTRUCTOR) {
-                        TypeComputerUtilities.setOpenType(argFunc, true);
-                    }
-                }
+
+        IAType itemType = requiredListType.getItemType();
+        if (itemType == null || itemType.getTypeTag().equals(ATypeTag.ANY))
+            return;
+        IAType inputItemType = inputListType.getItemType();
+        for (int j = 0; j < args.size(); j++) {
+            ILogicalExpression arg = args.get(j).getValue();
+            if (arg.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
+                ScalarFunctionCallExpression argFunc = (ScalarFunctionCallExpression) arg;
+                rewriteFuncExpr(argFunc, itemType, inputItemType);
             }
         }
     }
 
-    private void staticTypeCast(ScalarFunctionCallExpression func, ARecordType reqType, ARecordType inputType) {
+    private void staticRecordTypeCast(ScalarFunctionCallExpression func, ARecordType reqType, ARecordType inputType) {
         IAType[] reqFieldTypes = reqType.getFieldTypes();
         String[] reqFieldNames = reqType.getFieldNames();
         IAType[] inputFieldTypes = inputType.getFieldTypes();
@@ -167,6 +184,8 @@
         for (int i = 0; i < inputFieldNames.length; i++) {
             String fieldName = inputFieldNames[i];
             IAType fieldType = inputFieldTypes[i];
+
+            ILogicalExpression arg = func.getArguments().get(2 * i + 1).getValue();
             matched = false;
             for (int j = 0; j < reqFieldNames.length; j++) {
                 String reqFieldName = reqFieldNames[j];
@@ -177,10 +196,9 @@
                         openFields[i] = false;
                         matched = true;
 
-                        if (fieldType.getTypeTag() == ATypeTag.RECORD) {
-                            ScalarFunctionCallExpression scalarFunc = (ScalarFunctionCallExpression) func
-                                    .getArguments().get(2 * i + 1).getValue();
-                            rewriteFuncExpr(scalarFunc, (ARecordType) reqFieldType, (ARecordType) fieldType);
+                        if (arg.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
+                            ScalarFunctionCallExpression scalarFunc = (ScalarFunctionCallExpression) arg;
+                            rewriteFuncExpr(scalarFunc, reqFieldType, fieldType);
                         }
                         break;
                     }
@@ -197,21 +215,18 @@
                             matched = true;
 
                             // rewrite record expr
-                            if (reqFieldType.getTypeTag() == ATypeTag.RECORD
-                                    && fieldType.getTypeTag() == ATypeTag.RECORD) {
-                                ScalarFunctionCallExpression scalarFunc = (ScalarFunctionCallExpression) func
-                                        .getArguments().get(2 * i + 1).getValue();
-                                rewriteFuncExpr(scalarFunc, (ARecordType) reqFieldType, (ARecordType) fieldType);
+                            if (arg.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
+                                ScalarFunctionCallExpression scalarFunc = (ScalarFunctionCallExpression) arg;
+                                rewriteFuncExpr(scalarFunc, reqFieldType, fieldType);
                             }
                             break;
                         }
                     }
 
                     // match the record field: need cast
-                    if (reqFieldType.getTypeTag() == ATypeTag.RECORD && fieldType.getTypeTag() == ATypeTag.RECORD) {
-                        ScalarFunctionCallExpression scalarFunc = (ScalarFunctionCallExpression) func.getArguments()
-                                .get(2 * i + 1).getValue();
-                        rewriteFuncExpr(scalarFunc, (ARecordType) reqFieldType, (ARecordType) fieldType);
+                    if (arg.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
+                        ScalarFunctionCallExpression scalarFunc = (ScalarFunctionCallExpression) arg;
+                        rewriteFuncExpr(scalarFunc, reqFieldType, fieldType);
                         fieldPermutation[j] = i;
                         openFields[i] = false;
                         matched = true;
@@ -290,9 +305,23 @@
             if (openFields[i]) {
                 arguments.add(argumentsClone.get(2 * i));
                 Mutable<ILogicalExpression> fExprRef = argumentsClone.get(2 * i + 1);
-                if (inputFieldTypes[i].getTypeTag() == ATypeTag.RECORD) {
-                    ScalarFunctionCallExpression funcExpr = (ScalarFunctionCallExpression) fExprRef.getValue();
-                    rewriteFuncExpr(funcExpr, nestedOpenRecType, (ARecordType) inputFieldTypes[i]);
+                ILogicalExpression argExpr = fExprRef.getValue();
+
+                if (argExpr.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
+                    IAType reqFieldType = inputFieldTypes[i];
+                    if (inputFieldTypes[i].getTypeTag() == ATypeTag.RECORD) {
+                        reqFieldType = DefaultOpenFieldType.NESTED_OPEN_RECORD_TYPE;
+                    }
+                    if (inputFieldTypes[i].getTypeTag() == ATypeTag.ORDEREDLIST) {
+                        reqFieldType = DefaultOpenFieldType.NESTED_OPEN_AORDERED_LIST_TYPE;
+                    }
+                    if (inputFieldTypes[i].getTypeTag() == ATypeTag.UNORDEREDLIST) {
+                        reqFieldType = DefaultOpenFieldType.NESTED_OPEN_AUNORDERED_LIST_TYPE;
+                    }
+                    if (!reqFieldType.equals(inputFieldTypes[i])) {
+                        ScalarFunctionCallExpression argFunc = (ScalarFunctionCallExpression) fExprRef.getValue();
+                        rewriteFuncExpr(argFunc, reqFieldType, inputFieldTypes[i]);
+                    }
                 }
                 arguments.add(fExprRef);
             }
diff --git a/asterix-app/src/test/resources/runtimets/queries/dml/opentype-c2o.aql b/asterix-app/src/test/resources/runtimets/queries/dml/opentype-c2o.aql
index e29ccdc..a63e2df 100644
--- a/asterix-app/src/test/resources/runtimets/queries/dml/opentype-c2o.aql
+++ b/asterix-app/src/test/resources/runtimets/queries/dml/opentype-c2o.aql
@@ -12,7 +12,7 @@
 create type testtype as closed {
   id: string,
   name: string,
-  hobby: string?
+  hobby: {{string}}?
 }
 
 /*
@@ -28,19 +28,19 @@
 create dataset testds2(testtype2) partitioned by key id;
  
 insert into dataset testds (
-{ "hobby": "music", "id": "001", "name": "Person Three"}
+{ "hobby": {{"music", "coding"}}, "id": "001", "name": "Person Three"}
 );
 
 insert into dataset testds (
-{ "name": "Person One", "id": "002", "hobby": "sports"}
+{ "name": "Person One", "id": "002", "hobby": {{"sports"}} }
 );
 
 insert into dataset testds (
-{ "id": "003", "hobby": "movie", "name": "Person Two"}
+{ "id": "003", "hobby": {{"movie", "sports"}}, "name": "Person Two"}
 );
 
 insert into dataset testds (
-{ "id": "004", "name": "Person Four", "hobby": "swimming"}
+{ "id": "004", "name": "Person Four", "hobby": {{"swimming"}} }
 );
  
 insert into dataset testds (
diff --git a/asterix-app/src/test/resources/runtimets/queries/dml/opentype-o2c.aql b/asterix-app/src/test/resources/runtimets/queries/dml/opentype-o2c.aql
index a6ed9cc..015aa7b 100644
--- a/asterix-app/src/test/resources/runtimets/queries/dml/opentype-o2c.aql
+++ b/asterix-app/src/test/resources/runtimets/queries/dml/opentype-o2c.aql
@@ -16,7 +16,7 @@
 }
 
 create type testtype2 as closed {
-  hobby: string?,
+  hobby: {{string}}?,
   id: string,
   name: string
 }
@@ -26,19 +26,19 @@
 create dataset testds2(testtype2) partitioned by key id; 
  
 insert into dataset testds (
-{ "id": "001",  "hobby": "music", "name": "Person Three"}
+{ "id": "001",  "hobby": {{"music"}}, "name": "Person Three"}
 );
 
 insert into dataset testds (
-{ "id": "002", "name": "Person Three", "hobby": "football"}
+{ "id": "002", "name": "Person Three", "hobby": {{"football"}}}
 );
 
 insert into dataset testds (
-{ "id": "003", "name": "Person Three", "hobby": "movie"}
+{ "id": "003", "name": "Person Three", "hobby": {{"movie", "coding", "debugging"}}}
 );
 
 insert into dataset testds (
-{ "name": "Person Three", "hobby": "swimming", "id": "004"}
+{ "name": "Person Three", "hobby": {{"swimming", "music"}}, "id": "004"}
 );
 
 insert into dataset testds (
diff --git a/asterix-app/src/test/resources/runtimets/results/dml/opentype-c2o.adm b/asterix-app/src/test/resources/runtimets/results/dml/opentype-c2o.adm
index 5e7a349..6086a08 100644
--- a/asterix-app/src/test/resources/runtimets/results/dml/opentype-c2o.adm
+++ b/asterix-app/src/test/resources/runtimets/results/dml/opentype-c2o.adm
@@ -1,5 +1,5 @@
-{ "id": "001", "name": "Person Three", "hobby": "music" }
-{ "id": "002", "name": "Person One", "hobby": "sports" }
-{ "id": "003", "name": "Person Two", "hobby": "movie" }
-{ "id": "004", "name": "Person Four", "hobby": "swimming" }
+{ "id": "001", "name": "Person Three", "hobby": {{ "music", "coding" }} }
+{ "id": "002", "name": "Person One", "hobby": {{ "sports" }} }
+{ "id": "003", "name": "Person Two", "hobby": {{ "movie", "sports" }} }
+{ "id": "004", "name": "Person Four", "hobby": {{ "swimming" }} }
 { "id": "005", "name": "Person Five", "hobby": null }
diff --git a/asterix-app/src/test/resources/runtimets/results/dml/opentype-o2c.adm b/asterix-app/src/test/resources/runtimets/results/dml/opentype-o2c.adm
index d9c778b..92809fd 100644
--- a/asterix-app/src/test/resources/runtimets/results/dml/opentype-o2c.adm
+++ b/asterix-app/src/test/resources/runtimets/results/dml/opentype-o2c.adm
@@ -1,5 +1,5 @@
-{ "hobby": "music", "id": "001", "name": "Person Three" }
-{ "hobby": "football", "id": "002", "name": "Person Three" }
-{ "hobby": "movie", "id": "003", "name": "Person Three" }
-{ "hobby": "swimming", "id": "004", "name": "Person Three" }
+{ "hobby": {{ "music" }}, "id": "001", "name": "Person Three" }
+{ "hobby": {{ "football" }}, "id": "002", "name": "Person Three" }
+{ "hobby": {{ "movie", "coding", "debugging" }}, "id": "003", "name": "Person Three" }
+{ "hobby": {{ "swimming", "music" }}, "id": "004", "name": "Person Three" }
 { "hobby": null, "id": "005", "name": "Person Five" }
diff --git a/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/base/TypeComputerUtilities.java b/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/base/TypeComputerUtilities.java
index e8786ec..293aef1 100644
--- a/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/base/TypeComputerUtilities.java
+++ b/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/base/TypeComputerUtilities.java
@@ -1,28 +1,12 @@
 package edu.uci.ics.asterix.om.typecomputer.base;
 
-import edu.uci.ics.asterix.om.types.ARecordType;
+import edu.uci.ics.asterix.om.types.IAType;
 import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression;
 
 public class TypeComputerUtilities {
 
-    public static void setOpenType(AbstractFunctionCallExpression expr, boolean openType) {
-        Boolean openField = true;
-        Object[] opaqueParameters = new Object[1];
-        opaqueParameters[0] = openField;
-        expr.setOpaqueParameters(opaqueParameters);
-    }
-
-    public static boolean isOpenType(AbstractFunctionCallExpression expr) {
-        boolean openType = false;
-        Object[] opaqueParameters = expr.getOpaqueParameters();
-        if (opaqueParameters != null) {
-            openType = (Boolean) opaqueParameters[0];
-        }
-        return openType;
-    }
-
-    public static boolean setRequiredAndInputTypes(AbstractFunctionCallExpression expr, ARecordType requiredRecordType,
-            ARecordType inputRecordType) {
+    public static boolean setRequiredAndInputTypes(AbstractFunctionCallExpression expr, IAType requiredRecordType,
+            IAType inputRecordType) {
         boolean changed = false;
         Object opaqueParameter = expr.getOpaqueParameters();
         if (opaqueParameter == null) {
@@ -35,19 +19,19 @@
         return changed;
     }
 
-    public static ARecordType getRequiredType(AbstractFunctionCallExpression expr) {
+    public static IAType getRequiredType(AbstractFunctionCallExpression expr) {
         Object[] type = expr.getOpaqueParameters();
         if (type != null) {
-            ARecordType recordType = (ARecordType) type[0];
+            IAType recordType = (IAType) type[0];
             return recordType;
         } else
             return null;
     }
 
-    public static ARecordType getInputType(AbstractFunctionCallExpression expr) {
+    public static IAType getInputType(AbstractFunctionCallExpression expr) {
         Object[] type = expr.getOpaqueParameters();
         if (type != null) {
-            ARecordType recordType = (ARecordType) type[1];
+            IAType recordType = (IAType) type[1];
             return recordType;
         } else
             return null;
diff --git a/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/ClosedRecordConstructorResultType.java b/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/ClosedRecordConstructorResultType.java
index 6a17a46..39485ab 100644
--- a/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/ClosedRecordConstructorResultType.java
+++ b/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/ClosedRecordConstructorResultType.java
@@ -31,7 +31,7 @@
         /**
          * if type has been top-down propagated, use the enforced type
          */
-        ARecordType type = TypeComputerUtilities.getRequiredType(f);
+        ARecordType type = (ARecordType) TypeComputerUtilities.getRequiredType(f);
         if (type != null)
             return type;
 
diff --git a/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/OpenRecordConstructorResultType.java b/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/OpenRecordConstructorResultType.java
index 8b27a82..790ca3f 100644
--- a/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/OpenRecordConstructorResultType.java
+++ b/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/OpenRecordConstructorResultType.java
@@ -33,7 +33,7 @@
         /**
          * if type has been top-down propagated, use the enforced type
          */
-        ARecordType type = TypeComputerUtilities.getRequiredType(f);
+        ARecordType type = (ARecordType) TypeComputerUtilities.getRequiredType(f);
         if (type != null)
             return type;
 
diff --git a/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/OrderedListConstructorResultType.java b/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/OrderedListConstructorResultType.java
index 47f239b..c4e35b6 100644
--- a/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/OrderedListConstructorResultType.java
+++ b/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/OrderedListConstructorResultType.java
@@ -7,7 +7,6 @@
 import edu.uci.ics.asterix.om.types.AOrderedListType;
 import edu.uci.ics.asterix.om.types.ATypeTag;
 import edu.uci.ics.asterix.om.types.AUnionType;
-import edu.uci.ics.asterix.om.types.BuiltinType;
 import edu.uci.ics.asterix.om.types.IAType;
 import edu.uci.ics.asterix.om.util.NonTaggedFormatUtil;
 import edu.uci.ics.hyracks.algebricks.common.exceptions.AlgebricksException;
@@ -24,26 +23,28 @@
     public AOrderedListType computeType(ILogicalExpression expression, IVariableTypeEnvironment env,
             IMetadataProvider<?, ?> metadataProvider) throws AlgebricksException {
         AbstractFunctionCallExpression f = (AbstractFunctionCallExpression) expression;
-        boolean openType = TypeComputerUtilities.isOpenType(f);
-        int n = f.getArguments().size();
-        if (n == 0 || openType) {
-            return new AOrderedListType(BuiltinType.ANY, null);
-        } else {
-            ArrayList<IAType> types = new ArrayList<IAType>();
-            for (int k = 0; k < f.getArguments().size(); k++) {
-                IAType type = (IAType) env.getType(f.getArguments().get(k).getValue());
-                if (type.getTypeTag() == ATypeTag.UNION && NonTaggedFormatUtil.isOptionalField((AUnionType) type))
-                    type = ((AUnionType) type).getUnionList()
-                            .get(NonTaggedFormatUtil.OPTIONAL_TYPE_INDEX_IN_UNION_LIST);
-                if (types.indexOf(type) < 0) {
-                    types.add(type);
-                }
-            }
-            if (types.size() == 1) {
-                return new AOrderedListType(types.get(0), null);
-            } else {
-                throw new AlgebricksException("You can not construct a heterogenous list.");
+
+        /**
+         * if type has been top-down propagated, use the enforced type
+         */
+        AOrderedListType reqType = (AOrderedListType) TypeComputerUtilities.getRequiredType(f);
+        if (reqType != null)
+            return reqType;
+
+        ArrayList<IAType> types = new ArrayList<IAType>();
+        for (int k = 0; k < f.getArguments().size(); k++) {
+            IAType type = (IAType) env.getType(f.getArguments().get(k).getValue());
+            if (type.getTypeTag() == ATypeTag.UNION && NonTaggedFormatUtil.isOptionalField((AUnionType) type))
+                type = ((AUnionType) type).getUnionList().get(NonTaggedFormatUtil.OPTIONAL_TYPE_INDEX_IN_UNION_LIST);
+            if (types.indexOf(type) < 0) {
+                types.add(type);
             }
         }
+        if (types.size() == 1) {
+            return new AOrderedListType(types.get(0), null);
+        } else {
+            throw new AlgebricksException("You can not construct a heterogenous list.");
+        }
+
     }
 }
diff --git a/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/UnorderedListConstructorResultType.java b/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/UnorderedListConstructorResultType.java
index 0e03e6d..21c473d 100644
--- a/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/UnorderedListConstructorResultType.java
+++ b/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/UnorderedListConstructorResultType.java
@@ -7,7 +7,6 @@
 import edu.uci.ics.asterix.om.types.ATypeTag;
 import edu.uci.ics.asterix.om.types.AUnionType;
 import edu.uci.ics.asterix.om.types.AUnorderedListType;
-import edu.uci.ics.asterix.om.types.BuiltinType;
 import edu.uci.ics.asterix.om.types.IAType;
 import edu.uci.ics.asterix.om.util.NonTaggedFormatUtil;
 import edu.uci.ics.hyracks.algebricks.common.exceptions.AlgebricksException;
@@ -24,26 +23,28 @@
     public AUnorderedListType computeType(ILogicalExpression expression, IVariableTypeEnvironment env,
             IMetadataProvider<?, ?> metadataProvider) throws AlgebricksException {
         AbstractFunctionCallExpression f = (AbstractFunctionCallExpression) expression;
-        boolean openType = TypeComputerUtilities.isOpenType(f);
-        int n = f.getArguments().size();
-        if (n == 0 || openType) {
-            return new AUnorderedListType(BuiltinType.ANY, null);
-        } else {
-            ArrayList<IAType> types = new ArrayList<IAType>();
-            for (int k = 0; k < f.getArguments().size(); k++) {
-                IAType type = (IAType) env.getType(f.getArguments().get(k).getValue());
-                if (type.getTypeTag() == ATypeTag.UNION && NonTaggedFormatUtil.isOptionalField((AUnionType) type))
-                    type = ((AUnionType) type).getUnionList()
-                            .get(NonTaggedFormatUtil.OPTIONAL_TYPE_INDEX_IN_UNION_LIST);
-                if (types.indexOf(type) < 0) {
-                    types.add(type);
-                }
-            }
-            if (types.size() == 1) {
-                return new AUnorderedListType(types.get(0), null);
-            } else {
-                throw new AlgebricksException("You can not construct a heterogenous list.");
+
+        /**
+         * if type has been top-down propagated, use the enforced type
+         */
+        AUnorderedListType reqType = (AUnorderedListType) TypeComputerUtilities.getRequiredType(f);
+        if (reqType != null)
+            return reqType;
+
+        ArrayList<IAType> types = new ArrayList<IAType>();
+        for (int k = 0; k < f.getArguments().size(); k++) {
+            IAType type = (IAType) env.getType(f.getArguments().get(k).getValue());
+            if (type.getTypeTag() == ATypeTag.UNION && NonTaggedFormatUtil.isOptionalField((AUnionType) type))
+                type = ((AUnionType) type).getUnionList().get(NonTaggedFormatUtil.OPTIONAL_TYPE_INDEX_IN_UNION_LIST);
+            if (types.indexOf(type) < 0) {
+                types.add(type);
             }
         }
+        if (types.size() == 1) {
+            return new AUnorderedListType(types.get(0), null);
+        } else {
+            throw new AlgebricksException("You can not construct a heterogenous list.");
+        }
+
     }
 }
diff --git a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/AListAccessor.java b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/AListAccessor.java
index 8599d38..8056d09 100644
--- a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/AListAccessor.java
+++ b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/AListAccessor.java
@@ -24,7 +24,6 @@
         }
     };
 
-    private AbstractCollectionType inputType;
     private IAType itemType;
     private ATypeTag itemTag;
     private boolean typedItemList = false;
@@ -33,16 +32,11 @@
     private List<IBinaryAccessor> itemTags = new ArrayList<IBinaryAccessor>();
     private AccessorAllocator allocator = new AccessorAllocator();
 
-    private byte[] typeBuffer = new byte[32768];
-    private ResettableByteArrayOutputStream typeBos = new ResettableByteArrayOutputStream();
-    private DataOutputStream typeDos = new DataOutputStream(typeBos);
-
     private byte[] dataBuffer = new byte[32768];
     private ResettableByteArrayOutputStream dataBos = new ResettableByteArrayOutputStream();
     private DataOutputStream dataDos = new DataOutputStream(dataBos);
 
     private AListAccessor(AbstractCollectionType inputType) {
-        this.inputType = inputType;
         if (inputType != null && inputType.getItemType() != null) {
             itemType = inputType.getItemType();
             if (itemType.getTypeTag() == ATypeTag.ANY) {
@@ -59,19 +53,10 @@
     private void reset() {
         allocator.reset();
         items.clear();
-        
-        typeBos.setByteArray(typeBuffer, 0);
+        itemTags.clear();
         dataBos.setByteArray(dataBuffer, 0);
     }
 
-    public List<IBinaryAccessor> getItems() {
-        return items;
-    }
-
-    public List<IBinaryAccessor> getItemTags() {
-        return itemTags;
-    }
-
     @Override
     public void reset(byte[] b, int s, int len) {
         reset();
@@ -97,20 +82,46 @@
             if (typedItemList) {
                 for (int i = 0; i < numberOfitems; i++) {
                     itemLength = NonTaggedFormatUtil.getFieldValueLength(b, itemOffset, itemTag, false);
-                    IBinaryAccessor field = allocator.allocateFieldValue(itemType);
-                    field.reset(b, itemOffset, itemLength);
+                    IBinaryAccessor tag = allocator.allocateFieldType();
+                    IBinaryAccessor item = allocator.allocateFieldValue(itemType);
+
+                    // set item type tag
+                    int start = dataBos.size();
+                    dataDos.writeByte(itemTag.serialize());
+                    int end = dataBos.size();
+                    tag.reset(dataBuffer, start, end - start);
+                    itemTags.add(tag);
+                    
+                    // set item value
+                    start = dataBos.size();
+                    dataDos.writeByte(itemTag.serialize());
+                    dataDos.write(b, itemOffset, itemLength);
+                    end = dataBos.size();
+                    item.reset(dataBuffer, start, end - start);
                     itemOffset += itemLength;
+                    items.add(item);
                 }
             } else {
                 for (int i = 0; i < numberOfitems; i++) {
                     itemTag = EnumDeserializer.ATYPETAGDESERIALIZER.deserialize(b[itemOffset]);
                     itemLength = NonTaggedFormatUtil.getFieldValueLength(b, itemOffset, itemTag, true) + 1;
-                    IBinaryAccessor field = allocator.allocateFieldValue(itemType);
-                    field.reset(b, itemOffset, itemLength);
+                    IBinaryAccessor tag = allocator.allocateFieldType();
+                    IBinaryAccessor item = allocator.allocateFieldValue(itemType);
+
+                    // set item type tag
+                    int start = dataBos.size();
+                    dataDos.writeByte(itemTag.serialize());
+                    int end = dataBos.size();
+                    tag.reset(dataBuffer, start, end - start);
+                    itemTags.add(tag);
+
+                    // open part field already include the type tag
+                    item.reset(b, itemOffset, itemLength);
                     itemOffset += itemLength;
+                    items.add(item);
                 }
             }
-        } catch (AsterixException e) {
+        } catch (Exception e) {
             throw new IllegalStateException(e);
         }
     }
@@ -120,4 +131,11 @@
         return vistor.visit(this, tag);
     }
 
+    public List<IBinaryAccessor> getItems() {
+        return items;
+    }
+
+    public List<IBinaryAccessor> getItemTags() {
+        return itemTags;
+    }
 }
diff --git a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/ARecordAccessor.java b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/ARecordAccessor.java
index 686aa8e..776cdc0 100644
--- a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/ARecordAccessor.java
+++ b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/ARecordAccessor.java
@@ -29,7 +29,6 @@
 import edu.uci.ics.asterix.om.types.EnumDeserializer;
 import edu.uci.ics.asterix.om.types.IAType;
 import edu.uci.ics.asterix.om.util.NonTaggedFormatUtil;
-import edu.uci.ics.asterix.runtime.accessors.base.DefaultOpenFieldType;
 import edu.uci.ics.asterix.runtime.accessors.base.IBinaryAccessor;
 import edu.uci.ics.asterix.runtime.accessors.visitor.IBinaryAccessorVisitor;
 import edu.uci.ics.asterix.runtime.util.ResettableByteArrayOutputStream;
@@ -238,12 +237,7 @@
                     fieldValueLength = NonTaggedFormatUtil.getFieldValueLength(b, fieldOffset, typeTag, true) + 1;
 
                     // allocate
-                    IBinaryAccessor fieldValueAccessor;
-
-                    if (typeTag == ATypeTag.RECORD)
-                        fieldValueAccessor = allocator.allocateFieldValue(DefaultOpenFieldType.NESTED_OPEN_RECORD_TYPE);
-                    else
-                        fieldValueAccessor = allocator.allocateFieldValue(null);
+                    IBinaryAccessor fieldValueAccessor = allocator.allocateFieldValue(typeTag);
                     fieldValueAccessor.reset(b, fieldOffset, fieldValueLength);
                     fieldValues.add(fieldValueAccessor);
                     fieldOffset += fieldValueLength;
diff --git a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/AccessorAllocator.java b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/AccessorAllocator.java
index c177b1f..82c56b5 100644
--- a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/AccessorAllocator.java
+++ b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/AccessorAllocator.java
@@ -2,6 +2,7 @@
 
 import edu.uci.ics.asterix.om.types.ATypeTag;
 import edu.uci.ics.asterix.om.types.IAType;
+import edu.uci.ics.asterix.runtime.accessors.base.DefaultOpenFieldType;
 import edu.uci.ics.asterix.runtime.accessors.base.IBinaryAccessor;
 import edu.uci.ics.asterix.runtime.util.container.IElementAllocator;
 import edu.uci.ics.asterix.runtime.util.container.ListElementAllocator;
@@ -33,6 +34,19 @@
         else
             return flatArtifactAllocator.allocate(null);
     }
+    
+    public IBinaryAccessor allocateFieldValue(ATypeTag typeTag) {
+        if(typeTag == null)
+            return flatArtifactAllocator.allocate(null);
+        else if (typeTag.equals(ATypeTag.RECORD))
+            return nestedRecValueAllocator.allocate(DefaultOpenFieldType.NESTED_OPEN_RECORD_TYPE);
+        else if (typeTag.equals(ATypeTag.UNORDEREDLIST))
+            return nestedListValueAllocator.allocate(DefaultOpenFieldType.NESTED_OPEN_AUNORDERED_LIST_TYPE);
+        else if(typeTag.equals(ATypeTag.ORDEREDLIST))
+            return nestedListValueAllocator.allocate(DefaultOpenFieldType.NESTED_OPEN_AORDERED_LIST_TYPE);
+        else
+            return flatArtifactAllocator.allocate(null);
+    }
 
     public IBinaryAccessor allocateNestedListValue(IAType type) {
         return nestedListValueAllocator.allocate(type);
diff --git a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/base/DefaultOpenFieldType.java b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/base/DefaultOpenFieldType.java
index 1544f66..dca89f5 100644
--- a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/base/DefaultOpenFieldType.java
+++ b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/base/DefaultOpenFieldType.java
@@ -2,6 +2,7 @@
 
 import edu.uci.ics.asterix.om.types.AOrderedListType;
 import edu.uci.ics.asterix.om.types.ARecordType;
+import edu.uci.ics.asterix.om.types.ATypeTag;
 import edu.uci.ics.asterix.om.types.AUnorderedListType;
 import edu.uci.ics.asterix.om.types.BuiltinType;
 import edu.uci.ics.asterix.om.types.IAType;
@@ -19,5 +20,16 @@
     // nested open list type
     public static AUnorderedListType NESTED_OPEN_AUNORDERED_LIST_TYPE = new AUnorderedListType(BuiltinType.ANY,
             "nested-unordered-list");
+    
+    public static IAType getDefaultOpenFieldType(ATypeTag tag){
+        if(tag.equals(ATypeTag.RECORD))
+            return NESTED_OPEN_RECORD_TYPE;
+        if(tag.equals(ATypeTag.ORDEREDLIST))
+            return NESTED_OPEN_AORDERED_LIST_TYPE;
+        if(tag.equals(ATypeTag.UNORDEREDLIST))
+            return NESTED_OPEN_AUNORDERED_LIST_TYPE;
+        else
+            return null;
+    }
 
 }
diff --git a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/cast/ACastVisitor.java b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/cast/ACastVisitor.java
index c84f28e..65d8275 100644
--- a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/cast/ACastVisitor.java
+++ b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/cast/ACastVisitor.java
@@ -5,6 +5,7 @@
 
 import edu.uci.ics.asterix.common.exceptions.AsterixException;
 import edu.uci.ics.asterix.om.types.ARecordType;
+import edu.uci.ics.asterix.om.types.AbstractCollectionType;
 import edu.uci.ics.asterix.om.types.IAType;
 import edu.uci.ics.asterix.runtime.accessors.AFlatValueAccessor;
 import edu.uci.ics.asterix.runtime.accessors.AListAccessor;
@@ -16,9 +17,20 @@
 public class ACastVisitor implements IBinaryAccessorVisitor<Void, Triple<IBinaryAccessor, IAType, Boolean>> {
 
     private Map<IBinaryAccessor, ARecordCaster> raccessorToCaster = new HashMap<IBinaryAccessor, ARecordCaster>();
+    private Map<IBinaryAccessor, AListCaster> laccessorToCaster = new HashMap<IBinaryAccessor, AListCaster>();
 
     @Override
-    public Void visit(AListAccessor accessor, Triple<IBinaryAccessor, IAType, Boolean> arg) {
+    public Void visit(AListAccessor accessor, Triple<IBinaryAccessor, IAType, Boolean> arg) throws AsterixException {
+        AListCaster caster = laccessorToCaster.get(accessor);
+        if (caster == null) {
+            caster = new AListCaster();
+            laccessorToCaster.put(accessor, caster);
+        }
+        try {
+            caster.castList(accessor, arg.first, (AbstractCollectionType) arg.second, this);
+        } catch (Exception e) {
+            throw new AsterixException(e);
+        }
         return null;
     }
 
@@ -39,7 +51,7 @@
 
     @Override
     public Void visit(AFlatValueAccessor accessor, Triple<IBinaryAccessor, IAType, Boolean> arg) {
-        //set the pointer for result
+        // set the pointer for result
         arg.first.reset(accessor.getBytes(), accessor.getStartIndex(), accessor.getLength());
         return null;
     }
diff --git a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/cast/AListCaster.java b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/cast/AListCaster.java
new file mode 100644
index 0000000..776c359
--- /dev/null
+++ b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/cast/AListCaster.java
@@ -0,0 +1,86 @@
+package edu.uci.ics.asterix.runtime.accessors.cast;
+
+import java.io.DataOutput;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.List;
+
+import edu.uci.ics.asterix.builders.OrderedListBuilder;
+import edu.uci.ics.asterix.builders.UnorderedListBuilder;
+import edu.uci.ics.asterix.common.exceptions.AsterixException;
+import edu.uci.ics.asterix.om.types.AOrderedListType;
+import edu.uci.ics.asterix.om.types.ATypeTag;
+import edu.uci.ics.asterix.om.types.AUnorderedListType;
+import edu.uci.ics.asterix.om.types.AbstractCollectionType;
+import edu.uci.ics.asterix.om.types.EnumDeserializer;
+import edu.uci.ics.asterix.om.types.IAType;
+import edu.uci.ics.asterix.runtime.accessors.AFlatValueAccessor;
+import edu.uci.ics.asterix.runtime.accessors.AListAccessor;
+import edu.uci.ics.asterix.runtime.accessors.base.DefaultOpenFieldType;
+import edu.uci.ics.asterix.runtime.accessors.base.IBinaryAccessor;
+import edu.uci.ics.asterix.runtime.util.ResettableByteArrayOutputStream;
+import edu.uci.ics.hyracks.algebricks.common.utils.Triple;
+
+class AListCaster {
+
+    private IAType reqItemType;
+    private IBinaryAccessor itemTempReference = AFlatValueAccessor.FACTORY.createElement(null);
+    private Triple<IBinaryAccessor, IAType, Boolean> itemVisitorArg = new Triple<IBinaryAccessor, IAType, Boolean>(
+            itemTempReference, null, null);
+
+    private UnorderedListBuilder unOrderedListBuilder = new UnorderedListBuilder();
+    private OrderedListBuilder orderedListBuilder = new OrderedListBuilder();
+
+    private byte[] dataBuffer = new byte[32768];
+    private ResettableByteArrayOutputStream dataBos = new ResettableByteArrayOutputStream();
+    private DataOutput dataDos = new DataOutputStream(dataBos);
+
+    public AListCaster() {
+
+    }
+
+    public void castList(AListAccessor listAccessor, IBinaryAccessor resultAccessor, AbstractCollectionType reqType,
+            ACastVisitor visitor) throws IOException, AsterixException {
+        if (reqType.getTypeTag().equals(ATypeTag.UNORDEREDLIST)) {
+            unOrderedListBuilder.reset((AUnorderedListType) reqType);
+        }
+        if (reqType.getTypeTag().equals(ATypeTag.ORDEREDLIST)) {
+            orderedListBuilder.reset((AOrderedListType) reqType);
+        }
+        dataBos.setByteArray(dataBuffer, 0);
+
+        List<IBinaryAccessor> itemTags = listAccessor.getItemTags();
+        List<IBinaryAccessor> items = listAccessor.getItems();
+
+        int start = dataBos.size();
+        for (int i = 0; i < items.size(); i++) {
+            IBinaryAccessor itemTypeTag = itemTags.get(i);
+            IBinaryAccessor item = items.get(i);
+            ATypeTag typeTag = EnumDeserializer.ATYPETAGDESERIALIZER.deserialize(itemTypeTag.getBytes()[itemTypeTag
+                    .getStartIndex()]);
+            if (reqItemType == null || reqItemType.getTypeTag().equals(ATypeTag.ANY)) {
+                itemVisitorArg.second = DefaultOpenFieldType.getDefaultOpenFieldType(typeTag);
+                item.accept(visitor, itemVisitorArg);
+            } else {
+                if (typeTag != reqItemType.getTypeTag())
+                    throw new AsterixException("mismatched item type");
+                itemVisitorArg.second = reqItemType;
+                item.accept(visitor, itemVisitorArg);
+            }
+            if (reqType.getTypeTag().equals(ATypeTag.ORDEREDLIST)) {
+                orderedListBuilder.addItem(itemVisitorArg.first);
+            }
+            if (reqType.getTypeTag().equals(ATypeTag.UNORDEREDLIST)) {
+                unOrderedListBuilder.addItem(itemVisitorArg.first);
+            }
+        }
+        if (reqType.getTypeTag().equals(ATypeTag.ORDEREDLIST)) {
+            orderedListBuilder.write(dataDos, true);
+        }
+        if (reqType.getTypeTag().equals(ATypeTag.UNORDEREDLIST)) {
+            unOrderedListBuilder.write(dataDos, true);
+        }
+        int end = dataBos.size();
+        resultAccessor.reset(dataBuffer, start, end - start);
+    }
+}
diff --git a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/cast/ARecordCaster.java b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/cast/ARecordCaster.java
index 8face9c..a4efa58 100644
--- a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/cast/ARecordCaster.java
+++ b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/cast/ARecordCaster.java
@@ -249,8 +249,6 @@
             }
             field.accept(visitor, nestedVisitorArg);
             recBuilder.addField(i, nestedVisitorArg.first);
-            //reset the req type
-            nestedVisitorArg.second = null;
         }
 
         // write the open part
@@ -262,13 +260,9 @@
 
                 ATypeTag typeTag = EnumDeserializer.ATYPETAGDESERIALIZER
                         .deserialize(fieldTypeTag.getBytes()[fieldTypeTag.getStartIndex()]);
-                if (typeTag.equals(ATypeTag.RECORD))
-                    nestedVisitorArg.second = DefaultOpenFieldType.NESTED_OPEN_RECORD_TYPE;
+                nestedVisitorArg.second = DefaultOpenFieldType.getDefaultOpenFieldType(typeTag);
                 field.accept(visitor, nestedVisitorArg);
                 recBuilder.addField(name, nestedVisitorArg.first);
-                
-                //reset the req type
-                nestedVisitorArg.second = null;
             }
         }
         recBuilder.write(output, true);