Search in sources :

Example 96 with AnnotationValue

use of javax.lang.model.element.AnnotationValue in project graal by oracle.

the class StructsProcessor method process.

@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
    if (done) {
        return false;
    }
    // Initialize annotations
    generateStructs = findAnnotation(GENERATE_STRUCTS);
    knownStruct = findAnnotation(KNOWN_STRUCT);
    genStructValue = findAttribute("value", generateStructs);
    structName = findAttribute("structName", knownStruct);
    memberNames = findAttribute("memberNames", knownStruct);
    types = findAttribute("types", knownStruct);
    List<String> structs = new ArrayList<>();
    // Look at the @GenerateStructs annotation
    for (Element e : roundEnv.getElementsAnnotatedWith(generateStructs)) {
        assert e.getKind() == ElementKind.CLASS;
        AnnotationMirror generateStructAnnotation = EspressoProcessor.getAnnotation(e, generateStructs);
        // Obtain the value() of @GenerateStructs (The only interesting thing)
        AnnotationValue v = getAttribute(generateStructAnnotation, genStructValue);
        assert v.getValue() instanceof List<?>;
        List<?> list = (List<?>) v.getValue();
        for (Object known : list) {
            // Each entry in the annotation value is a struct to generate.
            assert known instanceof AnnotationValue;
            assert ((AnnotationValue) known).getValue() instanceof AnnotationMirror;
            AnnotationMirror knownStr = ((AnnotationMirror) ((AnnotationValue) known).getValue());
            // C struct name.
            String strName = (String) getAttribute(knownStr, structName).getValue();
            // C struct members.
            List<?> memberNamesList = (List<?>) getAttribute(knownStr, memberNames).getValue();
            // native to java types.
            List<?> typesList = (List<?>) getAttribute(knownStr, types).getValue();
            String className = processStruct(strName, memberNamesList, typesList);
            structs.add(className);
        }
    }
    String source = generateStructCollector(structs);
    commit(null, STRUCTS_CLASS, source);
    done = true;
    return false;
}
Also used : AnnotationMirror(javax.lang.model.element.AnnotationMirror) VariableElement(javax.lang.model.element.VariableElement) TypeElement(javax.lang.model.element.TypeElement) ExecutableElement(javax.lang.model.element.ExecutableElement) Element(javax.lang.model.element.Element) ArrayList(java.util.ArrayList) AnnotationValue(javax.lang.model.element.AnnotationValue) ArrayList(java.util.ArrayList) List(java.util.List) JavaFileObject(javax.tools.JavaFileObject)

Example 97 with AnnotationValue

use of javax.lang.model.element.AnnotationValue in project graal by oracle.

the class NodeParser method parseChildren.

private List<NodeChildData> parseChildren(NodeData node, final List<TypeElement> typeHierarchy, List<? extends Element> elements) {
    Map<String, TypeMirror> castNodeTypes = new HashMap<>();
    for (ExecutableElement method : ElementFilter.methodsIn(elements)) {
        AnnotationMirror mirror = findAnnotationMirror(method, types.CreateCast);
        if (mirror != null) {
            List<String> children = (getAnnotationValueList(String.class, mirror, "value"));
            if (children != null) {
                for (String child : children) {
                    castNodeTypes.put(child, method.getReturnType());
                }
            }
        }
    }
    List<NodeChildData> executedFieldChildren = new ArrayList<>();
    for (VariableElement field : ElementFilter.fieldsIn(elements)) {
        if (field.getModifiers().contains(Modifier.STATIC)) {
            continue;
        }
        AnnotationMirror executed = findAnnotationMirror(field.getAnnotationMirrors(), types.Executed);
        if (executed != null) {
            TypeMirror type = field.asType();
            String name = field.getSimpleName().toString();
            Cardinality cardinality = Cardinality.ONE;
            if (type.getKind() == TypeKind.ARRAY) {
                cardinality = Cardinality.MANY;
            }
            AnnotationValue executedWith = getAnnotationValue(executed, "with");
            NodeChildData child = new NodeChildData(field, executed, name, type, type, field, cardinality, executedWith, null, null);
            executedFieldChildren.add(child);
            if (field.getModifiers().contains(Modifier.PRIVATE)) {
                child.addError("Field annotated with @%s must be visible for the generated subclass to execute.", types.Executed.asElement().getSimpleName().toString());
            }
            if (cardinality == Cardinality.ONE) {
                if (ElementUtils.findAnnotationMirror(field, types.Node_Child) == null) {
                    child.addError("Field annotated with @%s must also be annotated with @%s.", types.Executed.asElement().getSimpleName().toString(), types.Node_Child.asElement().getSimpleName().toString());
                }
            } else {
                assert cardinality == Cardinality.MANY;
                if (ElementUtils.findAnnotationMirror(field, types.Node_Children) == null) {
                    child.addError("Field annotated with @%s must also be annotated with @%s.", types.Executed.asElement().getSimpleName().toString(), types.Node_Children.asElement().getSimpleName().toString());
                }
            }
        }
    }
    NodeChildData many = null;
    Set<String> names = new HashSet<>();
    for (NodeChildData child : executedFieldChildren) {
        if (child.needsGeneratedField()) {
            throw new AssertionError("Should not need generated field.");
        }
        if (names.contains(child.getName())) {
            child.addError("Field annotated with @%s has duplicate name '%s'. " + "Executed children must have unique names.", types.Executed.asElement().getSimpleName().toString(), child.getName());
        } else if (many != null) {
            child.addError("Field annotated with @%s is hidden by executed field '%s'. " + "Executed child fields with multiple children hide all following executed child declarations. " + "Reorder or remove this executed child declaration.", types.Executed.asElement().getSimpleName().toString(), many.getName());
        } else if (child.getCardinality().isMany()) {
            many = child;
        }
        names.add(child.getName());
    }
    List<NodeChildData> nodeChildren = new ArrayList<>();
    List<TypeElement> typeHierarchyReversed = new ArrayList<>(typeHierarchy);
    Collections.reverse(typeHierarchyReversed);
    for (TypeElement type : typeHierarchyReversed) {
        AnnotationMirror nodeChildrenMirror = findAnnotationMirror(type, types.NodeChildren);
        TypeMirror nodeClassType = type.getSuperclass();
        if (nodeClassType.getKind() == TypeKind.NONE || !isAssignable(nodeClassType, types.Node)) {
            nodeClassType = null;
        }
        List<AnnotationMirror> children = collectAnnotations(nodeChildrenMirror, "value", type, types.NodeChild);
        int index = 0;
        for (AnnotationMirror childMirror : children) {
            String name = getAnnotationValue(String.class, childMirror, "value");
            if (name.equals("")) {
                name = "child" + index;
            }
            Cardinality cardinality = Cardinality.ONE;
            TypeMirror childNodeType = inheritType(childMirror, "type", nodeClassType);
            if (childNodeType.getKind() == TypeKind.ARRAY) {
                cardinality = Cardinality.MANY;
            }
            TypeMirror originalChildType = childNodeType;
            TypeMirror castNodeType = castNodeTypes.get(name);
            if (castNodeType != null) {
                childNodeType = castNodeType;
            }
            Element getter = findGetter(elements, name, childNodeType);
            AnnotationValue executeWith = getAnnotationValue(childMirror, "executeWith");
            String create = null;
            boolean implicit = (boolean) unboxAnnotationValue(getAnnotationValue(childMirror, "implicit"));
            boolean implicitCreateSpecified = getAnnotationValue(childMirror, "implicitCreate", false) != null;
            if (implicit || implicitCreateSpecified) {
                create = (String) unboxAnnotationValue(getAnnotationValue(childMirror, "implicitCreate"));
            }
            String uncached = null;
            boolean allowUncached = (boolean) unboxAnnotationValue(getAnnotationValue(childMirror, "allowUncached"));
            boolean uncachedSpecified = getAnnotationValue(childMirror, "uncached", false) != null;
            if (allowUncached || uncachedSpecified) {
                uncached = (String) unboxAnnotationValue(getAnnotationValue(childMirror, "uncached"));
            }
            NodeChildData nodeChild = new NodeChildData(type, childMirror, name, childNodeType, originalChildType, getter, cardinality, executeWith, create, uncached);
            if (implicitCreateSpecified && implicit) {
                nodeChild.addError("The attributes 'implicit' and 'implicitCreate' are mutually exclusive. Remove one of the attributes to resolve this.");
            }
            if (uncachedSpecified && allowUncached) {
                nodeChild.addError("The attributes 'allowUncached' and 'uncached' are mutually exclusive. Remove one of the attributes to resolve this.");
            }
            nodeChildren.add(nodeChild);
            if (nodeChild.getNodeType() == null) {
                nodeChild.addError("No valid node type could be resolved.");
            }
            if (nodeChild.hasErrors()) {
                continue;
            }
            index++;
        }
    }
    if (!nodeChildren.isEmpty() && !executedFieldChildren.isEmpty()) {
        node.addError("The use of @%s and @%s at the same time is not supported.", types.NodeChild.asElement().getSimpleName().toString(), types.Executed.asElement().getSimpleName().toString());
        return executedFieldChildren;
    } else if (!executedFieldChildren.isEmpty()) {
        return executedFieldChildren;
    } else {
        List<NodeChildData> filteredChildren = new ArrayList<>();
        Set<String> encounteredNames = new HashSet<>();
        for (int i = nodeChildren.size() - 1; i >= 0; i--) {
            NodeChildData child = nodeChildren.get(i);
            if (!encounteredNames.contains(child.getName())) {
                filteredChildren.add(0, child);
                encounteredNames.add(child.getName());
            }
        }
        return filteredChildren;
    }
}
Also used : Set(java.util.Set) LinkedHashSet(java.util.LinkedHashSet) HashSet(java.util.HashSet) LinkedHashMap(java.util.LinkedHashMap) HashMap(java.util.HashMap) CodeExecutableElement(com.oracle.truffle.dsl.processor.java.model.CodeExecutableElement) ExecutableElement(javax.lang.model.element.ExecutableElement) TypeElement(javax.lang.model.element.TypeElement) GeneratedElement(com.oracle.truffle.dsl.processor.java.model.GeneratedElement) CodeExecutableElement(com.oracle.truffle.dsl.processor.java.model.CodeExecutableElement) Element(javax.lang.model.element.Element) VariableElement(javax.lang.model.element.VariableElement) CodeVariableElement(com.oracle.truffle.dsl.processor.java.model.CodeVariableElement) CodeTypeElement(com.oracle.truffle.dsl.processor.java.model.CodeTypeElement) ExecutableElement(javax.lang.model.element.ExecutableElement) ArrayList(java.util.ArrayList) VariableElement(javax.lang.model.element.VariableElement) CodeVariableElement(com.oracle.truffle.dsl.processor.java.model.CodeVariableElement) ElementUtils.fromTypeMirror(com.oracle.truffle.dsl.processor.java.ElementUtils.fromTypeMirror) CodeTypeMirror(com.oracle.truffle.dsl.processor.java.model.CodeTypeMirror) ArrayCodeTypeMirror(com.oracle.truffle.dsl.processor.java.model.CodeTypeMirror.ArrayCodeTypeMirror) TypeMirror(javax.lang.model.type.TypeMirror) ArrayList(java.util.ArrayList) ElementUtils.getAnnotationValueList(com.oracle.truffle.dsl.processor.java.ElementUtils.getAnnotationValueList) List(java.util.List) LinkedHashSet(java.util.LinkedHashSet) HashSet(java.util.HashSet) NodeChildData(com.oracle.truffle.dsl.processor.model.NodeChildData) Cardinality(com.oracle.truffle.dsl.processor.model.NodeChildData.Cardinality) TypeElement(javax.lang.model.element.TypeElement) CodeTypeElement(com.oracle.truffle.dsl.processor.java.model.CodeTypeElement) ElementUtils.findAnnotationMirror(com.oracle.truffle.dsl.processor.java.ElementUtils.findAnnotationMirror) AnnotationMirror(javax.lang.model.element.AnnotationMirror) AnnotationValue(javax.lang.model.element.AnnotationValue) ElementUtils.getAnnotationValue(com.oracle.truffle.dsl.processor.java.ElementUtils.getAnnotationValue) ElementUtils.unboxAnnotationValue(com.oracle.truffle.dsl.processor.java.ElementUtils.unboxAnnotationValue) ElementUtils.resolveAnnotationValue(com.oracle.truffle.dsl.processor.java.ElementUtils.resolveAnnotationValue)

Example 98 with AnnotationValue

use of javax.lang.model.element.AnnotationValue in project graal by oracle.

the class NodeParser method initializeReplaces.

private static void initializeReplaces(NodeData node) {
    for (SpecializationData specialization : node.getSpecializations()) {
        Set<SpecializationData> resolvedSpecializations = specialization.getReplaces();
        Set<String> includeNames = specialization.getReplacesNames();
        for (String includeName : includeNames) {
            // TODO reduce complexity of this lookup.
            List<SpecializationData> foundSpecializations = lookupSpecialization(node, includeName);
            AnnotationValue value = getAnnotationValue(specialization.getMarkerAnnotation(), "replaces");
            if (foundSpecializations.isEmpty()) {
                specialization.addError(value, "The referenced specialization '%s' could not be found.", includeName);
            } else {
                resolvedSpecializations.addAll(foundSpecializations);
                for (SpecializationData foundSpecialization : foundSpecializations) {
                    if (foundSpecialization.compareTo(specialization) > 0) {
                        specialization.addError(value, "The replaced specialization '%s' must be declared before the replacing specialization.", includeName);
                    }
                }
            }
        }
    }
}
Also used : SpecializationData(com.oracle.truffle.dsl.processor.model.SpecializationData) AnnotationValue(javax.lang.model.element.AnnotationValue) ElementUtils.getAnnotationValue(com.oracle.truffle.dsl.processor.java.ElementUtils.getAnnotationValue) ElementUtils.unboxAnnotationValue(com.oracle.truffle.dsl.processor.java.ElementUtils.unboxAnnotationValue) ElementUtils.resolveAnnotationValue(com.oracle.truffle.dsl.processor.java.ElementUtils.resolveAnnotationValue)

Example 99 with AnnotationValue

use of javax.lang.model.element.AnnotationValue in project graal by oracle.

the class NodeParser method parseCached.

private void parseCached(CacheExpression cache, SpecializationData specialization, DSLExpressionResolver originalResolver, Parameter parameter) {
    DSLExpressionResolver resolver = originalResolver;
    AnnotationMirror cachedAnnotation = cache.getMessageAnnotation();
    AnnotationValue adopt = null;
    if (!cache.hasErrors()) {
        adopt = getAnnotationValue(cachedAnnotation, "adopt", false);
        AnnotationMirror cached = findAnnotationMirror(cache.getParameter().getVariableElement(), types.Cached);
        cache.setDimensions(getAnnotationValue(Integer.class, cached, "dimensions"));
        boolean disabledAdopt = adopt != null && Boolean.FALSE.equals(adopt.getValue());
        if (parameter.getType().getKind() == TypeKind.ARRAY && (disabledAdopt || !isSubtype(((ArrayType) parameter.getType()).getComponentType(), types.NodeInterface))) {
            if (cache.getDimensions() == -1) {
                cache.addWarning("The cached dimensions attribute must be specified for array types.");
            }
        } else {
            if (!disabledAdopt && cache.getDimensions() != -1) {
                cache.addError("The dimensions attribute has no affect for the type %s.", getSimpleName(parameter.getType()));
            }
        }
    }
    List<String> expressionParameters = getAnnotationValueList(String.class, cachedAnnotation, "parameters");
    String initializer = getAnnotationValue(String.class, cachedAnnotation, "value");
    String uncached = getAnnotationValue(String.class, cachedAnnotation, "uncached");
    String parameters = String.join(", ", expressionParameters);
    initializer = initializer.replace("$parameters", parameters);
    uncached = uncached.replace("$parameters", parameters);
    if (ElementUtils.isAssignable(parameter.getType(), types.Library) && !ElementUtils.typeEquals(parameter.getType(), types.Library)) {
        cache.addError("The use of @%s is not supported for libraries. Use @%s instead.", types.Cached.asElement().getSimpleName().toString(), types.CachedLibrary.asElement().getSimpleName().toString());
    } else if (NodeCodeGenerator.isSpecializedNode(parameter.getType())) {
        // if it is a node try to parse with the node parser to find out whether we
        // should may use the generated create and getUncached methods.
        List<CodeExecutableElement> executables = parseNodeFactoryMethods(parameter.getType());
        if (executables != null) {
            resolver = resolver.copy(executables);
        }
    }
    if (!cache.hasErrors()) {
        cache.setDefaultExpression(parseCachedExpression(resolver, cache, parameter.getType(), initializer));
    }
    boolean requireUncached = specialization.getNode().isGenerateUncached() || mode == ParseMode.EXPORTED_MESSAGE;
    if (cache.hasErrors()) {
        // error sync point
        return;
    }
    boolean uncachedSpecified = getAnnotationValue(cachedAnnotation, "uncached", false) != null;
    if (requireUncached) {
        boolean allowUncached = getAnnotationValue(Boolean.class, cachedAnnotation, "allowUncached");
        if (uncachedSpecified && allowUncached) {
            cache.addError("The attributes 'allowUncached' and 'uncached' are mutually exclusive. Remove one of the attributes to resolve this.");
        } else if (allowUncached) {
            cache.setUncachedExpression(cache.getDefaultExpression());
        } else {
            if (!uncachedSpecified && cache.getDefaultExpression() != null && !cache.getDefaultExpression().mayAllocate()) {
                cache.setUncachedExpression(cache.getDefaultExpression());
            } else {
                cache.setUncachedExpression(parseCachedExpression(resolver, cache, parameter.getType(), uncached));
                if (!uncachedSpecified && cache.hasErrors()) {
                    cache.setUncachedExpressionError(cache.getMessages().iterator().next());
                    cache.getMessages().clear();
                }
            }
        }
    }
    if (requireUncached && cache.getUncachedExpression() == null && cache.getDefaultExpression() != null) {
        if (specialization.isTrivialExpression(cache.getDefaultExpression())) {
            cache.setUncachedExpression(cache.getDefaultExpression());
        }
    }
    if (adopt != null) {
        TypeMirror type = parameter.getType();
        if (type == null || !ElementUtils.isAssignable(type, types.NodeInterface) && !(type.getKind() == TypeKind.ARRAY && isAssignable(((ArrayType) type).getComponentType(), types.NodeInterface))) {
            cache.addError("Type '%s' is neither a NodeInterface type, nor an array of NodeInterface types and therefore it can not be adopted. Remove the adopt attribute to resolve this.", Objects.toString(type));
        }
    }
    cache.setAdopt(getAnnotationValue(Boolean.class, cachedAnnotation, "adopt", true));
}
Also used : ArrayType(javax.lang.model.type.ArrayType) ElementUtils.findAnnotationMirror(com.oracle.truffle.dsl.processor.java.ElementUtils.findAnnotationMirror) AnnotationMirror(javax.lang.model.element.AnnotationMirror) ElementUtils.fromTypeMirror(com.oracle.truffle.dsl.processor.java.ElementUtils.fromTypeMirror) CodeTypeMirror(com.oracle.truffle.dsl.processor.java.model.CodeTypeMirror) ArrayCodeTypeMirror(com.oracle.truffle.dsl.processor.java.model.CodeTypeMirror.ArrayCodeTypeMirror) TypeMirror(javax.lang.model.type.TypeMirror) AnnotationValue(javax.lang.model.element.AnnotationValue) ElementUtils.getAnnotationValue(com.oracle.truffle.dsl.processor.java.ElementUtils.getAnnotationValue) ElementUtils.unboxAnnotationValue(com.oracle.truffle.dsl.processor.java.ElementUtils.unboxAnnotationValue) ElementUtils.resolveAnnotationValue(com.oracle.truffle.dsl.processor.java.ElementUtils.resolveAnnotationValue) ArrayList(java.util.ArrayList) ElementUtils.getAnnotationValueList(com.oracle.truffle.dsl.processor.java.ElementUtils.getAnnotationValueList) List(java.util.List) DSLExpressionResolver(com.oracle.truffle.dsl.processor.expression.DSLExpressionResolver) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean)

Example 100 with AnnotationValue

use of javax.lang.model.element.AnnotationValue in project graal by oracle.

the class NodeParser method initializeOrder.

private static void initializeOrder(NodeData node) {
    List<SpecializationData> specializations = node.getSpecializations();
    Collections.sort(specializations);
    for (SpecializationData specialization : specializations) {
        String searchName = specialization.getInsertBeforeName();
        if (searchName == null || specialization.getMethod() == null) {
            continue;
        }
        List<SpecializationData> found = lookupSpecialization(node, searchName);
        if (found.isEmpty() || found.get(0).getMethod() == null) {
            AnnotationValue value = getAnnotationValue(specialization.getMarkerAnnotation(), "insertBefore");
            specialization.addError(value, "The referenced specialization '%s' could not be found.", searchName);
            continue;
        }
        SpecializationData first = found.iterator().next();
        ExecutableElement currentMethod = specialization.getMethod();
        ExecutableElement insertBeforeMethod = first.getMethod();
        TypeMirror currentEnclosedType = currentMethod.getEnclosingElement().asType();
        TypeMirror insertBeforeEnclosedType = insertBeforeMethod.getEnclosingElement().asType();
        if (typeEquals(currentEnclosedType, insertBeforeEnclosedType) || !isSubtype(currentEnclosedType, insertBeforeEnclosedType)) {
            AnnotationValue value = getAnnotationValue(specialization.getMarkerAnnotation(), "insertBefore");
            specialization.addError(value, "Specializations can only be inserted before specializations in superclasses.", searchName);
            continue;
        }
        specialization.setInsertBefore(first);
    }
    for (int i = 0; i < specializations.size(); i++) {
        SpecializationData specialization = specializations.get(i);
        SpecializationData insertBefore = specialization.getInsertBefore();
        if (insertBefore != null) {
            int insertIndex = specializations.indexOf(insertBefore);
            if (insertIndex < i) {
                specializations.remove(i);
                specializations.add(insertIndex, specialization);
            }
        }
    }
    for (int i = 0; i < specializations.size(); i++) {
        specializations.get(i).setIndex(i);
    }
}
Also used : ElementUtils.fromTypeMirror(com.oracle.truffle.dsl.processor.java.ElementUtils.fromTypeMirror) CodeTypeMirror(com.oracle.truffle.dsl.processor.java.model.CodeTypeMirror) ArrayCodeTypeMirror(com.oracle.truffle.dsl.processor.java.model.CodeTypeMirror.ArrayCodeTypeMirror) TypeMirror(javax.lang.model.type.TypeMirror) CodeExecutableElement(com.oracle.truffle.dsl.processor.java.model.CodeExecutableElement) ExecutableElement(javax.lang.model.element.ExecutableElement) SpecializationData(com.oracle.truffle.dsl.processor.model.SpecializationData) AnnotationValue(javax.lang.model.element.AnnotationValue) ElementUtils.getAnnotationValue(com.oracle.truffle.dsl.processor.java.ElementUtils.getAnnotationValue) ElementUtils.unboxAnnotationValue(com.oracle.truffle.dsl.processor.java.ElementUtils.unboxAnnotationValue) ElementUtils.resolveAnnotationValue(com.oracle.truffle.dsl.processor.java.ElementUtils.resolveAnnotationValue)

Aggregations

AnnotationValue (javax.lang.model.element.AnnotationValue)182 AnnotationMirror (javax.lang.model.element.AnnotationMirror)81 TypeElement (javax.lang.model.element.TypeElement)62 ArrayList (java.util.ArrayList)54 ExecutableElement (javax.lang.model.element.ExecutableElement)53 TypeMirror (javax.lang.model.type.TypeMirror)48 List (java.util.List)45 Test (org.junit.Test)30 DeclaredType (javax.lang.model.type.DeclaredType)27 Map (java.util.Map)20 HashSet (java.util.HashSet)19 HashMap (java.util.HashMap)18 VariableElement (javax.lang.model.element.VariableElement)15 Element (javax.lang.model.element.Element)14 ElementUtils.getAnnotationValue (com.oracle.truffle.dsl.processor.java.ElementUtils.getAnnotationValue)10 ElementUtils.fromTypeMirror (com.oracle.truffle.dsl.processor.java.ElementUtils.fromTypeMirror)9 CodeExecutableElement (com.oracle.truffle.dsl.processor.java.model.CodeExecutableElement)8 ElementUtils.resolveAnnotationValue (com.oracle.truffle.dsl.processor.java.ElementUtils.resolveAnnotationValue)7 ElementUtils.unboxAnnotationValue (com.oracle.truffle.dsl.processor.java.ElementUtils.unboxAnnotationValue)7 ArrayCodeTypeMirror (com.oracle.truffle.dsl.processor.java.model.CodeTypeMirror.ArrayCodeTypeMirror)7