Search in sources :

Example 36 with TypedReference

use of org.eclipse.ceylon.model.typechecker.model.TypedReference in project ceylon by eclipse.

the class ClassTransformer method generateInstantiatorDelegate.

private void generateInstantiatorDelegate(ClassDefinitionBuilder classBuilder, Type satisfiedType, Interface iface, Class klass, Constructor ctor, Type currentType, boolean includeBody) {
    Type typeMember = satisfiedType.getTypeMember(klass, klass.getType().getTypeArgumentList());
    if (ctor != null) {
        typeMember = ctor.appliedType(typeMember, Collections.<Type>emptyList());
    }
    java.util.List<TypeParameter> typeParameters = klass.getTypeParameters();
    java.util.List<Parameter> parameters = (ctor != null ? ctor.getParameterLists() : klass.getParameterLists()).get(0).getParameters();
    long flags = modifierTransformation().instantiatorBridgeFlags(includeBody);
    String instantiatorMethodName = naming.getInstantiatorMethodName(klass);
    for (Parameter param : parameters) {
        if (Strategy.hasDefaultParameterValueMethod(param) && !klass.isActual()) {
            final TypedReference typedParameter = typeMember.getTypedParameter(param);
            // If that method has a defaulted parameter,
            // we need to generate a default value method
            // which also delegates to the $impl
            final MethodDefinitionBuilder defaultValueDelegate = makeDelegateToCompanion(iface, typeMember, currentType, flags, typeParameters, producedTypeParameterBounds(typeMember, klass), typedParameter.getFullType(), Naming.getDefaultedParamMethodName(ctor != null ? ctor : klass, param), parameters.subList(0, parameters.indexOf(param)), param.getModel().getTypeErased(), null, param, includeBody);
            classBuilder.method(defaultValueDelegate);
        }
        if (Strategy.hasDefaultParameterOverload(param)) {
            final MethodDefinitionBuilder overload = makeDelegateToCompanion(iface, typeMember, currentType, flags, typeParameters, producedTypeParameterBounds(typeMember, klass), typeMember.getType(), instantiatorMethodName, parameters.subList(0, parameters.indexOf(param)), false, null, null, includeBody);
            classBuilder.method(overload);
        }
    }
    final MethodDefinitionBuilder overload = makeDelegateToCompanion(iface, typeMember, currentType, flags, typeParameters, producedTypeParameterBounds(typeMember, klass), typeMember.getType(), instantiatorMethodName, parameters, false, null, null, includeBody);
    classBuilder.method(overload);
}
Also used : Type(org.eclipse.ceylon.model.typechecker.model.Type) TypeParameter(org.eclipse.ceylon.model.typechecker.model.TypeParameter) TypedReference(org.eclipse.ceylon.model.typechecker.model.TypedReference) Parameter(org.eclipse.ceylon.model.typechecker.model.Parameter) TypeParameter(org.eclipse.ceylon.model.typechecker.model.TypeParameter)

Example 37 with TypedReference

use of org.eclipse.ceylon.model.typechecker.model.TypedReference in project ceylon by eclipse.

the class CallableBuilder method makeFunctionalInterfaceMethod.

public MethodDefinitionBuilder makeFunctionalInterfaceMethod() {
    FunctionOrValue methodOrValue = (FunctionOrValue) functionalInterfaceMethod.getDeclaration();
    MethodDefinitionBuilder callMethod = MethodDefinitionBuilder.method(gen, methodOrValue, 0);
    callMethod.isOverride(true);
    callMethod.modifiers(Flags.PUBLIC);
    Type returnType = functionalInterfaceMethod.getType();
    if (methodOrValue instanceof Value || !((Function) methodOrValue).isDeclaredVoid()) {
        int flags = CodegenUtil.isUnBoxed(methodOrValue) ? 0 : JT_NO_PRIMITIVES;
        callMethod.resultType(gen.makeJavaType(returnType, flags), null);
    }
    ListBuffer<JCExpression> args = new ListBuffer<>();
    // this depends on how we're declared to Java
    boolean turnedToRaw = gen.rawSupertype(functionalInterface, JT_EXTENDS | JT_CLASS_NEW);
    boolean variadic = false;
    if (methodOrValue instanceof Function) {
        int index = 0;
        java.util.List<Parameter> parameters = ((Function) methodOrValue).getFirstParameterList().getParameters();
        for (int i = 0; i < parameters.size(); i++) {
            Parameter param = parameters.get(i);
            Parameter targetParam = paramLists.getParameters().get(i);
            TypedReference typedParameter = functionalInterfaceMethod.getTypedParameter(param);
            ParameterDefinitionBuilder pdb = ParameterDefinitionBuilder.systemParameter(gen, param.getName());
            Type paramType = typedParameter.getType();
            if (param.isSequenced()) {
                paramType = gen.typeFact().getSequentialElementType(paramType);
                variadic = true;
            }
            // This is very special-casey, but is required and I haven't found more subtle
            if (turnedToRaw && gen.simplifyType(param.getType()).isTypeParameter()) {
                paramType = gen.typeFact().getObjectType();
            }
            long flags = Flags.FINAL;
            // that looks fishy, perhaps we need to call non-widening rules instead
            JCExpression javaType = gen.makeJavaType(paramType, paramType.isRaw() ? AbstractTransformer.JT_RAW : 0);
            if (param.isSequenced()) {
                flags |= Flags.VARARGS;
                javaType = gen.make().TypeArray(javaType);
            }
            pdb.type(new TransformedType(javaType));
            pdb.modifiers(flags);
            callMethod.parameter(pdb);
            JCExpression arg;
            if (param.isSequenced()) {
                arg = gen.javaVariadicToSequential(paramType, param);
            } else {
                arg = gen.makeUnquotedIdent(param.getName());
                Type argumentType = parameterTypes.get(index);
                if (gen.isOptional(paramType) && argumentType.isSubtypeOf(gen.typeFact().getObjectType()) && !targetParam.getModel().hasUncheckedNullType()) {
                    arg = gen.utilInvocation().checkNull(arg);
                }
                Type simpleParamType = gen.simplifyType(paramType);
                // make unboxed java strings pass for ceylon strings so we can box them
                boolean unboxedString = gen.isJavaStringExactly(simpleParamType);
                if (unboxedString)
                    simpleParamType = gen.typeFact().getStringType();
                BoxingStrategy boxingStrategy = BoxingStrategy.BOXED;
                // in rare cases we don't want boxes
                if (unboxedString && gen.isJavaStringExactly(argumentType))
                    boxingStrategy = BoxingStrategy.UNBOXED;
                arg = gen.expressionGen().applyErasureAndBoxing(arg, simpleParamType, !(CodegenUtil.isUnBoxed(param.getModel()) || unboxedString), boxingStrategy, argumentType);
            }
            args.append(arg);
            index++;
        }
    } else {
    // no-arg getter
    }
    String callMethodName;
    if (variadic)
        callMethodName = Naming.getCallableVariadicMethodName();
    else
        callMethodName = Naming.getCallableMethodName();
    JCExpression call = gen.make().Apply(null, gen.makeUnquotedIdent(callMethodName), args.toList());
    JCStatement body;
    if (methodOrValue instanceof Function && ((Function) methodOrValue).isDeclaredVoid())
        body = gen.make().Exec(call);
    else {
        Type callableReturnType = gen.getReturnTypeOfCallable(typeModel);
        Type simpleReturnType = gen.simplifyType(returnType);
        boolean unboxed = CodegenUtil.isUnBoxed(methodOrValue) || gen.isJavaStringExactly(simpleReturnType);
        if (unboxed) {
            call = gen.expressionGen().applyErasureAndBoxing(call, callableReturnType, true, BoxingStrategy.UNBOXED, returnType);
        } else if (callableReturnType.isNull()) {
            // if the callable returns null and the SAM does not, we need a cast
            call = gen.expressionGen().applyErasureAndBoxing(call, callableReturnType, true, BoxingStrategy.INDIFFERENT, returnType);
        }
        body = gen.make().Return(call);
    }
    callMethod.body(body);
    return callMethod;
}
Also used : TypedReference(org.eclipse.ceylon.model.typechecker.model.TypedReference) ListBuffer(org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer) JCStatement(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCStatement) Function(org.eclipse.ceylon.model.typechecker.model.Function) Type(org.eclipse.ceylon.model.typechecker.model.Type) JCExpression(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression) FunctionOrValue(org.eclipse.ceylon.model.typechecker.model.FunctionOrValue) Value(org.eclipse.ceylon.model.typechecker.model.Value) FieldValue(org.eclipse.ceylon.model.loader.model.FieldValue) Parameter(org.eclipse.ceylon.model.typechecker.model.Parameter) TypeParameter(org.eclipse.ceylon.model.typechecker.model.TypeParameter) JCTypeParameter(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCTypeParameter) BoxingStrategy(org.eclipse.ceylon.compiler.java.codegen.AbstractTransformer.BoxingStrategy) FunctionOrValue(org.eclipse.ceylon.model.typechecker.model.FunctionOrValue)

Example 38 with TypedReference

use of org.eclipse.ceylon.model.typechecker.model.TypedReference in project ceylon by eclipse.

the class ExpressionTransformer method transformAssignment.

private JCExpression transformAssignment(Node op, Tree.Term leftTerm, Tree.Term rightTerm) {
    // Remember and disable inStatement for RHS
    boolean tmpInStatement = inStatement;
    inStatement = false;
    // FIXME: can this be anything else than a Tree.MemberOrTypeExpression or Tree.ParameterizedExpression or Tree.IndexExpression?
    final JCExpression rhs;
    BoxingStrategy boxing;
    if (leftTerm instanceof Tree.MemberOrTypeExpression) {
        TypedDeclaration decl = (TypedDeclaration) ((Tree.MemberOrTypeExpression) leftTerm).getDeclaration();
        boxing = CodegenUtil.getBoxingStrategy(decl);
        if (decl instanceof Value) {
            Value val = (Value) decl;
            if (val.getSetter() != null && val.getSetter().getUnboxed() != null) {
                boxing = CodegenUtil.getBoxingStrategy(val.getSetter());
            }
        }
        Type targetType = tmpInStatement ? leftTerm.getTypeModel() : rightTerm.getTypeModel();
        // if we're dealing with widening do not trust the type of the declaration and get the real type
        if (CodegenUtil.hasUntrustedType(decl)) {
            TypedReference typedRef = (TypedReference) ((Tree.MemberOrTypeExpression) leftTerm).getTarget();
            TypedReference nonWideningTypedRef = nonWideningTypeDecl(typedRef);
            targetType = nonWideningType(typedRef, nonWideningTypedRef);
        }
        int flags = decl.hasUncheckedNullType() ? EXPR_TARGET_ACCEPTS_NULL : 0;
        flags |= leftTerm.getSmall() && !rightTerm.getSmall() ? EXPR_UNSAFE_PRIMITIVE_TYPECAST_OK : 0;
        if (decl.isMember() && useFieldInAssignment(op, null, decl) && !ModelUtil.isLocalToInitializer(decl) && useJavaBox(decl, ((TypedDeclaration) decl.getRefinedDeclaration()).getType())) {
            boxing = BoxingStrategy.JAVA;
            flags |= EXPR_HAS_NULL_CHECK_FENCE;
        }
        rhs = transformExpression(rightTerm, boxing, targetType, flags);
    } else if (leftTerm instanceof Tree.IndexExpression) {
        Tree.IndexExpression idx = (Tree.IndexExpression) leftTerm;
        Unit unit = op.getUnit();
        Type pt = idx.getPrimary().getTypeModel();
        boxing = (unit.isJavaPrimitiveArrayType(pt)) ? BoxingStrategy.UNBOXED : BoxingStrategy.BOXED;
        rhs = transformExpression(rightTerm, boxing, idx.getTypeModel(), 0);
    } else if (leftTerm instanceof Tree.ParameterizedExpression) {
        boxing = CodegenUtil.getBoxingStrategy(leftTerm);
        Tree.ParameterizedExpression paramExpr = (Tree.ParameterizedExpression) leftTerm;
        FunctionOrValue decl = (FunctionOrValue) ((Tree.MemberOrTypeExpression) paramExpr.getPrimary()).getDeclaration();
        CallableBuilder callableBuilder = CallableBuilder.anonymous(gen(), paramExpr, decl, (Tree.Expression) rightTerm, paramExpr.getParameterLists(), paramExpr.getPrimary().getTypeModel(), decl instanceof Function ? !((Function) decl).isDeferred() : false);
        rhs = callableBuilder.build();
    } else {
        return makeErroneous(leftTerm, "compiler bug: left term of type '" + leftTerm.getClass().getSimpleName() + "' is not yet supported");
    }
    if (tmpInStatement) {
        return makeAssignment(op, leftTerm, transformAssignmentLhs(op, leftTerm), rhs);
    } else {
        Type valueType = rightTerm.getTypeModel();
        if (isNull(valueType))
            valueType = leftTerm.getTypeModel();
        return transformAssignAndReturnOperation(op, leftTerm, boxing == BoxingStrategy.BOXED, leftTerm.getTypeModel(), valueType, new AssignAndReturnOperationFactory() {

            @Override
            public JCExpression getNewValue(JCExpression previousValue) {
                return rhs;
            }
        });
    }
}
Also used : TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) TypedReference(org.eclipse.ceylon.model.typechecker.model.TypedReference) Unit(org.eclipse.ceylon.model.typechecker.model.Unit) Function(org.eclipse.ceylon.model.typechecker.model.Function) UnionType(org.eclipse.ceylon.model.typechecker.model.UnionType) Type(org.eclipse.ceylon.model.typechecker.model.Type) JCExpression(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression) Value(org.eclipse.ceylon.model.typechecker.model.Value) FieldValue(org.eclipse.ceylon.model.loader.model.FieldValue) FunctionOrValue(org.eclipse.ceylon.model.typechecker.model.FunctionOrValue) JCTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree) Tree(org.eclipse.ceylon.compiler.typechecker.tree.Tree) FunctionOrValue(org.eclipse.ceylon.model.typechecker.model.FunctionOrValue)

Example 39 with TypedReference

use of org.eclipse.ceylon.model.typechecker.model.TypedReference in project ceylon by eclipse.

the class NamedArgumentInvocation method transformPrimary.

protected TransformedInvocationPrimary transformPrimary(JCExpression primaryExpr, String selector) {
    JCExpression transformedPrimary = instanceFieldName != null ? instanceFieldName.makeIdent() : primaryExpr;
    String transformedSelector = selector;
    if (getPrimaryDeclaration() instanceof Value) {
        if (transformedPrimary == null)
            transformedPrimary = gen.makeUnquotedIdent(selector);
        else
            transformedPrimary = gen.makeQualIdent(primaryExpr, selector);
        Type primaryType = ((Value) getPrimaryDeclaration()).getType();
        TypedReference samRef = gen.checkForFunctionalInterface(primaryType);
        if (samRef != null)
            transformedSelector = samRef.getDeclaration().getName();
        else
            transformedSelector = Naming.getCallableMethodName();
    } else if (getPrimaryDeclaration() instanceof Function && getPrimaryDeclaration().isParameter() && // This is fishy at best
    transformedPrimary == null) {
        // FIXME: there's a good chance this should be merged with the previous block
        transformedPrimary = gen.makeUnquotedIdent(selector);
        transformedSelector = Naming.getCallableMethodName();
    } else if (isCallableToFunctionalInterfaceBridge) {
        transformedSelector = Naming.getCallableMethodName();
    }
    return new TransformedInvocationPrimary(transformedPrimary, transformedSelector);
}
Also used : Function(org.eclipse.ceylon.model.typechecker.model.Function) Type(org.eclipse.ceylon.model.typechecker.model.Type) JCExpression(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression) TypedReference(org.eclipse.ceylon.model.typechecker.model.TypedReference) Value(org.eclipse.ceylon.model.typechecker.model.Value)

Example 40 with TypedReference

use of org.eclipse.ceylon.model.typechecker.model.TypedReference in project ceylon by eclipse.

the class AbstractTransformer method getRefinedDeclaration.

/*
     * We have several special cases here to find the best non-widening refinement in case of multiple inheritace:
     * 
     * - The first special case is for some decls like None.first, which inherits from ContainerWithFirstElement
     * twice: once with Nothing (erased to j.l.Object) and once with Element (a type param). Now, in order to not widen the
     * return type it can't be Nothing (j.l.Object), it must be Element (a type param that is not instantiated), because in Java
     * a type param refines j.l.Object but not the other way around.
     * - The second special case is when implementing an interface first with a non-erased type, then with an erased type. In this
     * case we want the refined decl to be the one with the non-erased type.
     * - The third special case is when we implement a declaration via multiple super types, without having any refining
     * declarations in those supertypes, simply by instantiating a common super type with different type parameters
     */
TypedReference getRefinedDeclaration(TypedReference typedReference, Type currentType) {
    TypedDeclaration decl = typedReference.getDeclaration();
    TypedDeclaration modelRefinedDecl = (TypedDeclaration) decl.getRefinedDeclaration();
    Type referenceQualifyingType = typedReference.getQualifyingType();
    boolean forMixinMethod = currentType != null && decl.getContainer() instanceof ClassOrInterface && referenceQualifyingType != null && !Decl.equal(referenceQualifyingType.getDeclaration(), currentType.getDeclaration());
    // quick exit
    if (Decl.equal(decl, modelRefinedDecl) && !forMixinMethod)
        return null;
    // modelRefinedDecl exists, but perhaps it's the toplevel refinement and not the one Java will look at
    if (!forMixinMethod)
        modelRefinedDecl = getFirstRefinedDeclaration(decl);
    TypeDeclaration qualifyingDeclaration = currentType.getDeclaration();
    if (qualifyingDeclaration instanceof ClassOrInterface) {
        // if both are returning unboxed void we're good
        if (Decl.isUnboxedVoid(decl) && Decl.isUnboxedVoid(modelRefinedDecl))
            return null;
        // only try to find better if we're erasing to Object and we're not returning a type param
        if (willEraseToObject(typedReference.getType()) || isWideningTypeArguments(decl.getType(), modelRefinedDecl.getType(), true) && !isTypeParameter(typedReference.getType())) {
            ClassOrInterface declaringType = (ClassOrInterface) qualifyingDeclaration;
            Set<TypedDeclaration> refinedMembers = getRefinedMembers(declaringType, decl.getName(), org.eclipse.ceylon.model.typechecker.model.ModelUtil.getSignature(decl), org.eclipse.ceylon.model.typechecker.model.ModelUtil.isVariadic(decl));
            // now we must select a different refined declaration if we refine it more than once
            if (refinedMembers.size() > (forMixinMethod ? 0 : 1)) {
                // first case
                for (TypedDeclaration refinedDecl : refinedMembers) {
                    // get the type reference to see if any eventual type param is instantiated in our inheritance of this type/method
                    TypedReference refinedTypedReference = getRefinedTypedReference(typedReference, refinedDecl);
                    // if it is not instantiated, that's the one we're looking for
                    if (isTypeParameter(refinedTypedReference.getType()))
                        return refinedTypedReference;
                }
                // second case
                for (TypedDeclaration refinedDecl : refinedMembers) {
                    // get the type reference to see if any eventual type param is instantiated in our inheritance of this type/method
                    TypedReference refinedTypedReference = getRefinedTypedReference(typedReference, refinedDecl);
                    // if we're not erasing this one to Object let's select it
                    if (!willEraseToObject(refinedTypedReference.getType()) && !isWideningTypeArguments(refinedDecl.getType(), modelRefinedDecl.getType(), true))
                        return refinedTypedReference;
                }
                // third case
                if (isTypeParameter(modelRefinedDecl.getType())) {
                    // it can happen that we have inherited a method twice from a single refined declaration
                    // via different supertype instantiations, without having ever refined them in supertypes
                    // so we try each super type to see if we already have a matching typed reference
                    // first super type
                    Type extendedType = declaringType.getExtendedType();
                    if (extendedType != null) {
                        TypedReference refinedTypedReference = getRefinedTypedReference(extendedType, modelRefinedDecl);
                        Type refinedType = refinedTypedReference.getType();
                        if (!isTypeParameter(refinedType) && !willEraseToObject(refinedType))
                            return refinedTypedReference;
                    }
                    // then satisfied interfaces
                    for (Type satisfiedType : declaringType.getSatisfiedTypes()) {
                        TypedReference refinedTypedReference = getRefinedTypedReference(satisfiedType, modelRefinedDecl);
                        Type refinedType = refinedTypedReference.getType();
                        if (!isTypeParameter(refinedType) && !willEraseToObject(refinedType))
                            return refinedTypedReference;
                    }
                }
            }
        }
        /*
             * Now there's another crazy case:
             * 
             * interface Top<out Element> {
             *  Top<Element> ret => nothing;
             * }
             * interface Left satisfies Top<Integer> {}
             * interface Right satisfies Top<String> {}
             * class Bottom() satisfies Left&Right {}
             * 
             * Where Bottom.ret does not exist and is typed as returning Integer&String which is Nothing, erased to Object,
             * and we look at what it refines and find only a single definition Top.ret typed as returning Integer&String (Nothing),
             * so we think there's no widening, but Java will only see Top<Integer>.ret from Left, and that's the one we want
             * to use for determining widening.
             * See https://github.com/ceylon/ceylon-compiler/issues/1765
             */
        Type firstInstantiation = isInheritedWithDifferentTypeArguments(modelRefinedDecl.getContainer(), currentType);
        if (firstInstantiation != null) {
            TypedReference firstInstantiationTypedReference = getRefinedTypedReference(firstInstantiation, modelRefinedDecl);
            Type firstInstantiationType = firstInstantiationTypedReference.getType();
            if (isWidening(decl.getType(), firstInstantiationType) || isWideningTypeArguments(decl.getType(), firstInstantiationType, true))
                return firstInstantiationTypedReference;
        }
    }
    return getRefinedTypedReference(typedReference, modelRefinedDecl);
}
Also used : TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) ClassOrInterface(org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) Type(org.eclipse.ceylon.model.typechecker.model.Type) ModelUtil.appliedType(org.eclipse.ceylon.model.typechecker.model.ModelUtil.appliedType) TypedReference(org.eclipse.ceylon.model.typechecker.model.TypedReference) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration)

Aggregations

TypedReference (org.eclipse.ceylon.model.typechecker.model.TypedReference)40 Type (org.eclipse.ceylon.model.typechecker.model.Type)35 ModelUtil.appliedType (org.eclipse.ceylon.model.typechecker.model.ModelUtil.appliedType)17 TypeParameter (org.eclipse.ceylon.model.typechecker.model.TypeParameter)17 FunctionOrValue (org.eclipse.ceylon.model.typechecker.model.FunctionOrValue)16 Function (org.eclipse.ceylon.model.typechecker.model.Function)15 Value (org.eclipse.ceylon.model.typechecker.model.Value)14 Parameter (org.eclipse.ceylon.model.typechecker.model.Parameter)12 Tree (org.eclipse.ceylon.compiler.typechecker.tree.Tree)11 AnalyzerUtil.getTupleType (org.eclipse.ceylon.compiler.typechecker.analyzer.AnalyzerUtil.getTupleType)10 AnalyzerUtil.spreadType (org.eclipse.ceylon.compiler.typechecker.analyzer.AnalyzerUtil.spreadType)10 ModelUtil.intersectionType (org.eclipse.ceylon.model.typechecker.model.ModelUtil.intersectionType)10 TypedDeclaration (org.eclipse.ceylon.model.typechecker.model.TypedDeclaration)10 JCExpression (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression)9 ModelUtil.genericFunctionType (org.eclipse.ceylon.model.typechecker.model.ModelUtil.genericFunctionType)8 ModelUtil.unionType (org.eclipse.ceylon.model.typechecker.model.ModelUtil.unionType)8 ParameterList (org.eclipse.ceylon.model.typechecker.model.ParameterList)8 TypeDeclaration (org.eclipse.ceylon.model.typechecker.model.TypeDeclaration)8 UnknownType (org.eclipse.ceylon.model.typechecker.model.UnknownType)8 ArrayList (java.util.ArrayList)7