use of org.codehaus.groovy.ast.MethodNode in project groovy-core by groovy.
the class StaticTypeCheckingVisitor method convertClosureTypeToSAMType.
/**
* This method will convert a closure type to the appropriate SAM type, which will be used
* to infer return type generics.
*
* @param closureType the inferred type of a closure (Closure<ClosureReturnType>)
* @param samType the type into which the closure is coerced into
* @return same SAM type, but completed with information from the closure node
*/
private static ClassNode convertClosureTypeToSAMType(final Expression expression, final ClassNode closureType, final ClassNode samType, final Map<String, GenericsType> placeholders) {
if (!samType.isUsingGenerics())
return samType;
// use the generics information from the Closure to further specify the type
MethodNode sam = findSAM(samType);
if (closureType.isUsingGenerics() && sam != null) {
//correct SAM type for generics
//sam = applyGenericsContext(placeholders, sam);
// the return type of the SAM method exactly corresponds to the inferred return type
ClassNode samReturnType = sam.getReturnType();
ClassNode closureReturnType = expression.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
if (closureReturnType != null && closureReturnType.isUsingGenerics()) {
ClassNode unwrapped = closureReturnType.getGenericsTypes()[0].getType();
extractGenericsConnections(placeholders, unwrapped, samReturnType);
} else if (samReturnType.isGenericsPlaceHolder()) {
placeholders.put(samReturnType.getGenericsTypes()[0].getName(), closureType.getGenericsTypes()[0]);
}
// now repeat the same for each parameter given in the ClosureExpression
if (expression instanceof ClosureExpression) {
List<ClassNode[]> genericsToConnect = new LinkedList<ClassNode[]>();
Parameter[] closureParams = ((ClosureExpression) expression).getParameters();
ClassNode[] closureParamTypes = extractTypesFromParameters(closureParams);
if (expression.getNodeMetaData(StaticTypesMarker.CLOSURE_ARGUMENTS) != null) {
closureParamTypes = expression.getNodeMetaData(StaticTypesMarker.CLOSURE_ARGUMENTS);
}
final Parameter[] parameters = sam.getParameters();
for (int i = 0; i < parameters.length; i++) {
final Parameter parameter = parameters[i];
if (parameter.getOriginType().isUsingGenerics() && closureParamTypes.length > i) {
genericsToConnect.add(new ClassNode[] { closureParamTypes[i], parameter.getOriginType() });
}
}
for (ClassNode[] classNodes : genericsToConnect) {
ClassNode found = classNodes[0];
ClassNode expected = classNodes[1];
if (!isAssignableTo(found, expected)) {
// probably facing a type mismatch
continue;
}
ClassNode generifiedType = GenericsUtils.parameterizeType(found, expected);
while (expected.isArray()) {
expected = expected.getComponentType();
generifiedType = generifiedType.getComponentType();
}
if (expected.isGenericsPlaceHolder()) {
placeholders.put(expected.getGenericsTypes()[0].getName(), new GenericsType(generifiedType));
} else {
GenericsType[] expectedGenericsTypes = expected.getGenericsTypes();
GenericsType[] foundGenericsTypes = generifiedType.getGenericsTypes();
for (int i = 0; i < expectedGenericsTypes.length; i++) {
final GenericsType type = expectedGenericsTypes[i];
if (type.isPlaceholder()) {
String name = type.getName();
placeholders.put(name, foundGenericsTypes[i]);
}
}
}
}
}
}
ClassNode result = applyGenericsContext(placeholders, samType.redirect());
return result;
}
use of org.codehaus.groovy.ast.MethodNode in project groovy-core by groovy.
the class StaticTypeCheckingVisitor method checkReturnType.
protected ClassNode checkReturnType(final ReturnStatement statement) {
Expression expression = statement.getExpression();
ClassNode type = getType(expression);
if (typeCheckingContext.getEnclosingClosure() != null) {
return type;
}
MethodNode enclosingMethod = typeCheckingContext.getEnclosingMethod();
if (enclosingMethod != null && typeCheckingContext.getEnclosingClosure() == null) {
if (!enclosingMethod.isVoidMethod() && !type.equals(void_WRAPPER_TYPE) && !type.equals(VOID_TYPE) && !checkCompatibleAssignmentTypes(enclosingMethod.getReturnType(), type, null, false) && !(isNullConstant(expression))) {
if (!extension.handleIncompatibleReturnType(statement, type)) {
addStaticTypeError("Cannot return value of type " + type.toString(false) + " on method returning type " + enclosingMethod.getReturnType().toString(false), expression);
}
} else if (!enclosingMethod.isVoidMethod()) {
ClassNode previousType = getInferredReturnType(enclosingMethod);
ClassNode inferred = previousType == null ? type : lowestUpperBound(type, previousType);
if (implementsInterfaceOrIsSubclassOf(inferred, enclosingMethod.getReturnType())) {
if (missesGenericsTypes(inferred)) {
DeclarationExpression virtualDecl = new DeclarationExpression(new VariableExpression("{target}", enclosingMethod.getReturnType()), Token.newSymbol(EQUAL, -1, -1), new VariableExpression("{source}", type));
virtualDecl.setSourcePosition(statement);
virtualDecl.visit(this);
ClassNode newlyInferred = (ClassNode) virtualDecl.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
if (!missesGenericsTypes(newlyInferred))
type = newlyInferred;
}
return type;
} else {
return enclosingMethod.getReturnType();
}
}
}
return type;
}
use of org.codehaus.groovy.ast.MethodNode in project groovy-core by groovy.
the class MethodCallExpressionTransformer method tryTransformIsToCompareIdentity.
/**
* Identifies a method call expression on {@link DefaultGroovyMethods#is(Object, Object)} and if recognized, transforms it into a {@link CompareIdentityExpression}.
* @param call a method call to be transformed
* @return null if the method call is not DGM#is, or {@link CompareIdentityExpression}
*/
private static Expression tryTransformIsToCompareIdentity(MethodCallExpression call) {
MethodNode methodTarget = call.getMethodTarget();
if (methodTarget instanceof ExtensionMethodNode && "is".equals(methodTarget.getName()) && methodTarget.getParameters().length == 1) {
methodTarget = ((ExtensionMethodNode) methodTarget).getExtensionMethodNode();
ClassNode owner = methodTarget.getDeclaringClass();
if (DGM_CLASSNODE.equals(owner)) {
Expression args = call.getArguments();
if (args instanceof ArgumentListExpression) {
ArgumentListExpression arguments = (ArgumentListExpression) args;
List<Expression> exprs = arguments.getExpressions();
if (exprs.size() == 1) {
CompareIdentityExpression cid = new CompareIdentityExpression(call.getObjectExpression(), exprs.get(0));
cid.setSourcePosition(call);
return cid;
}
}
}
}
return null;
}
use of org.codehaus.groovy.ast.MethodNode in project groovy-core by groovy.
the class StaticMethodCallExpressionTransformer method transformStaticMethodCallExpression.
Expression transformStaticMethodCallExpression(final StaticMethodCallExpression orig) {
MethodNode target = (MethodNode) orig.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET);
if (target != null) {
MethodCallExpression call = new MethodCallExpression(new ClassExpression(orig.getOwnerType()), orig.getMethod(), orig.getArguments());
call.setMethodTarget(target);
call.setSourcePosition(orig);
call.copyNodeMetaData(orig);
return transformer.transform(call);
}
return transformer.superTransform(orig);
}
use of org.codehaus.groovy.ast.MethodNode in project groovy-core by groovy.
the class StaticTypeCheckingVisitor method visitClosureExpression.
@Override
public void visitClosureExpression(final ClosureExpression expression) {
boolean oldStaticContext = typeCheckingContext.isInStaticContext;
typeCheckingContext.isInStaticContext = false;
// collect every variable expression used in the loop body
final Map<VariableExpression, ClassNode> varOrigType = new HashMap<VariableExpression, ClassNode>();
Statement code = expression.getCode();
code.visit(new VariableExpressionTypeMemoizer(varOrigType));
Map<VariableExpression, List<ClassNode>> oldTracker = pushAssignmentTracking();
// first, collect closure shared variables and reinitialize types
SharedVariableCollector collector = new SharedVariableCollector(getSourceUnit());
collector.visitClosureExpression(expression);
Set<VariableExpression> closureSharedExpressions = collector.getClosureSharedExpressions();
Map<VariableExpression, ListHashMap> typesBeforeVisit = null;
if (!closureSharedExpressions.isEmpty()) {
typesBeforeVisit = new HashMap<VariableExpression, ListHashMap>();
saveVariableExpressionMetadata(closureSharedExpressions, typesBeforeVisit);
}
// perform visit
typeCheckingContext.pushEnclosingClosureExpression(expression);
DelegationMetadata dmd = getDelegationMetadata(expression);
if (dmd == null) {
typeCheckingContext.delegationMetadata = new DelegationMetadata(typeCheckingContext.getEnclosingClassNode(), Closure.OWNER_FIRST, typeCheckingContext.delegationMetadata);
} else {
typeCheckingContext.delegationMetadata = new DelegationMetadata(dmd.getType(), dmd.getStrategy(), typeCheckingContext.delegationMetadata);
}
super.visitClosureExpression(expression);
typeCheckingContext.delegationMetadata = typeCheckingContext.delegationMetadata.getParent();
MethodNode node = new MethodNode("dummy", 0, ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, code);
returnAdder.visitMethod(node);
TypeCheckingContext.EnclosingClosure enclosingClosure = typeCheckingContext.getEnclosingClosure();
if (!enclosingClosure.getReturnTypes().isEmpty()) {
ClassNode returnType = lowestUpperBound(enclosingClosure.getReturnTypes());
storeInferredReturnType(expression, returnType);
ClassNode inferredType = wrapClosureType(returnType);
storeType(enclosingClosure.getClosureExpression(), inferredType);
}
typeCheckingContext.popEnclosingClosure();
boolean typeChanged = isSecondPassNeededForControlStructure(varOrigType, oldTracker);
if (typeChanged)
visitClosureExpression(expression);
// restore original metadata
restoreVariableExpressionMetadata(typesBeforeVisit);
typeCheckingContext.isInStaticContext = oldStaticContext;
Parameter[] parameters = expression.getParameters();
if (parameters != null) {
for (Parameter parameter : parameters) {
typeCheckingContext.controlStructureVariables.remove(parameter);
}
}
}
Aggregations