/* * Copyright 2009-2010 MBTE Sweden AB. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.mbte.groovypp.compiler.transformers; import groovy.lang.TypePolicy; import org.codehaus.groovy.ast.*; import org.codehaus.groovy.ast.expr.*; import org.codehaus.groovy.util.FastArray; import org.codehaus.groovy.classgen.BytecodeHelper; import org.mbte.groovypp.compiler.*; import org.mbte.groovypp.compiler.bytecode.BytecodeExpr; import org.mbte.groovypp.compiler.bytecode.InnerThisBytecodeExpr; import org.mbte.groovypp.compiler.bytecode.PropertyUtil; import org.mbte.groovypp.compiler.bytecode.ResolvedMethodBytecodeExpr; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import java.util.*; /** * Cast processing rules: * a) as operator always go via asType method * b) both numerical types always goes via primitive types * c) if we cast statically to lower type we keep upper (except if upper NullType) * d) otherwise we do direct cast * e) primitive types goes via boxing and Number */ public class CastExpressionTransformer extends ExprTransformer<CastExpression> { public BytecodeExpr transform(CastExpression cast, CompilerTransformer compiler) { if (cast.getExpression() instanceof TernaryExpression) { return compiler.cast(cast.getExpression(), cast.getType()); } if (cast.getExpression() instanceof ClassExpression) { ClassExpression exp = (ClassExpression) cast.getExpression(); ConstructorCallExpression newCall = new ConstructorCallExpression(exp.getType(), new ArgumentListExpression()); newCall.setSourcePosition(exp); return compiler.cast(newCall, cast.getType()); } if (cast.getExpression() instanceof ListExpressionTransformer.UntransformedListExpr) { final CastExpression newExp = new CastExpression(cast.getType(), ((ListExpressionTransformer.UntransformedListExpr) cast.getExpression()).exp); newExp.setSourcePosition(cast); cast = newExp; } if (cast.getExpression() instanceof MapExpressionTransformer.UntransformedMapExpr) { final CastExpression newExp = new CastExpression(cast.getType(), ((MapExpressionTransformer.UntransformedMapExpr) cast.getExpression()).exp); newExp.setSourcePosition(cast); cast = newExp; } if (cast.getExpression() instanceof TernaryExpressionTransformer.UntransformedTernaryExpr) { final TernaryExpression original = ((TernaryExpressionTransformer.UntransformedTernaryExpr) cast.getExpression()).exp; if (original instanceof ElvisOperatorExpression) { final CastExpression newTrue = new CastExpression(cast.getType(), original.getTrueExpression()); newTrue.setSourcePosition(original.getTrueExpression()); final CastExpression newFalse = new CastExpression(cast.getType(), original.getFalseExpression()); newFalse.setSourcePosition(original.getFalseExpression()); ElvisOperatorExpression newTernary = new ElvisOperatorExpression(newTrue, newFalse); newTernary.setSourcePosition(original); return (BytecodeExpr) compiler.transformToGround(newTernary); } else { final CastExpression newTrue = new CastExpression(cast.getType(), original.getTrueExpression()); newTrue.setSourcePosition(original.getTrueExpression()); final CastExpression newFalse = new CastExpression(cast.getType(), original.getFalseExpression()); newFalse.setSourcePosition(original.getFalseExpression()); TernaryExpression newTernary = new TernaryExpression(original.getBooleanExpression(), newTrue, newFalse); newTernary.setSourcePosition(original); return (BytecodeExpr) compiler.transformToGround(newTernary); } } if (cast.getType().equals(ClassHelper.boolean_TYPE) || cast.getType().equals(ClassHelper.Boolean_TYPE)) { if (cast.getExpression() instanceof ListExpression) { return compiler.castToBoolean( new ListExpressionTransformer.TransformedListExpr( (ListExpression)cast.getExpression(), TypeUtil.ARRAY_LIST_TYPE, compiler, true), cast.getType()); } if (cast.getExpression() instanceof MapExpression) { return compiler.castToBoolean( new MapExpressionTransformer.TransformedMapExpr( (MapExpression)cast.getExpression(), TypeUtil.LINKED_HASH_MAP_TYPE, compiler), cast.getType()); } return compiler.castToBoolean((BytecodeExpr)compiler.transform(cast.getExpression()), cast.getType()); } if (cast.getExpression() instanceof ListExpression) { ListExpression listExpression = (ListExpression) cast.getExpression(); if (cast.getType().isArray()) { ClassNode componentType = cast.getType().getComponentType(); improveListTypes(listExpression, componentType); final ArrayExpression array = new ArrayExpression(componentType, listExpression.getExpressions(), null); array.setSourcePosition(listExpression); return (BytecodeExpr) compiler.transform(array); } if(cast.getType().implementsInterface(TypeUtil.ITERABLE) || cast.getType().equals(TypeUtil.ITERABLE)) { if(compiler.findConstructor(cast.getType(), ClassNode.EMPTY_ARRAY, null) != null){ ClassNode componentType = compiler.getCollectionType(cast.getType()); improveListTypes(listExpression, componentType); final List<Expression> list = listExpression.getExpressions(); for (int i = 0; i != list.size(); ++i) { list.set(i, compiler.transform(list.get(i))); } ClassNode collType = calcResultCollectionType(cast, componentType, compiler); return new ListExpressionTransformer.TransformedListExpr(listExpression, collType, compiler, false); } } if (!TypeUtil.isDirectlyAssignableFrom(cast.getType(), TypeUtil.ARRAY_LIST_TYPE)) { final ArgumentListExpression args = new ArgumentListExpression(listExpression.getExpressions()); if (cast.getType().redirect() instanceof InnerClassNode && (cast.getType().getModifiers() & ACC_STATIC) == 0) { args.getExpressions().add(0, VariableExpression.THIS_EXPRESSION); } final ConstructorCallExpression constr = new ConstructorCallExpression(cast.getType(), args); constr.setSourcePosition(cast); return (BytecodeExpr) compiler.transform(constr); } else { // Assignable from ArrayList but not Iterable ClassNode componentType = ClassHelper.OBJECT_TYPE; improveListTypes(listExpression, componentType); final List<Expression> list = listExpression.getExpressions(); for (int i = 0; i != list.size(); ++i) { list.set(i, compiler.transform(list.get(i))); } return new ListExpressionTransformer.TransformedListExpr(listExpression, TypeUtil.ARRAY_LIST_TYPE, compiler, true); } } if (cast.getExpression() instanceof MapExpression) { MapExpression mapExpression = (MapExpression) cast.getExpression(); if (cast.getType().implementsInterface(ClassHelper.MAP_TYPE)) { if(compiler.findConstructor(cast.getType(), ClassNode.EMPTY_ARRAY, null) != null){ ClassNode keyType = compiler.getMapKeyType(cast.getType()); ClassNode valueType = compiler.getMapValueType(cast.getType()); improveMapTypes(mapExpression, keyType, valueType); ClassNode mapType = calcResultMapType(cast, keyType, valueType, compiler); return new MapExpressionTransformer.TransformedMapExpr(mapExpression, mapType, compiler); } } boolean isMap = cast.getType().implementsInterface(ClassHelper.MAP_TYPE) || cast.getType().equals(ClassHelper.MAP_TYPE); if (!isMap && !TypeUtil.isAssignableFrom(cast.getType(), TypeUtil.LINKED_HASH_MAP_TYPE)) { return buildClassFromMap (mapExpression, cast.getType(), compiler); } else { ClassNode mapType = TypeUtil.LINKED_HASH_MAP_TYPE; if (isMap) { final GenericsType[] generics = TypeUtil.getSubstitutedType(ClassHelper.MAP_TYPE, ClassHelper.MAP_TYPE, cast.getType()).getGenericsTypes(); ClassNode keyType = ClassHelper.OBJECT_TYPE; ClassNode valueType = ClassHelper.OBJECT_TYPE; if (generics != null) { keyType = compiler.getCollOrMapGenericType(generics[0].getType()); valueType = compiler.getCollOrMapGenericType(generics[1].getType()); improveMapTypes(mapExpression, keyType, valueType); } mapType = calcResultMapType(cast, keyType, valueType, compiler); } final MapExpressionTransformer.TransformedMapExpr inner = new MapExpressionTransformer.TransformedMapExpr((MapExpression) cast.getExpression(), mapType, compiler); return standardCast(cast, compiler, inner); } } BytecodeExpr expr = (BytecodeExpr) compiler.transform(cast.getExpression()); if (expr.getType().implementsInterface(TypeUtil.TCLOSURE)) { List<MethodNode> one = ClosureUtil.isOneMethodAbstract(cast.getType()); MethodNode doCall = ClosureUtil.isMatch(one, (ClosureClassNode) expr.getType(), cast.getType(), compiler); if (doCall != null) { return expr; } } if (cast.getType().equals(ClassHelper.STRING_TYPE)) { if (cast.getExpression() instanceof ListExpression) { return compiler.castToString( new ListExpressionTransformer.TransformedListExpr( (ListExpression)cast.getExpression(), TypeUtil.ARRAY_LIST_TYPE, compiler, true)); } return compiler.castToString((BytecodeExpr)compiler.transform(cast.getExpression())); } if (expr.getType().implementsInterface(TypeUtil.TTHIS)) { ClassNode castType = cast.getType(); final ClassNode exprType = expr.getType().getOuterClass(); if (TypeUtil.isDirectlyAssignableFrom(castType, exprType)) return expr; ClassNode outer = exprType.getOuterClass(); while(!TypeUtil.isDirectlyAssignableFrom(castType, outer)) { outer = outer.getOuterClass(); } return new InnerThisBytecodeExpr(expr, outer, compiler, exprType); } if (!TypeUtil.isDirectlyAssignableFrom(cast.getType(), expr.getType())) { MethodNode unboxing = TypeUtil.getReferenceUnboxingMethod(expr.getType()); if (unboxing != null) { ResolvedMethodBytecodeExpr mce = ResolvedMethodBytecodeExpr.create(cast, unboxing, expr, new ArgumentListExpression(), compiler); if (TypeUtil.isDirectlyAssignableFrom(ClassHelper.getUnwrapper(cast.getType()), ClassHelper.getUnwrapper(mce.getType()))) return mce; } } return standardCast(cast, compiler, expr); } private BytecodeExpr buildClassFromMap(MapExpression exp, ClassNode type, final CompilerTransformer compiler) { final List<MapEntryExpression> list = exp.getMapEntryExpressions(); Expression superArgs = null; for (int i = 0; i != list.size(); ++i) { final MapEntryExpression me = list.get(i); Expression key = me.getKeyExpression(); if (!(key instanceof ConstantExpression) || !(((ConstantExpression)key).getValue() instanceof String)) { compiler.addError( "<key> must have java.lang.String type", key); return null; } } ClassNode objType = null; if ((type.getModifiers() & ACC_ABSTRACT) != 0 || type.isInterface()) { objType = createNewType(type, exp, compiler); } List<MapEntryExpression> methods = new LinkedList<MapEntryExpression>(); final List<MapEntryExpression> fields = new LinkedList<MapEntryExpression>(); final List<MapEntryExpression> props = new LinkedList<MapEntryExpression>(); for (int i = 0; i != list.size(); ++i) { final MapEntryExpression me = list.get(i); String keyName = (String) ((ConstantExpression)me.getKeyExpression()).getValue(); Expression value = me.getValueExpression(); if (keyName.equals("super")) { if (objType == null) objType = createNewType(type, exp, compiler); superArgs = value; continue; } final Object prop = PropertyUtil.resolveSetProperty(type, keyName, TypeUtil.NULL_TYPE, compiler, true); if (prop != null) { ClassNode propType; ClassNode propDeclClass; if (prop instanceof MethodNode) { propType = ((MethodNode)prop).getParameters()[0].getType(); propDeclClass = ((MethodNode)prop).getDeclaringClass(); } else if (prop instanceof FieldNode) { propType = ((FieldNode)prop).getType(); propDeclClass = ((FieldNode)prop).getDeclaringClass(); } else { propDeclClass = ((PropertyNode)prop).getDeclaringClass(); propType = ((PropertyNode)prop).getType(); } propType = TypeUtil.getSubstitutedType(propType, propDeclClass, type); final CastExpression cast = new CastExpression(propType, value); cast.setSourcePosition(value); final BytecodeExpr obj = new BytecodeExpr(type, type) { protected void compile(MethodVisitor mv) { mv.visitInsn(DUP); } }; final BytecodeExpr setter = PropertyUtil.createSetProperty(me, compiler, keyName, obj, (BytecodeExpr) compiler.transform(cast), prop); props.add(new MapEntryExpression(me.getKeyExpression(), setter)); } else { if (objType == null) objType = createNewType(type, exp, compiler); if (value instanceof ClosureExpression) { ClosureExpression ce = (ClosureExpression) value; methods.add (me); ClosureUtil.addFields(ce, objType, compiler); } else { fields.add(me); } } } if (objType != null) { if (superArgs != null) { if (superArgs instanceof ListExpression) { superArgs = new ArgumentListExpression(((ListExpression)superArgs).getExpressions()); } else superArgs = new ArgumentListExpression(superArgs); } else superArgs = new ArgumentListExpression(); final Expression finalSA = compiler.transform(superArgs); final MethodNode constructor = ConstructorCallExpressionTransformer.findConstructorWithClosureCoercion(objType.getSuperClass(), compiler.exprToTypeArray(superArgs), compiler, objType); if (constructor == null) { compiler.addError ("Cannot find super constructor " + objType.getSuperClass().getName(), exp); return null; } final List<Expression> ll = ((ArgumentListExpression) superArgs).getExpressions(); final Parameter[] parameters = constructor.getParameters(); if (parameters.length > 0 && parameters[parameters.length-1].getType().isArray()) { for (int i = 0; i != parameters.length-1; ++i) ll.set(i, compiler.cast(ll.get(i), parameters[i].getType())); final ClassNode last = parameters[parameters.length - 1].getType().getComponentType(); for (int i = parameters.length-1; i != ll.size(); ++i) ll.set(i, compiler.cast(ll.get(i), last)); } else { for (int i = 0; i != ll.size(); ++i) ll.set(i, compiler.cast(ll.get(i), parameters[i].getType())); } for (MapEntryExpression me : fields) { final String keyName = (String) ((ConstantExpression) me.getKeyExpression()).getValue(); final Expression init = compiler.transform(me.getValueExpression()); me.setValueExpression(init); FieldNode fieldNode = objType.addField(keyName, 0, init.getType(), null); fieldNode.addAnnotation(new AnnotationNode(TypeUtil.NO_EXTERNAL_INITIALIZATION)); } for (MapEntryExpression me : methods) { final String keyName = (String) ((ConstantExpression) me.getKeyExpression()).getValue(); closureToMethod(type, compiler, objType, keyName, (ClosureExpression)me.getValueExpression()); } return new BytecodeExpr(exp, objType) { protected void compile(MethodVisitor mv) { ClassNode type = getType(); if (compiler.policy == TypePolicy.STATIC && !compiler.context.isOuterClassInstanceUsed(type) && type.getDeclaredField("this$0") != null /* todo: remove this check */) { type.removeField("this$0"); } final Parameter[] constrParams = ClosureUtil.createClosureConstructorParams(type, compiler); ClosureUtil.createClosureConstructor(type, constrParams, finalSA, compiler); ClosureUtil.instantiateClass(type, compiler, constrParams, finalSA, mv); for (MapEntryExpression me : fields) { final String keyName = (String) ((ConstantExpression) me.getKeyExpression()).getValue(); final FieldNode fieldNode = type.getDeclaredField(keyName); mv.visitInsn(DUP); ((BytecodeExpr)me.getValueExpression()).visit(mv); mv.visitFieldInsn(PUTFIELD, BytecodeHelper.getClassInternalName(type), fieldNode.getName(), BytecodeHelper.getTypeDescription(fieldNode.getType())); } for (MapEntryExpression me : props) { ((BytecodeExpr)me.getValueExpression()).visit(mv); mv.visitInsn(POP); } } }; } else { final ConstructorCallExpression constr = new ConstructorCallExpression(type, new ArgumentListExpression()); constr.setSourcePosition(exp); final BytecodeExpr transformendConstr = (BytecodeExpr) compiler.transform(constr); return new BytecodeExpr(exp, type) { protected void compile(MethodVisitor mv) { transformendConstr.visit(mv); for (MapEntryExpression me : props) { ((BytecodeExpr)me.getValueExpression()).visit(mv); mv.visitInsn(POP); } } }; } } private void closureToMethod(ClassNode type, CompilerTransformer compiler, ClassNode objType, String keyName, ClosureExpression ce) { if (ce.getParameters() != null && ce.getParameters().length == 0) { final VariableScope scope = ce.getVariableScope(); ce = new ClosureExpression(new Parameter[1], ce.getCode()); ce.setVariableScope(scope); ce.getParameters()[0] = new Parameter(ClassHelper.OBJECT_TYPE, "it", new ConstantExpression(null)); } final ClosureMethodNode _doCallMethod = new ClosureMethodNode( keyName, Opcodes.ACC_PUBLIC, ClassHelper.OBJECT_TYPE, ce.getParameters() == null ? Parameter.EMPTY_ARRAY : ce.getParameters(), ce.getCode()); objType.addMethod(_doCallMethod); _doCallMethod.createDependentMethods(objType); Object methods = ClassNodeCache.getMethods(type, keyName); if (methods != null) { if (methods instanceof MethodNode) { MethodNode baseMethod = (MethodNode) methods; _doCallMethod.checkOverride(baseMethod, type); } else { FastArray methodsArr = (FastArray) methods; int methodCount = methodsArr.size(); for (int j = 0; j != methodCount; ++j) { MethodNode baseMethod = (MethodNode) methodsArr.get(j); _doCallMethod.checkOverride(baseMethod, type); } } } ClassNodeCache.clearCache (_doCallMethod.getDeclaringClass()); StaticMethodBytecode.replaceMethodCode(compiler.su, compiler.context, _doCallMethod, compiler.compileStack, compiler.debug == -1 ? -1 : compiler.debug+1, compiler.policy, _doCallMethod.getDeclaringClass().getName()); } private ClassNode createNewType(ClassNode type, Expression exp, CompilerTransformer compiler) { ClassNode objType; if ((type.getModifiers() & Opcodes.ACC_FINAL) != 0) { compiler.addError("You are not allowed to overwrite the final class '" + type.getName() + "'", exp); return null; } objType = new InnerClassNode(compiler.classNode, compiler.getNextClosureName(), ACC_PUBLIC|ACC_FINAL|ACC_SYNTHETIC, ClassHelper.OBJECT_TYPE); if (type.isInterface()) { objType.setInterfaces(new ClassNode [] {type} ); } else { objType.setSuperClass(type); } objType.setModule(compiler.classNode.getModule()); if (!compiler.methodNode.isStatic() || compiler.classNode.getName().endsWith("$TraitImpl")) objType.addField("this$0", ACC_PUBLIC|ACC_FINAL|ACC_SYNTHETIC, !compiler.methodNode.isStatic() ? compiler.classNode : compiler.methodNode.getParameters()[0].getType(), null); return objType; } private ClassNode calcResultMapType(CastExpression exp, ClassNode keyType, ClassNode valueType, CompilerTransformer compiler) { ClassNode collType = exp.getType(); if ((collType.getModifiers() & ACC_ABSTRACT) != 0) { if (collType.equals(ClassHelper.MAP_TYPE)) { if (collType.getGenericsTypes() != null) { collType = ClassHelper.make ("java.util.LinkedHashMap"); collType.setRedirect(TypeUtil.LINKED_HASH_MAP_TYPE); collType.setGenericsTypes(new GenericsType[]{new GenericsType(keyType), new GenericsType(valueType)}); } else collType = TypeUtil.LINKED_HASH_MAP_TYPE; } else { if (collType.equals(TypeUtil.SORTED_MAP_TYPE)) { if (collType.getGenericsTypes() != null) { collType = ClassHelper.make ("java.util.TreeMap"); collType.setRedirect(TypeUtil.LINKED_HASH_SET_TYPE); collType.setGenericsTypes(new GenericsType[]{new GenericsType(keyType), new GenericsType(valueType)}); } else collType = TypeUtil.TREE_MAP_TYPE; } else { compiler.addError ("Cannot instantiate map as instance of abstract type " + collType.getName(), exp); return null; } } } return collType; } private ClassNode calcResultCollectionType(CastExpression exp, ClassNode componentType, CompilerTransformer compiler) { ClassNode collType = exp.getType(); if ((collType.getModifiers() & ACC_ABSTRACT) != 0) { if (collType.equals(ClassHelper.LIST_TYPE) || collType.equals(TypeUtil.COLLECTION_TYPE) || collType.equals(TypeUtil.ITERABLE)) { if (collType.getGenericsTypes() != null) { collType = ClassHelper.make ("java.util.ArrayList"); collType.setRedirect(TypeUtil.ARRAY_LIST_TYPE); collType.setGenericsTypes(new GenericsType[]{new GenericsType(componentType)}); } else collType = TypeUtil.ARRAY_LIST_TYPE; } else { if (collType.equals(TypeUtil.SET_TYPE)) { if (collType.getGenericsTypes() != null) { collType = ClassHelper.make ("java.util.LinkedHashSet"); collType.setRedirect(TypeUtil.LINKED_HASH_SET_TYPE); collType.setGenericsTypes(new GenericsType[]{new GenericsType(componentType)}); } else collType = TypeUtil.LINKED_HASH_SET_TYPE; } else { if (collType.equals(TypeUtil.SORTED_SET_TYPE)) { if (collType.getGenericsTypes() != null) { collType = ClassHelper.make ("java.util.TreeSet"); collType.setRedirect(TypeUtil.TREE_SET_TYPE); collType.setGenericsTypes(new GenericsType[]{new GenericsType(componentType)}); } else collType = TypeUtil.TREE_SET_TYPE; } else { if (collType.equals(TypeUtil.QUEUE_TYPE)) { if (collType.getGenericsTypes() != null) { collType = ClassHelper.make ("java.util.LinkedList"); collType.setRedirect(TypeUtil.LINKED_LIST_TYPE); collType.setGenericsTypes(new GenericsType[]{new GenericsType(componentType)}); } else collType = TypeUtil.LINKED_LIST_TYPE; } else { compiler.addError ("Cannot instantiate list as instance of abstract type " + collType.getName(), exp); return null; } } } } } return collType; } private BytecodeExpr standardCast(final CastExpression exp, CompilerTransformer compiler, final BytecodeExpr expr) { if (exp.isCoerce()) { // a) final ClassNode type = TypeUtil.wrapSafely(exp.getType()); Expression arg = ClassExpressionTransformer.newExpr(exp, type); return new AsType(exp, type, expr, (BytecodeExpr) arg); } else { if (TypeUtil.isNumericalType(exp.getType()) && TypeUtil.isNumericalType(expr.getType())) { // b) return new Cast(exp.getType(), expr); } else { ClassNode rtype = TypeUtil.wrapSafely(expr.getType()); if (rtype.equals(TypeUtil.NULL_TYPE) && ClassHelper.isPrimitiveType(exp.getType())) { return new BytecodeExpr(exp, exp.getType()) { protected void compile(MethodVisitor mv) { if (exp.getType() == ClassHelper.double_TYPE) { mv.visitInsn(DCONST_0); } else if (exp.getType() == ClassHelper.float_TYPE) { mv.visitInsn(FCONST_0); } else if (exp.getType() == ClassHelper.long_TYPE) { mv.visitInsn(LCONST_0); } else mv.visitInsn(ICONST_0); } }; } if (TypeUtil.isDirectlyAssignableFrom(exp.getType(), rtype)) { // c) final ClassNode castType = exp.getType(); if (castType.getGenericsTypes() == null && castType.redirect().getGenericsTypes() != null) { // Correect type arguments. final ClassNode mapped = TypeUtil.mapTypeFromSuper(castType.redirect(), castType.redirect(), rtype); if (mapped != null) { exp.setType(mapped); } } if (rtype.equals(exp.getType())) { expr.setType(exp.getType()); // important for correct generic signature return expr; } else { return new BytecodeExpr(expr, exp.getType()) { protected void compile(MethodVisitor mv) { expr.visit(mv); box(expr.getType(), mv); } }; } } else { // d if (!TypeUtil.isConvertibleFrom(exp.getType(), rtype)) { compiler.addError("Cannot convert " + PresentationUtil.getText(rtype) + " to " + PresentationUtil.getText(exp.getType()), exp); return null; } return new Cast(exp.getType(), expr); } } } } private void improveListTypes(ListExpression listExpression, ClassNode componentType) { List<Expression> list = listExpression.getExpressions(); int count = list.size(); for (int i = 0; i != count; ++i) { Expression el = list.get(i); CastExpression castExpression = new CastExpression(componentType, el); castExpression.setSourcePosition(el); list.set(i, castExpression); } } private void improveMapTypes(MapExpression mapExpression, ClassNode keyType, ClassNode valueType) { List<MapEntryExpression> list = mapExpression.getMapEntryExpressions(); int count = list.size(); for (int i = 0; i != count; ++i) { MapEntryExpression el = list.get(i); CastExpression castExpression; castExpression = new CastExpression(keyType, el.getKeyExpression()); castExpression.setSourcePosition(el.getKeyExpression()); el.setKeyExpression(castExpression); castExpression = new CastExpression(valueType, el.getValueExpression()); castExpression.setSourcePosition(el.getValueExpression()); el.setValueExpression(castExpression); } } private static class AsType extends BytecodeExpr { private final BytecodeExpr expr; private final BytecodeExpr arg1; public AsType(CastExpression exp, ClassNode type, BytecodeExpr expr, BytecodeExpr arg1) { super(exp, type); this.expr = expr; this.arg1 = arg1; } protected void compile(MethodVisitor mv) { expr.visit(mv); box(expr.getType(), mv); arg1.visit(mv); mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/ScriptBytecodeAdapter", "asType", "(Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;"); BytecodeExpr.checkCast(getType(), mv); } } public static class Cast extends BytecodeExpr { private final BytecodeExpr expr; public Cast(ClassNode type, BytecodeExpr expr) { super(expr, type); this.expr = expr; } protected void compile(MethodVisitor mv) { expr.visit(mv); box(expr.getType(), mv); cast(TypeUtil.wrapSafely(expr.getType()), TypeUtil.wrapSafely(getType()), mv); unbox(getType(), mv); } } }