use of org.codehaus.groovy.ast.expr.MethodReferenceExpression in project groovy by apache.
the class StaticTypesBinaryExpressionMultiTypeDispatcher method evaluateEqual.
@Override
public void evaluateEqual(final BinaryExpression expression, final boolean defineVariable) {
Expression leftExpression = expression.getLeftExpression();
if (!defineVariable) {
if (leftExpression instanceof PropertyExpression) {
PropertyExpression pexp = (PropertyExpression) leftExpression;
if (makeSetProperty(pexp.getObjectExpression(), pexp.getProperty(), expression.getRightExpression(), pexp.isSafe(), pexp.isSpreadSafe(), pexp.isImplicitThis(), pexp instanceof AttributeExpression)) {
return;
}
}
} else {
Expression rightExpression = expression.getRightExpression();
if (rightExpression instanceof LambdaExpression || rightExpression instanceof MethodReferenceExpression) {
rightExpression.putNodeMetaData(INFERRED_FUNCTIONAL_INTERFACE_TYPE, leftExpression.getNodeMetaData(INFERRED_TYPE));
}
}
// GROOVY-5620: spread-safe operator on LHS is not supported
if (leftExpression instanceof PropertyExpression && ((PropertyExpression) leftExpression).isSpreadSafe() && isAssignment(expression.getOperation().getType())) {
// rewrite it so that it can be statically compiled
transformSpreadOnLHS(expression);
return;
}
super.evaluateEqual(expression, defineVariable);
}
use of org.codehaus.groovy.ast.expr.MethodReferenceExpression in project groovy by apache.
the class StaticTypeCheckingVisitor method getResultType.
protected ClassNode getResultType(ClassNode left, final int op, final ClassNode right, final BinaryExpression expr) {
ClassNode leftRedirect = left.redirect();
ClassNode rightRedirect = right.redirect();
Expression leftExpression = expr.getLeftExpression();
Expression rightExpression = expr.getRightExpression();
if (op == EQUAL || op == ELVIS_EQUAL) {
if (rightRedirect.isDerivedFrom(CLOSURE_TYPE)) {
ClosureExpression closureExpression = null;
if (rightExpression instanceof ClosureExpression) {
closureExpression = (ClosureExpression) rightExpression;
} else if (rightExpression instanceof MethodReferenceExpression) {
closureExpression = rightExpression.getNodeMetaData(CONSTRUCTED_LAMBDA_EXPRESSION);
}
if (closureExpression != null) {
MethodNode abstractMethod = findSAM(left);
if (abstractMethod != null) {
return inferSAMTypeGenericsInAssignment(left, abstractMethod, right, closureExpression);
}
}
}
if (leftExpression instanceof VariableExpression) {
ClassNode initialType = getOriginalDeclarationType(leftExpression);
if (isPrimitiveType(rightRedirect) && initialType.isDerivedFrom(Number_TYPE)) {
return getWrapper(right);
}
if (isPrimitiveType(initialType) && rightRedirect.isDerivedFrom(Number_TYPE)) {
return getUnwrapper(right);
}
// as anything can be assigned to a String, Class or [Bb]oolean, return the left type instead
if (isWildcardLeftHandSide(initialType) && !isObjectType(initialType)) {
return initialType;
}
}
if (!isObjectType(leftRedirect)) {
if (rightExpression instanceof ListExpression) {
if (LIST_TYPE.equals(leftRedirect) || ITERABLE_TYPE.equals(leftRedirect) || Collection_TYPE.equals(leftRedirect) || ArrayList_TYPE.isDerivedFrom(leftRedirect)) {
// GROOVY-7128
return getLiteralResultType(left, right, ArrayList_TYPE);
}
if (SET_TYPE.equals(leftRedirect) || LinkedHashSet_TYPE.isDerivedFrom(leftRedirect)) {
// GROOVY-7128
return getLiteralResultType(left, right, LinkedHashSet_TYPE);
}
}
if (rightExpression instanceof MapExpression) {
if (MAP_TYPE.equals(leftRedirect) || LinkedHashMap_TYPE.isDerivedFrom(leftRedirect)) {
// GROOVY-7128, GROOVY-9844
return getLiteralResultType(left, right, LinkedHashMap_TYPE);
}
}
}
return right;
}
if (isBoolIntrinsicOp(op)) {
return boolean_TYPE;
}
if (op == FIND_REGEX) {
return Matcher_TYPE;
}
if (isArrayOp(op)) {
// using getPNR() to ignore generics at this point
// and a different binary expression not to pollute the AST
BinaryExpression newExpr = binX(leftExpression, expr.getOperation(), rightExpression);
newExpr.setSourcePosition(expr);
MethodNode method = findMethodOrFail(newExpr, left.getPlainNodeReference(), "getAt", right.getPlainNodeReference());
if (method != null && implementsInterfaceOrIsSubclassOf(right, RANGE_TYPE)) {
return inferReturnTypeGenerics(left, method, rightExpression);
}
return method != null ? inferComponentType(left, right) : null;
}
// the left operand is determining the result of the operation
// for primitives and their wrapper we use a fixed table here
String operationName = getOperationName(op);
ClassNode mathResultType = getMathResultType(op, leftRedirect, rightRedirect, operationName);
if (mathResultType != null) {
return mathResultType;
}
// GROOVY-9006: compare to null for types that overload equals
if ("equals".equals(operationName) && (left == UNKNOWN_PARAMETER_TYPE || right == UNKNOWN_PARAMETER_TYPE)) {
return boolean_TYPE;
}
// GROOVY-5890: do not mix Class<Type> with Type
if (leftExpression instanceof ClassExpression) {
left = CLASS_Type.getPlainNodeReference();
}
MethodNode method = findMethodOrFail(expr, left, operationName, right);
if (method != null) {
storeTargetMethod(expr, method);
typeCheckMethodsWithGenericsOrFail(left, new ClassNode[] { right }, method, expr);
if (isAssignment(op))
return left;
if (isCompareToBoolean(op))
return boolean_TYPE;
if (op == COMPARE_TO)
return int_TYPE;
return inferReturnTypeGenerics(left, method, args(rightExpression));
}
return null;
}
use of org.codehaus.groovy.ast.expr.MethodReferenceExpression in project groovy by apache.
the class StaticTypeCheckingVisitor method inferMethodReferenceType.
private void inferMethodReferenceType(final ClassNode receiver, final ArgumentListExpression argumentList, final MethodNode selectedMethod) {
if (receiver == null)
return;
if (argumentList == null)
return;
if (selectedMethod == null)
return;
List<Expression> argumentExpressions = argumentList.getExpressions();
if (argumentExpressions == null || argumentExpressions.stream().noneMatch(e -> e instanceof MethodReferenceExpression)) {
return;
}
Parameter[] parameters = selectedMethod.getParameters();
final int nthParameter = parameters.length - 1;
List<Integer> methodReferencePositions = new LinkedList<>();
List<Expression> newArgumentExpressions = new LinkedList<>();
for (int i = 0, n = argumentExpressions.size(); i < n; i += 1) {
Expression argumentExpression = argumentExpressions.get(i);
if (!(argumentExpression instanceof MethodReferenceExpression)) {
newArgumentExpressions.add(argumentExpression);
} else {
// GROOVY-10336
Parameter param = parameters[Math.min(i, nthParameter)];
ClassNode paramType = param.getType();
if (i >= nthParameter && paramType.isArray())
paramType = paramType.getComponentType();
if (!isFunctionalInterface(paramType.redirect())) {
addError("The argument is a method reference, but the parameter type is not a functional interface", argumentExpression);
newArgumentExpressions.add(argumentExpression);
} else {
methodReferencePositions.add(i);
newArgumentExpressions.add(constructLambdaExpressionForMethodReference(paramType));
}
}
}
// GROOVY-10269
if (methodReferencePositions.isEmpty())
return;
visitMethodCallArguments(receiver, args(newArgumentExpressions), true, selectedMethod);
for (int index : methodReferencePositions) {
Expression lambdaExpression = newArgumentExpressions.get(index);
Expression methodReferenceExpression = argumentExpressions.get(index);
methodReferenceExpression.putNodeMetaData(CLOSURE_ARGUMENTS, lambdaExpression.getNodeMetaData(CLOSURE_ARGUMENTS));
}
}
use of org.codehaus.groovy.ast.expr.MethodReferenceExpression in project groovy by apache.
the class StaticTypeCheckingVisitor method visitMethodPointerExpression.
@Override
public void visitMethodPointerExpression(final MethodPointerExpression expression) {
super.visitMethodPointerExpression(expression);
Expression nameExpr = expression.getMethodName();
if (nameExpr instanceof ConstantExpression && isStringType(getType(nameExpr))) {
String nameText = nameExpr.getText();
if ("new".equals(nameText)) {
ClassNode receiverType = getType(expression.getExpression());
if (isClassClassNodeWrappingConcreteType(receiverType)) {
storeType(expression, wrapClosureType(receiverType));
}
return;
}
List<Receiver<String>> receivers = new ArrayList<>();
addReceivers(receivers, makeOwnerList(expression.getExpression()), false);
ClassNode receiverType = null;
List<MethodNode> candidates = EMPTY_METHODNODE_LIST;
for (Receiver<String> currentReceiver : receivers) {
receiverType = wrapTypeIfNecessary(currentReceiver.getType());
candidates = findMethodsWithGenerated(receiverType, nameText);
if (isBeingCompiled(receiverType))
candidates.addAll(GROOVY_OBJECT_TYPE.getMethods(nameText));
candidates.addAll(findDGMMethodsForClassNode(getSourceUnit().getClassLoader(), receiverType, nameText));
candidates = filterMethodsByVisibility(candidates, typeCheckingContext.getEnclosingClassNode());
if (!candidates.isEmpty()) {
break;
}
}
if (candidates.isEmpty()) {
candidates = extension.handleMissingMethod(getType(expression.getExpression()), nameText, null, null, null);
} else if (candidates.size() > 1) {
candidates = extension.handleAmbiguousMethods(candidates, expression);
}
if (!candidates.isEmpty()) {
Map<GenericsTypeName, GenericsType> gts = GenericsUtils.extractPlaceholders(receiverType);
candidates.stream().map(candidate -> applyGenericsContext(gts, candidate.getReturnType())).reduce(WideningCategories::lowestUpperBound).ifPresent(returnType -> {
storeType(expression, wrapClosureType(returnType));
});
expression.putNodeMetaData(MethodNode.class, candidates);
} else if (!(expression instanceof MethodReferenceExpression)) {
ClassNode type = wrapTypeIfNecessary(getType(expression.getExpression()));
if (isClassClassNodeWrappingConcreteType(type))
type = type.getGenericsTypes()[0].getType();
addStaticTypeError("Cannot find matching method " + prettyPrintTypeName(type) + "#" + nameText + ". Please check if the declared type is correct and if the method exists.", nameExpr);
}
}
}
use of org.codehaus.groovy.ast.expr.MethodReferenceExpression in project groovy by apache.
the class StaticTypesMethodReferenceExpressionWriter method writeMethodReferenceExpression.
@Override
public void writeMethodReferenceExpression(final MethodReferenceExpression methodReferenceExpression) {
ClassNode functionalInterfaceType = getFunctionalInterfaceType(methodReferenceExpression);
if (!ClassHelper.isFunctionalInterface(functionalInterfaceType)) {
// generate the default bytecode; most likely a method closure
super.writeMethodReferenceExpression(methodReferenceExpression);
return;
}
ClassNode redirect = functionalInterfaceType.redirect();
MethodNode abstractMethod = ClassHelper.findSAM(redirect);
String abstractMethodDesc = createMethodDescriptor(abstractMethod);
ClassNode classNode = controller.getClassNode();
Expression typeOrTargetRef = methodReferenceExpression.getExpression();
boolean isClassExpression = (typeOrTargetRef instanceof ClassExpression);
ClassNode typeOrTargetRefType = isClassExpression ? typeOrTargetRef.getType() : controller.getTypeChooser().resolveType(typeOrTargetRef, classNode);
ClassNode[] methodReferenceParamTypes = methodReferenceExpression.getNodeMetaData(StaticTypesMarker.CLOSURE_ARGUMENTS);
Parameter[] parametersWithExactType = createParametersWithExactType(abstractMethod, methodReferenceParamTypes);
String methodRefName = methodReferenceExpression.getMethodName().getText();
boolean isConstructorReference = isConstructorReference(methodRefName);
MethodNode methodRefMethod;
if (isConstructorReference) {
methodRefName = controller.getContext().getNextConstructorReferenceSyntheticMethodName(controller.getMethodNode());
methodRefMethod = addSyntheticMethodForConstructorReference(methodRefName, typeOrTargetRefType, parametersWithExactType);
} else {
// TODO: move the findMethodRefMethod and checking to StaticTypeCheckingVisitor
methodRefMethod = findMethodRefMethod(methodRefName, parametersWithExactType, typeOrTargetRef, typeOrTargetRefType);
}
validate(methodReferenceExpression, typeOrTargetRef, typeOrTargetRefType, methodRefName, parametersWithExactType, methodRefMethod);
if (isExtensionMethod(methodRefMethod)) {
ExtensionMethodNode extensionMethodNode = (ExtensionMethodNode) methodRefMethod;
methodRefMethod = extensionMethodNode.getExtensionMethodNode();
if (extensionMethodNode.isStaticExtension()) {
methodRefMethod = addSyntheticMethodForDGSM(methodRefMethod);
}
typeOrTargetRefType = methodRefMethod.getDeclaringClass();
Expression classExpression = classX(typeOrTargetRefType);
classExpression.setSourcePosition(typeOrTargetRef);
typeOrTargetRef = classExpression;
}
methodRefMethod.putNodeMetaData(ORIGINAL_PARAMETERS_WITH_EXACT_TYPE, parametersWithExactType);
if (!isClassExpression) {
if (isConstructorReference) {
// TODO: move the checking code to the parser
addFatalError("Constructor reference must be className::new", methodReferenceExpression);
} else if (methodRefMethod.isStatic()) {
ClassExpression classExpression = classX(typeOrTargetRefType);
classExpression.setSourcePosition(typeOrTargetRef);
typeOrTargetRef = classExpression;
isClassExpression = true;
} else {
typeOrTargetRef.visit(controller.getAcg());
}
}
controller.getMethodVisitor().visitInvokeDynamicInsn(abstractMethod.getName(), createAbstractMethodDesc(functionalInterfaceType, typeOrTargetRef), createBootstrapMethod(classNode.isInterface(), false), createBootstrapMethodArguments(abstractMethodDesc, methodRefMethod.isStatic() || isConstructorReference ? Opcodes.H_INVOKESTATIC : Opcodes.H_INVOKEVIRTUAL, isConstructorReference ? controller.getClassNode() : typeOrTargetRefType, methodRefMethod, false));
if (isClassExpression) {
controller.getOperandStack().push(redirect);
} else {
controller.getOperandStack().replace(redirect, 1);
}
}
Aggregations