@@ -365,16 +365,13 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
365365
366366 public static final Statement GENERATED_EMPTY_STATEMENT = EmptyStatement .INSTANCE ;
367367
368- protected final ReturnAdder .ReturnStatementListener returnListener = new ReturnAdder .ReturnStatementListener () {
369- @ Override
370- public void returnStatementAdded (final ReturnStatement returnStatement ) {
371- if (isNullConstant (returnStatement .getExpression ())) return ;
372- ClassNode returnType = checkReturnType (returnStatement );
373- if (typeCheckingContext .getEnclosingClosure () != null ) {
374- addClosureReturnType (returnType );
375- } else if (typeCheckingContext .getEnclosingMethod () == null ) {
376- throw new GroovyBugError ("Unexpected return statement at " + returnStatement .getLineNumber () + ":" + returnStatement .getColumnNumber () + " " + returnStatement .getText ());
377- }
368+ protected final ReturnAdder .ReturnStatementListener returnListener = returnStatement -> {
369+ if (returnStatement .isReturningNullOrVoid ()) return ;
370+ ClassNode returnType = checkReturnType (returnStatement );
371+ if (this .typeCheckingContext .getEnclosingClosure () != null ) {
372+ addClosureReturnType (returnType );
373+ } else if (this .typeCheckingContext .getEnclosingMethod () == null ) {
374+ throw new GroovyBugError ("Unexpected return statement at " + returnStatement .getLineNumber () + ":" + returnStatement .getColumnNumber () + " " + returnStatement .getText ());
378375 }
379376 };
380377
@@ -792,11 +789,7 @@ public void visitBinaryExpression(final BinaryExpression expression) {
792789 } else {
793790 lType = getOriginalDeclarationType (leftExpression );
794791
795- if (isFunctionalInterface (lType )) {
796- processFunctionalInterfaceAssignment (lType , rightExpression );
797- } else if (isClosureWithType (lType ) && rightExpression instanceof ClosureExpression ) {
798- storeInferredReturnType (rightExpression , getCombinedBoundType (lType .getGenericsTypes ()[0 ]));
799- }
792+ applyTargetType (lType , rightExpression );
800793 }
801794 rightExpression .visit (this );
802795 }
@@ -965,15 +958,22 @@ private void validateResourceInARM(final BinaryExpression expression, final Clas
965958 }
966959 }
967960
968- private void processFunctionalInterfaceAssignment (final ClassNode lhsType , final Expression rhsExpression ) {
969- if (rhsExpression instanceof ClosureExpression ) {
970- inferParameterAndReturnTypesOfClosureOnRHS (lhsType , (ClosureExpression ) rhsExpression );
971- } else if (rhsExpression instanceof MethodReferenceExpression ) {
972- LambdaExpression lambdaExpression = constructLambdaExpressionForMethodReference (lhsType );
961+ private void applyTargetType (final ClassNode target , final Expression source ) {
962+ if (isFunctionalInterface (target )) {
963+ if (source instanceof ClosureExpression ) {
964+ inferParameterAndReturnTypesOfClosureOnRHS (target , (ClosureExpression ) source );
965+ } else if (source instanceof MethodReferenceExpression ) {
966+ LambdaExpression lambdaExpression = constructLambdaExpressionForMethodReference (target );
973967
974- inferParameterAndReturnTypesOfClosureOnRHS (lhsType , lambdaExpression );
975- rhsExpression .putNodeMetaData (CONSTRUCTED_LAMBDA_EXPRESSION , lambdaExpression );
976- rhsExpression .putNodeMetaData (CLOSURE_ARGUMENTS , Arrays .stream (lambdaExpression .getParameters ()).map (Parameter ::getType ).toArray (ClassNode []::new ));
968+ inferParameterAndReturnTypesOfClosureOnRHS (target , lambdaExpression );
969+ source .putNodeMetaData (CONSTRUCTED_LAMBDA_EXPRESSION , lambdaExpression );
970+ source .putNodeMetaData (CLOSURE_ARGUMENTS , Arrays .stream (lambdaExpression .getParameters ()).map (Parameter ::getType ).toArray (ClassNode []::new ));
971+ }
972+ } else if (isClosureWithType (target )) {
973+ if (source instanceof ClosureExpression ) {
974+ GenericsType returnType = target .getGenericsTypes ()[0 ];
975+ storeInferredReturnType (source , getCombinedBoundType (returnType ));
976+ }
977977 }
978978 }
979979
@@ -1970,11 +1970,7 @@ public void visitField(final FieldNode node) {
19701970 private void visitInitialExpression (final Expression value , final Expression target , final ASTNode position ) {
19711971 if (value != null ) {
19721972 ClassNode lType = target .getType ();
1973- if (isFunctionalInterface (lType )) { // GROOVY-9977
1974- processFunctionalInterfaceAssignment (lType , value );
1975- } else if (isClosureWithType (lType ) && value instanceof ClosureExpression ) {
1976- storeInferredReturnType (value , getCombinedBoundType (lType .getGenericsTypes ()[0 ]));
1977- }
1973+ applyTargetType (lType , value ); // GROOVY-9977
19781974
19791975 typeCheckingContext .pushEnclosingBinaryExpression (assignX (target , value , position ));
19801976
@@ -2244,6 +2240,12 @@ public void visitExpressionStatement(final ExpressionStatement statement) {
22442240
22452241 @ Override
22462242 public void visitReturnStatement (final ReturnStatement statement ) {
2243+ if (typeCheckingContext .getEnclosingClosure () == null ) {
2244+ MethodNode method = typeCheckingContext .getEnclosingMethod ();
2245+ if (method != null && !method .isVoidMethod () && !method .isDynamicReturnType ()) {
2246+ applyTargetType (method .getReturnType (), statement .getExpression ()); // GROOVY-10660
2247+ }
2248+ }
22472249 super .visitReturnStatement (statement );
22482250 returnListener .returnStatementAdded (statement );
22492251 }
@@ -2631,6 +2633,10 @@ protected void startMethodInference(final MethodNode node, final ErrorCollector
26312633 @ Override
26322634 protected void visitConstructorOrMethod (final MethodNode node , final boolean isConstructor ) {
26332635 typeCheckingContext .pushEnclosingMethod (node );
2636+ final ClassNode returnType = node .getReturnType (); // GROOVY-10660: implicit return case
2637+ if (!isConstructor && (isClosureWithType (returnType ) || isFunctionalInterface (returnType ))) {
2638+ new ReturnAdder (returnStmt -> applyTargetType (returnType , returnStmt .getExpression ())).visitMethod (node );
2639+ }
26342640 readClosureParameterAnnotation (node ); // GROOVY-6603
26352641 super .visitConstructorOrMethod (node , isConstructor );
26362642 if (node .hasDefaultValue ()) {
@@ -4168,18 +4174,14 @@ public void visitArrayExpression(final ArrayExpression expression) {
41684174
41694175 @ Override
41704176 public void visitCastExpression (final CastExpression expression ) {
4171- ClassNode type = expression .getType ();
4177+ ClassNode target = expression .getType ();
41724178 Expression source = expression .getExpression ();
4173- if (isFunctionalInterface (type )) { // GROOVY-9997
4174- processFunctionalInterfaceAssignment (type , source );
4175- } else if (isClosureWithType (type ) && source instanceof ClosureExpression ) {
4176- storeInferredReturnType (source , getCombinedBoundType (type .getGenericsTypes ()[0 ]));
4177- }
4179+ applyTargetType (target , source ); // GROOVY-9997
41784180
41794181 source .visit (this );
41804182
4181- if (!expression .isCoerce () && !checkCast (type , source )) {
4182- addStaticTypeError ("Inconvertible types: cannot cast " + prettyPrintType (getType (source )) + " to " + prettyPrintType (type ), expression );
4183+ if (!expression .isCoerce () && !checkCast (target , source )) {
4184+ addStaticTypeError ("Inconvertible types: cannot cast " + prettyPrintType (getType (source )) + " to " + prettyPrintType (target ), expression );
41834185 }
41844186 }
41854187
@@ -5999,19 +6001,16 @@ private class ParameterVariableExpression extends VariableExpression {
59996001 ParameterVariableExpression (final Parameter parameter ) {
60006002 super (parameter );
60016003 this .parameter = parameter ;
6002- /* GRECLIPSE edit -- GROOVY-10651
6003- this.parameter.getNodeMetaData(INFERRED_TYPE, x -> parameter.getOriginType());
6004- */
6004+
60056005 ClassNode inferredType = getNodeMetaData (INFERRED_TYPE );
60066006 if (inferredType == null ) {
60076007 inferredType = typeCheckingContext .controlStructureVariables .get (parameter ); // for/catch/closure
60086008 if (inferredType == null ) {
60096009 TypeCheckingContext .EnclosingClosure enclosingClosure = typeCheckingContext .getEnclosingClosure ();
60106010 if (enclosingClosure != null ) inferredType = getTypeFromClosureArguments (parameter , enclosingClosure );
60116011 }
6012- setNodeMetaData (INFERRED_TYPE , inferredType != null ? inferredType : parameter .getType ()); // to parameter
6012+ setNodeMetaData (INFERRED_TYPE , inferredType != null ? inferredType : parameter .getType ()); // GROOVY-10651
60136013 }
6014- // GRECLIPSE end
60156014 }
60166015
60176016 @ Override
0 commit comments