public Object visit(ArrayLookup node) {
            Expression expr = node.getExpression();
            Expression lookupIndex = node.getLookupIndex();
            check(expr);
            check(lookupIndex);

            Type type = expr.getType();
            Type lookupType = lookupIndex.getType();

            if (type != null && lookupType != null) {
                // Array lookup can only work on objects.
                type = type.toNonPrimitive();
                expr.convertTo(type);

                // Now check if expression type class supports array lookup.
                // If so, check that lookup index is correct type

                Type elementType;
                try {
                    elementType = type.getArrayElementType();
                }
                catch (IntrospectionException e) {
                    error(e.toString(), node);
                    return null;
                }

                if (elementType == null) {
                    error("arraylookup.unsupported", type.getSimpleName(),
                          node.getLookupToken());

                    return null;
                }

                checkAccess(elementType.getObjectClass(), node);

                // Look for the best array access method.

                Method[] methods;
                try {
                    methods = type.getArrayAccessMethods();
                }
                catch (IntrospectionException e) {
                    error(e.toString(), node);
                    return null;
                }

                boolean good = false;

                if (methods.length == 0) {
                    // Must be an actual Java array.
                    if (type.getObjectClass().isArray()) {
                        Class<?> lookupClass = lookupType.getObjectClass();
                        if (Number.class.isAssignableFrom(lookupClass)) {
                            lookupIndex.convertTo(Type.INT_TYPE);
                            node.setType(elementType);
                            good = true;
                        }
                    }
                }
                else {
                    int count = MethodMatcher.match(methods, null,
                                                    new Type[] {lookupType});
                    if (count >= 1) {
                        Method m = methods[0];
                        lookupType = new Type(m.getParameterTypes()[0],
                                              m.getGenericParameterTypes()[0]);
                        Type returnType = new Type(m.getReturnType(),
                                                   m.getGenericReturnType());

                        // attempt to locate matching generic-based param
                        Type genericType = Generics.findType(returnType, type);

                        node.setType(returnType);
                        if (genericType != null) {
                            node.forceConversion(genericType, true);
                        }
                        else {
                            node.convertTo(elementType);
                        }

                        lookupIndex.convertTo(lookupType);
                        node.setReadMethod(m);
                        node.setType(new Type(m.getReturnType()));
                        node.convertTo(elementType);
                        good = true;
                    }
                }

                if (good) {
                    if (elementType.getObjectClass() == Character.class) {
                        // Convert any returned character to a String.
                        node.convertTo(Type.STRING_TYPE);
                    }
                }
                else {
                    error("arraylookup.unsupported.for", type.getSimpleName(),
                          lookupType.getSimpleName(), lookupIndex);
                }
            }

            return null;
        }