Skip to content
Permalink
Browse files

Noop refactor and cleanpu related to method references so that the co…

…de can be shared among different frontends.

PiperOrigin-RevId: 248355934
  • Loading branch information...
rluble authored and Copybara-Service committed May 15, 2019
1 parent 4c09cc8 commit a66e3d0678ee51ad582cc983b6321d1dd023ed51
@@ -251,51 +251,6 @@ public static Method createStaticForwardingMethod(
true);
}

/**
* Creates a FunctionExpression described by {@code functionalMethodDescriptor} that forwards to
* {@code targetMethodDescriptor}.
*/
public static FunctionExpression createForwardingFunctionExpression(
SourcePosition sourcePosition,
TypeDescriptor expressionTypeDescriptor,
MethodDescriptor functionalMethodDescriptor,
Expression qualifier,
MethodDescriptor targetMethodDescriptor,
boolean isStaticDispatch) {

List<Variable> parameters =
createParameterVariables(functionalMethodDescriptor.getParameterTypeDescriptors());

List<Variable> forwardingParameters = parameters;
if (!targetMethodDescriptor.isStatic()
&& (qualifier == null || qualifier instanceof JavaScriptConstructorReference)) {
// The qualifier for the instance method becomes the first parameter. Method references to
// instance methods without an explicit qualifier use the first parameter in the functional
// interface as the qualifier for the method call.
checkArgument(
parameters.size() == targetMethodDescriptor.getParameterTypeDescriptors().size() + 1
|| (parameters.size() >= targetMethodDescriptor.getParameterTypeDescriptors().size()
&& targetMethodDescriptor.isVarargs()));
qualifier = parameters.get(0).getReference();
forwardingParameters = parameters.subList(1, parameters.size());
}

Statement forwardingStatement =
createForwardingStatement(
sourcePosition,
qualifier,
targetMethodDescriptor,
isStaticDispatch,
forwardingParameters,
functionalMethodDescriptor.getReturnTypeDescriptor());
return FunctionExpression.newBuilder()
.setTypeDescriptor(expressionTypeDescriptor)
.setParameters(parameters)
.setStatements(forwardingStatement)
.setSourcePosition(sourcePosition)
.build();
}

/**
* Creates forwarding method {@code fromMethodDescriptor} that delegates to {@code
* toMethodDescriptor}, e.g.
@@ -33,12 +33,15 @@
import com.google.j2cl.ast.FieldAccess;
import com.google.j2cl.ast.FieldDescriptor;
import com.google.j2cl.ast.FunctionExpression;
import com.google.j2cl.ast.JavaScriptConstructorReference;
import com.google.j2cl.ast.MethodDescriptor;
import com.google.j2cl.ast.MultiExpression;
import com.google.j2cl.ast.NewArray;
import com.google.j2cl.ast.NewInstance;
import com.google.j2cl.ast.NullLiteral;
import com.google.j2cl.ast.NumberLiteral;
import com.google.j2cl.ast.ReturnStatement;
import com.google.j2cl.ast.Statement;
import com.google.j2cl.ast.StringLiteral;
import com.google.j2cl.ast.ThisReference;
import com.google.j2cl.ast.Type;
@@ -107,6 +110,106 @@ protected void setCurrentCompilationUnit(CompilationUnit currentCompilationUnit)
// Helpers to synthesize lambdas for method references.
////////////////////////////////////////////////////////////////////////////////////////////////

/**
* Creates a lambda from a qualified method reference.
*
* <p>
*
* <pre>{@code
* q::m into (par1, ..., parN) -> q.m(par1, ..., parN) or
* (let $q = q, (par1, ..., parN) -> $q.m(par1, ..., parN)
* }</pre>
*
* <p>depending on whether the qualifier can be evaluated inside the functional expression
* preserving the original semantics.
*/
protected static Expression createMethodReferenceLambda(
SourcePosition sourcePosition,
Expression qualifier,
MethodDescriptor referencedMethodDescriptor,
TypeDescriptor expressionTypeDescriptor,
MethodDescriptor functionalMethodDescriptor) {
List<Expression> result = new ArrayList<>();

if (qualifier != null && !qualifier.isEffectivelyInvariant()) {
// The semantics require that the qualifier be evaluated in the context where the method
// reference appears, so here we introduce a temporary variable to store the evaluated
// qualifier.
Variable variable =
Variable.newBuilder()
.setFinal(true)
.setName("$$q")
.setTypeDescriptor(qualifier.getTypeDescriptor())
.build();
// Declare the temporary variable and initialize to the evaluated qualifier.
result.add(
VariableDeclarationExpression.newBuilder()
.addVariableDeclaration(variable, qualifier)
.build());
// Use the newly introduced variable as a qualifier when forwarding the call within the
// lambda expression.
qualifier = variable.getReference();
}

result.add(
createForwardingFunctionExpression(
sourcePosition,
expressionTypeDescriptor,
functionalMethodDescriptor,
qualifier,
referencedMethodDescriptor,
false));

return result.size() == 1
? Iterables.getOnlyElement(result)
: MultiExpression.newBuilder().setExpressions(result).build();
}

/**
* Creates a FunctionExpression described by {@code functionalMethodDescriptor} that forwards to
* {@code targetMethodDescriptor}.
*/
protected static FunctionExpression createForwardingFunctionExpression(
SourcePosition sourcePosition,
TypeDescriptor expressionTypeDescriptor,
MethodDescriptor functionalMethodDescriptor,
Expression qualifier,
MethodDescriptor targetMethodDescriptor,
boolean isStaticDispatch) {

List<Variable> parameters =
AstUtils.createParameterVariables(functionalMethodDescriptor.getParameterTypeDescriptors());

List<Variable> forwardingParameters = parameters;
if (!targetMethodDescriptor.isStatic()
&& (qualifier == null || qualifier instanceof JavaScriptConstructorReference)) {
// The qualifier for the instance method becomes the first parameter. Method references to
// instance methods without an explicit qualifier use the first parameter in the functional
// interface as the qualifier for the method call.
checkArgument(
parameters.size() == targetMethodDescriptor.getParameterTypeDescriptors().size() + 1
|| (parameters.size() >= targetMethodDescriptor.getParameterTypeDescriptors().size()
&& targetMethodDescriptor.isVarargs()));
qualifier = parameters.get(0).getReference();
forwardingParameters = parameters.subList(1, parameters.size());
}

Statement forwardingStatement =
AstUtils.createForwardingStatement(
sourcePosition,
qualifier,
targetMethodDescriptor,
isStaticDispatch,
forwardingParameters,
functionalMethodDescriptor.getReturnTypeDescriptor());
return FunctionExpression.newBuilder()
.setTypeDescriptor(expressionTypeDescriptor)
.setParameters(parameters)
.setStatements(forwardingStatement)
.setSourcePosition(sourcePosition)
.build();
}

/**
* Creates a class instantiation lambda from a method reference.
*
@@ -117,7 +220,7 @@ protected void setCurrentCompilationUnit(CompilationUnit currentCompilationUnit)
* (par1, ..., parN) -> B.this.new A(par1, ..., parN)
* }</pre>
*/
public static Expression createInstantiationLambda(
protected static Expression createInstantiationLambda(
MethodDescriptor functionalMethodDescriptor,
MethodDescriptor targetConstructorMethodDescriptor,
Expression qualifier,
@@ -156,7 +259,7 @@ public static Expression createInstantiationLambda(
*
* <pre>{@code convert A[]::new into (size) -> new A[size]} </pre>
*/
public static Expression createArrayCreationLambda(
protected static Expression createArrayCreationLambda(
MethodDescriptor targetFunctionalMethodDescriptor,
ArrayTypeDescriptor arrayType,
SourcePosition sourcePosition) {
@@ -59,7 +59,6 @@
import com.google.j2cl.ast.Method;
import com.google.j2cl.ast.MethodCall;
import com.google.j2cl.ast.MethodDescriptor;
import com.google.j2cl.ast.MultiExpression;
import com.google.j2cl.ast.NewArray;
import com.google.j2cl.ast.NewInstance;
import com.google.j2cl.ast.NullLiteral;
@@ -1047,52 +1046,28 @@ private Block convertLambdaBody(ASTNode lambdaBody, TypeDescriptor returnTypeDes
* preserving semantics.
*/
private Expression convert(ExpressionMethodReference expression) {
checkNotNull(expression.getExpression());

SourcePosition sourcePosition = getSourcePosition(expression);
TypeDescriptor expressionTypeDescriptor =
JdtUtils.createTypeDescriptor(expression.resolveTypeBinding());
Expression qualifier = convertOrNull(expression.getExpression());
if (qualifier == null || qualifier.isEffectivelyInvariant()) {
// There is no need to introduce a temporary variable for the qualifier.
return AstUtils.createForwardingFunctionExpression(
getSourcePosition(expression),
expressionTypeDescriptor,
// functional interface method that the expression implements.
JdtUtils.createMethodDescriptor(
expression.resolveTypeBinding().getFunctionalInterfaceMethod()),
qualifier,
// target method to forward to.
JdtUtils.createMethodDescriptor(expression.resolveMethodBinding()),
false);
}
// The semantics require that the qualifier be evaluated in the context where the method
// reference appears, so here we introduce a temporary variable to store the evaluated
// qualifier.
Variable variable =
Variable.newBuilder()
.setFinal(true)
.setName("$$q")
.setTypeDescriptor(qualifier.getTypeDescriptor())
.build();
// Store the declaring type in the local scope so that variable declaration scope points to
// the right type when the functional expression is effectively constructed.
return MultiExpression.newBuilder()
.setExpressions(
// Declare the temporary variable and initialize to the evaluated qualifier.
VariableDeclarationExpression.newBuilder()
.addVariableDeclaration(variable, qualifier)
.build(),
// Construct the functional expression.
AstUtils.createForwardingFunctionExpression(
getSourcePosition(expression),
expressionTypeDescriptor,
// functional interface method that the expression implements.
JdtUtils.createMethodDescriptor(
expression.resolveTypeBinding().getFunctionalInterfaceMethod()),
variable.getReference(),
// target method to forward to.
JdtUtils.createMethodDescriptor(expression.resolveMethodBinding()),
false))
.build();

// MethodDescriptor target of the method reference.
MethodDescriptor referencedMethodDescriptor =
JdtUtils.createMethodDescriptor(expression.resolveMethodBinding());

// Functional interface method that the expression implements.
MethodDescriptor functionalMethodDescriptor =
JdtUtils.createMethodDescriptor(
expression.resolveTypeBinding().getFunctionalInterfaceMethod());

Expression qualifier = convert(expression.getExpression());

return createMethodReferenceLambda(
sourcePosition,
qualifier,
referencedMethodDescriptor,
expressionTypeDescriptor,
functionalMethodDescriptor);
}

/**
@@ -1154,13 +1129,12 @@ private Expression convert(CreationReference expression) {
*/
private Expression convert(TypeMethodReference expression) {
ITypeBinding expressionTypeBinding = expression.resolveTypeBinding();
return AstUtils.createForwardingFunctionExpression(
return createMethodReferenceLambda(
getSourcePosition(expression),
JdtUtils.createDeclaredTypeDescriptor(expressionTypeBinding),
JdtUtils.createMethodDescriptor(expressionTypeBinding.getFunctionalInterfaceMethod()),
null,
JdtUtils.createMethodDescriptor(expression.resolveMethodBinding()),
false);
JdtUtils.createDeclaredTypeDescriptor(expressionTypeBinding),
JdtUtils.createMethodDescriptor(expressionTypeBinding.getFunctionalInterfaceMethod()));
}

/**
@@ -1176,7 +1150,7 @@ private Expression convert(SuperMethodReference expression) {
MethodDescriptor methodDescriptor =
JdtUtils.createMethodDescriptor(expression.resolveMethodBinding());

return AstUtils.createForwardingFunctionExpression(
return AbstractCompilationUnitBuilder.createForwardingFunctionExpression(
getSourcePosition(expression),
JdtUtils.createDeclaredTypeDescriptor(expression.resolveTypeBinding()),
JdtUtils.createMethodDescriptor(

0 comments on commit a66e3d0

Please sign in to comment.
You can’t perform that action at this time.