1f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassettipackage com.github.javaparser.symbolsolver.resolution.typeinference.constraintformulas; 2f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 3f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassettiimport com.github.javaparser.ast.expr.*; 4f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassettiimport com.github.javaparser.ast.stmt.*; 5f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassettiimport com.github.javaparser.ast.type.UnknownType; 6e8007447885c3ee0a462444cbc7fa83e80297f4aFederico Tomassettiimport com.github.javaparser.resolution.types.ResolvedType; 7e8007447885c3ee0a462444cbc7fa83e80297f4aFederico Tomassettiimport com.github.javaparser.resolution.types.ResolvedTypeVariable; 8f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassettiimport com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade; 9f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassettiimport com.github.javaparser.symbolsolver.logic.FunctionalInterfaceLogic; 10f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassettiimport com.github.javaparser.symbolsolver.model.resolution.TypeSolver; 11f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassettiimport com.github.javaparser.symbolsolver.resolution.typeinference.*; 12f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassettiimport com.github.javaparser.utils.Pair; 13f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 14a65cadbf0b6914f061968057a80680a5d25a042bFederico Tomassettiimport java.util.HashMap; 15f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassettiimport java.util.LinkedList; 16f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassettiimport java.util.List; 17a65cadbf0b6914f061968057a80680a5d25a042bFederico Tomassettiimport java.util.Map; 18f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 19f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassettiimport static com.github.javaparser.symbolsolver.resolution.typeinference.ExpressionHelper.isPolyExpression; 20f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassettiimport static com.github.javaparser.symbolsolver.resolution.typeinference.ExpressionHelper.isStandaloneExpression; 21f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassettiimport static com.github.javaparser.symbolsolver.resolution.typeinference.TypeHelper.isCompatibleInALooseInvocationContext; 22f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassettiimport static com.github.javaparser.symbolsolver.resolution.typeinference.TypeHelper.isProperType; 23b54617e765d73b3ce0d187cf12ad8da382bce439Danny van Bruggenimport static java.util.stream.Collectors.*; 24f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 25f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti/** 26f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti * An expression is compatible in a loose invocation context with type T 27f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti * 28f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti * @author Federico Tomassetti 29f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti */ 30f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassettipublic class ExpressionCompatibleWithType extends ConstraintFormula { 31f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti private TypeSolver typeSolver; 32f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti private Expression expression; 33e8007447885c3ee0a462444cbc7fa83e80297f4aFederico Tomassetti private ResolvedType T; 34f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 35e8007447885c3ee0a462444cbc7fa83e80297f4aFederico Tomassetti public ExpressionCompatibleWithType(TypeSolver typeSolver, Expression expression, ResolvedType T) { 36f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti this.typeSolver = typeSolver; 37f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti this.expression = expression; 38f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti this.T = T; 39f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti } 40f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 41f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti @Override 42f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti public ReductionResult reduce(BoundSet currentBoundSet) { 43f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // If T is a proper type, the constraint reduces to true if the expression is compatible in a loose 44f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // invocation context with T (§5.3), and false otherwise. 45f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 46f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti if (isProperType(T)) { 47f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti if (isCompatibleInALooseInvocationContext(typeSolver, expression, T)) { 48f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti return ReductionResult.trueResult(); 49f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti } else { 50f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti return ReductionResult.falseResult(); 51f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti } 52f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti } 53f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 54f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // Otherwise, if the expression is a standalone expression (§15.2) of type S, the constraint reduces 55f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // to ‹S → T›. 56f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 57f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti if (isStandaloneExpression(expression)) { 58e8007447885c3ee0a462444cbc7fa83e80297f4aFederico Tomassetti ResolvedType s = JavaParserFacade.get(typeSolver).getType(expression, false); 59f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti return ReductionResult.empty().withConstraint(new TypeCompatibleWithType(typeSolver, s, T)); 60f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti } 61f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 62f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // Otherwise, the expression is a poly expression (§15.2). The result depends on the form of the expression: 63f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 64f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti if (isPolyExpression(expression)) { 65f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 66f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // - If the expression is a parenthesized expression of the form ( Expression' ), the constraint reduces 67f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // to ‹Expression' → T›. 68f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 69f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti if (expression instanceof EnclosedExpr) { 70f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti EnclosedExpr enclosedExpr = (EnclosedExpr)expression; 71f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti return ReductionResult.oneConstraint(new ExpressionCompatibleWithType(typeSolver, enclosedExpr.getInner(), T)); 72f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti } 73f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 74f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // - If the expression is a class instance creation expression or a method invocation expression, the 75f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // constraint reduces to the bound set B3 which would be used to determine the expression's invocation 76f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // type when targeting T, as defined in §18.5.2. (For a class instance creation expression, the 77f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // corresponding "method" used for inference is defined in §15.9.3). 78f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // 79f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // This bound set may contain new inference variables, as well as dependencies between these new 80f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // variables and the inference variables in T. 81f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 82f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti if (expression instanceof ObjectCreationExpr) { 83d85a40f2ffa200bbb0b11adc979e69f3c9410c5fFederico Tomassetti BoundSet B3 = new TypeInference(typeSolver).invocationTypeInferenceBoundsSetB3(); 84d85a40f2ffa200bbb0b11adc979e69f3c9410c5fFederico Tomassetti return ReductionResult.bounds(B3); 85f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti } 86f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 87f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti if (expression instanceof MethodCallExpr) { 88f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti throw new UnsupportedOperationException(); 89f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti } 90f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 91f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // - If the expression is a conditional expression of the form e1 ? e2 : e3, the constraint reduces to two 92f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // constraint formulas, ‹e2 → T› and ‹e3 → T›. 93f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 94f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti if (expression instanceof ConditionalExpr) { 95f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti ConditionalExpr conditionalExpr = (ConditionalExpr)expression; 96f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti return ReductionResult.withConstraints( 97f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti new ExpressionCompatibleWithType(typeSolver, conditionalExpr.getThenExpr(), T), 98f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti new ExpressionCompatibleWithType(typeSolver, conditionalExpr.getElseExpr(), T)); 99f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti } 100f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 101f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // - If the expression is a lambda expression or a method reference expression, the result is specified 102f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // below. 103f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 104f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // A constraint formula of the form ‹LambdaExpression → T›, where T mentions at least one inference variable, is reduced as follows: 105f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 106f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti if (expression instanceof LambdaExpr) { 107f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti LambdaExpr lambdaExpr = (LambdaExpr)expression; 108f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 109f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // - If T is not a functional interface type (§9.8), the constraint reduces to false. 110f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 111f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti if (!FunctionalInterfaceLogic.isFunctionalInterfaceType(T)) { 112f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti return ReductionResult.falseResult(); 113f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti } 114f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 115f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // - Otherwise, let T' be the ground target type derived from T, as specified in §15.27.3. If §18.5.3 116f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // is used to derive a functional interface type which is parameterized, then the test that 117f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // F<A'1, ..., A'm> is a subtype of F<A1, ..., Am> is not performed (instead, it is asserted with a 118f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // constraint formula below). Let the target function type for the lambda expression be the 119f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // function type of T'. Then: 120f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 121e8007447885c3ee0a462444cbc7fa83e80297f4aFederico Tomassetti Pair<ResolvedType, Boolean> result = TypeHelper.groundTargetTypeOfLambda(lambdaExpr, T, typeSolver); 122e8007447885c3ee0a462444cbc7fa83e80297f4aFederico Tomassetti ResolvedType TFirst = result.a; 123f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti MethodType targetFunctionType = TypeHelper.getFunctionType(TFirst); 124a65cadbf0b6914f061968057a80680a5d25a042bFederico Tomassetti targetFunctionType = replaceTypeVariablesWithInferenceVariables(targetFunctionType); 125f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti if (result.b) { 126f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti throw new UnsupportedOperationException(); 127f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti } 128f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 129f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // - If no valid function type can be found, the constraint reduces to false. 130f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // 131f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // Federico: THIS SHOULD NOT HAPPEN, IN CASE WE WILL THROW AN EXCEPTION 132f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // 133f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // - Otherwise, the congruence of LambdaExpression with the target function type is asserted as 134f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // follows: 135f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // 136f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // - If the number of lambda parameters differs from the number of parameter types of the function 137f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // type, the constraint reduces to false. 138f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 139f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti if (targetFunctionType.getFormalArgumentTypes().size() != lambdaExpr.getParameters().size()) { 140f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti return ReductionResult.falseResult(); 141f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti } 142f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 143f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // - If the lambda expression is implicitly typed and one or more of the function type's parameter 144f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // types is not a proper type, the constraint reduces to false. 145f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // 146f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // This condition never arises in practice, due to the handling of implicitly typed lambda 147f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // expressions in §18.5.1 and the substitution applied to the target type in §18.5.2. 148f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 149f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // - If the function type's result is void and the lambda body is neither a statement expression 150f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // nor a void-compatible block, the constraint reduces to false. 151f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 152f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti if (targetFunctionType.getReturnType().isVoid()) { 153f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti throw new UnsupportedOperationException(); 154f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti } 155f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 156f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // - If the function type's result is not void and the lambda body is a block that is not 157f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // value-compatible, the constraint reduces to false. 158f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 159f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti if (!targetFunctionType.getReturnType().isVoid() && lambdaExpr.getBody() instanceof BlockStmt 160f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti && !isValueCompatibleBlock(lambdaExpr.getBody())) { 161f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti return ReductionResult.falseResult(); 162f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti } 163f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 164f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // - Otherwise, the constraint reduces to all of the following constraint formulas: 165f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti List<ConstraintFormula> constraints = new LinkedList<>(); 166f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 167f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // - If the lambda parameters have explicitly declared types F1, ..., Fn and the function type 168f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // has parameter types G1, ..., Gn, then i) for all i (1 ≤ i ≤ n), ‹Fi = Gi›, and ii) ‹T' <: T›. 169f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 170f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti boolean hasExplicitlyDeclaredTypes = lambdaExpr.getParameters().stream().anyMatch(p -> !(p.getType() instanceof UnknownType)); 171f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti if (hasExplicitlyDeclaredTypes) { 172f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti throw new UnsupportedOperationException(); 173f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti } 174f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 175f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // - If the function type's return type is a (non-void) type R, assume the lambda's parameter 176f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // types are the same as the function type's parameter types. Then: 177f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 178f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti if (!targetFunctionType.getReturnType().isVoid()) { 179f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 180e8007447885c3ee0a462444cbc7fa83e80297f4aFederico Tomassetti ResolvedType R = targetFunctionType.getReturnType(); 181f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 182f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti if (TypeHelper.isProperType(R)) { 183f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 184f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // - If R is a proper type, and if the lambda body or some result expression in the lambda body 185f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // is not compatible in an assignment context with R, then false. 186f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 187f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti if (lambdaExpr.getBody() instanceof BlockStmt) { 188f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti List<Expression> resultExpressions = ExpressionHelper.getResultExpressions((BlockStmt)lambdaExpr.getBody()); 189f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti for (Expression e : resultExpressions) { 190f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti if (!ExpressionHelper.isCompatibleInAssignmentContext(e, R, typeSolver)) { 191f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti return ReductionResult.falseResult(); 192f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti } 193f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti } 194f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti } else { 195f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti Expression e = ((ExpressionStmt)lambdaExpr.getBody()).getExpression(); 196f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti if (!ExpressionHelper.isCompatibleInAssignmentContext(e, R, typeSolver)) { 197f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti return ReductionResult.falseResult(); 198f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti } 199f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti } 200f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti } else { 201f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // - Otherwise, if R is not a proper type, then where the lambda body has the form Expression, 202f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // the constraint ‹Expression → R›; or where the lambda body is a block with result 203f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // expressions e1, ..., em, for all i (1 ≤ i ≤ m), ‹ei → R›. 204f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 205f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti if (lambdaExpr.getBody() instanceof BlockStmt) { 206b54617e765d73b3ce0d187cf12ad8da382bce439Danny van Bruggen getAllReturnExpressions((BlockStmt)lambdaExpr.getBody()).forEach(e -> constraints.add(new ExpressionCompatibleWithType(typeSolver, e, R))); 207f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti } else { 208f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // FEDERICO: Added - Start 209f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti for (int i=0;i<lambdaExpr.getParameters().size();i++) { 210e8007447885c3ee0a462444cbc7fa83e80297f4aFederico Tomassetti ResolvedType paramType = targetFunctionType.getFormalArgumentTypes().get(i); 211f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti TypeInferenceCache.record(typeSolver, lambdaExpr, lambdaExpr.getParameter(i).getNameAsString(), paramType); 212f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti } 213f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // FEDERICO: Added - End 214f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti Expression e = ((ExpressionStmt)lambdaExpr.getBody()).getExpression(); 215f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti constraints.add(new ExpressionCompatibleWithType(typeSolver, e, R)); 216f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti } 217f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti } 218f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti } 219f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 220f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti return ReductionResult.withConstraints(constraints); 221f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti } 222f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 223f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // A constraint formula of the form ‹MethodReference → T›, where T mentions at least one inference variable, is reduced as follows: 224f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 225f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti if (expression instanceof MethodReferenceExpr) { 226f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 227f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // - If T is not a functional interface type, or if T is a functional interface type that does not have a function type (§9.9), the constraint reduces to false. 228f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // 229f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // - Otherwise, if there does not exist a potentially applicable method for the method reference when targeting T, the constraint reduces to false. 230f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // 231f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // - Otherwise, if the method reference is exact (§15.13.1), then let P1, ..., Pn be the parameter types of the function type of T, and let F1, ..., Fk be the parameter types of the potentially applicable method. The constraint reduces to a new set of constraints, as follows: 232f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // 233f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // - In the special case where n = k+1, the parameter of type P1 is to act as the target reference of the invocation. The method reference expression necessarily has the form ReferenceType :: [TypeArguments] Identifier. The constraint reduces to ‹P1 <: ReferenceType› and, for all i (2 ≤ i ≤ n), ‹Pi → Fi-1›. 234f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // 235f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // In all other cases, n = k, and the constraint reduces to, for all i (1 ≤ i ≤ n), ‹Pi → Fi›. 236f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // 237f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // - If the function type's result is not void, let R be its return type. Then, if the result of the potentially applicable compile-time declaration is void, the constraint reduces to false. Otherwise, the constraint reduces to ‹R' → R›, where R' is the result of applying capture conversion (§5.1.10) to the return type of the potentially applicable compile-time declaration. 238f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // 239f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // - Otherwise, the method reference is inexact, and: 240f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // 241f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // - If one or more of the function type's parameter types is not a proper type, the constraint reduces to false. 242f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // 243f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // This condition never arises in practice, due to the handling of inexact method references in §18.5.1 and the substitution applied to the target type in §18.5.2. 244f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // 245f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // - Otherwise, a search for a compile-time declaration is performed, as specified in §15.13.1. If there is no compile-time declaration for the method reference, the constraint reduces to false. Otherwise, there is a compile-time declaration, and: 246f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // 247f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // - If the result of the function type is void, the constraint reduces to true. 248f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // 249f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // - Otherwise, if the method reference expression elides TypeArguments, and the compile-time declaration is a generic method, and the return type of the compile-time declaration mentions at least one of the method's type parameters, then the constraint reduces to the bound set B3 which would be used to determine the method reference's invocation type when targeting the return type of the function type, as defined in §18.5.2. B3 may contain new inference variables, as well as dependencies between these new variables and the inference variables in T. 250f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // 251f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // - Otherwise, let R be the return type of the function type, and let R' be the result of applying capture conversion (§5.1.10) to the return type of the invocation type (§15.12.2.6) of the compile-time declaration. If R' is void, the constraint reduces to false; otherwise, the constraint reduces to ‹R' → R›. 252f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 253f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti throw new UnsupportedOperationException(); 254f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti } 255f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 256f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti throw new RuntimeException("This should not happen"); 257f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti } 258f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 259f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti throw new RuntimeException("This should not happen"); 260f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti } 261f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 262f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti private List<Expression> getAllReturnExpressions(BlockStmt blockStmt) { 263b54617e765d73b3ce0d187cf12ad8da382bce439Danny van Bruggen return blockStmt.findAll(ReturnStmt.class).stream() 264f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti .filter(r -> r.getExpression().isPresent()) 265f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti .map(r -> r.getExpression().get()) 266b54617e765d73b3ce0d187cf12ad8da382bce439Danny van Bruggen .collect(toList()); 267f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti } 268f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 269f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti private boolean isValueCompatibleBlock(Statement statement) { 270f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // A block lambda body is value-compatible if it cannot complete normally (§14.21) and every return statement 271f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti // in the block has the form return Expression;. 272f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 273f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti if (statement instanceof BlockStmt) { 274d86f152abcaf45b9ad37a1341ab46299b8e99497Federico Tomassetti if (!ControlFlowLogic.getInstance().canCompleteNormally(statement)) { 275f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti return true; 276f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti } 277b54617e765d73b3ce0d187cf12ad8da382bce439Danny van Bruggen List<ReturnStmt> returnStmts = statement.findAll(ReturnStmt.class); 278f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti return returnStmts.stream().allMatch(r -> r.getExpression().isPresent()); 279f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti } 280b54617e765d73b3ce0d187cf12ad8da382bce439Danny van Bruggen return false; 281f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti } 282f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 283f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti @Override 284f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti public boolean equals(Object o) { 285f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti if (this == o) return true; 286f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti if (o == null || getClass() != o.getClass()) return false; 287f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 288f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti ExpressionCompatibleWithType that = (ExpressionCompatibleWithType) o; 289f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 290f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti if (!typeSolver.equals(that.typeSolver)) return false; 291f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti if (!expression.equals(that.expression)) return false; 292f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti return T.equals(that.T); 293f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti } 294f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 295f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti @Override 296f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti public int hashCode() { 297f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti int result = typeSolver.hashCode(); 298f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti result = 31 * result + expression.hashCode(); 299f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti result = 31 * result + T.hashCode(); 300f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti return result; 301f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti } 302f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti 303f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti @Override 304f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti public String toString() { 305f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti return "ExpressionCompatibleWithType{" + 306f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti "typeSolver=" + typeSolver + 307f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti ", expression=" + expression + 308f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti ", T=" + T + 309f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti '}'; 310f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti } 311a65cadbf0b6914f061968057a80680a5d25a042bFederico Tomassetti 312a65cadbf0b6914f061968057a80680a5d25a042bFederico Tomassetti private MethodType replaceTypeVariablesWithInferenceVariables(MethodType methodType) { 313a65cadbf0b6914f061968057a80680a5d25a042bFederico Tomassetti // Find all type variable 314e8007447885c3ee0a462444cbc7fa83e80297f4aFederico Tomassetti Map<ResolvedTypeVariable, InferenceVariable> correspondences = new HashMap<>(); 315e8007447885c3ee0a462444cbc7fa83e80297f4aFederico Tomassetti List<ResolvedType> newFormalArgumentTypes = new LinkedList<>(); 316e8007447885c3ee0a462444cbc7fa83e80297f4aFederico Tomassetti for (ResolvedType formalArg : methodType.getFormalArgumentTypes()) { 317a65cadbf0b6914f061968057a80680a5d25a042bFederico Tomassetti newFormalArgumentTypes.add(replaceTypeVariablesWithInferenceVariables(formalArg, correspondences)); 318a65cadbf0b6914f061968057a80680a5d25a042bFederico Tomassetti } 319e8007447885c3ee0a462444cbc7fa83e80297f4aFederico Tomassetti ResolvedType newReturnType = replaceTypeVariablesWithInferenceVariables(methodType.getReturnType(), correspondences); 320a65cadbf0b6914f061968057a80680a5d25a042bFederico Tomassetti return new MethodType(methodType.getTypeParameters(), newFormalArgumentTypes, newReturnType, methodType.getExceptionTypes()); 321a65cadbf0b6914f061968057a80680a5d25a042bFederico Tomassetti } 322a65cadbf0b6914f061968057a80680a5d25a042bFederico Tomassetti 323e8007447885c3ee0a462444cbc7fa83e80297f4aFederico Tomassetti private ResolvedType replaceTypeVariablesWithInferenceVariables(ResolvedType originalType, Map<ResolvedTypeVariable, InferenceVariable> correspondences) { 324a65cadbf0b6914f061968057a80680a5d25a042bFederico Tomassetti if (originalType.isTypeVariable()) { 325a65cadbf0b6914f061968057a80680a5d25a042bFederico Tomassetti if (!correspondences.containsKey(originalType.asTypeVariable())) { 326a65cadbf0b6914f061968057a80680a5d25a042bFederico Tomassetti correspondences.put(originalType.asTypeVariable(), InferenceVariable.unnamed(originalType.asTypeVariable().asTypeParameter())); 327a65cadbf0b6914f061968057a80680a5d25a042bFederico Tomassetti } 328a65cadbf0b6914f061968057a80680a5d25a042bFederico Tomassetti return correspondences.get(originalType.asTypeVariable()); 329a65cadbf0b6914f061968057a80680a5d25a042bFederico Tomassetti } 330a65cadbf0b6914f061968057a80680a5d25a042bFederico Tomassetti if (originalType.isPrimitive()) { 331a65cadbf0b6914f061968057a80680a5d25a042bFederico Tomassetti return originalType; 332a65cadbf0b6914f061968057a80680a5d25a042bFederico Tomassetti } 333a65cadbf0b6914f061968057a80680a5d25a042bFederico Tomassetti throw new UnsupportedOperationException(originalType.toString()); 334a65cadbf0b6914f061968057a80680a5d25a042bFederico Tomassetti } 335f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti} 336