public Object visit(SpreadExpression node) {
            // check associated expression
            Expression expr = node.getExpression();
            check(expr);

            // get element type
            Type elementType = null;
            Type exprType = expr.getType();
            try { elementType = exprType.getIterationElementType(); }
            catch (IntrospectionException exception) {
                throw new IllegalStateException(
                    "unable to lookup spread array element type", exception);
            }

            // validate element type
            if (elementType == null) {
                error("spread.missing.type", node);
                return null;
            }

            // verify valid collection or array
            Class<?> exprClass = exprType.getNaturalClass();
            if (!Collection.class.isAssignableFrom(exprClass) &&
                !exprClass.isArray()) {
                error("spread.not.array", node);
                return null;
            }

            // handle nodes and set no-op per type
            Expression operation = node.getOperation();
            if (operation instanceof Lookup) {
                ((Lookup) operation).getExpression().setType(elementType);
            }
            else if (operation instanceof FunctionCallExpression) {
                ((FunctionCallExpression) operation)
                    .getExpression().setType(elementType);
            }
            else {
                error("spread.operation.unsupported", node);
                return null;
            }

            // check operation for type
            check(operation);

            // ensure operation converts to object wrapers
            if (!exprClass.isArray()) {
                operation.convertTo(operation.getType().toNonPrimitive());
            }

            // get resulting operation type
            Type operationType = node.getOperation().getType();

            // update node types based on operation type
            if (Collection.class.isAssignableFrom(exprClass)) {
                Class<?> listType = ArrayList.class;
                /* NOTE: disable this as we prolly do not want a return list
                 *       to be a set since we lose duplicate properties which
                 *       is not the intent.
                if (Set.class.isAssignableFrom(exprClass)) {
                    listType = HashSet.class;
                }
                */

                Type type = new Type
                (
                    listType,
                    new ParameterizedTypeImpl
                    (
                        listType,
                        new java.lang.reflect.Type[] { operationType.getGenericClass() }
                    )
                );

                try { type = type.setArrayElementType(operationType); }
                catch (IntrospectionException exception) {
                    throw new IllegalStateException(
                        "unable to set spread array element type", exception);
                }

                node.setType(type);
            }
            else if (exprClass.isArray()) {
                Type arrayType = new Type
                (
                    Array.newInstance
                    (
                        operationType.getNaturalClass(), 0
                    ).getClass(),
                    new GenericArrayTypeImpl(operationType.getGenericClass())
                );

                node.setType(arrayType);
            }

            // done
            return null;
        }