private boolean ensureValidSetter ( final Expression expression , final Expression leftExpression , final Expression rightExpression , final SetterInfo setterInfo ) { // for expressions like foo = { ... } // we know that the RHS type is a closure // but we must check if the binary expression is an assignment // because we need to check if a setter uses @DelegatesTo VariableExpression ve = new VariableExpression ( "%" , setterInfo . receiverType ) ; MethodCallExpression call = new MethodCallExpression ( ve , setterInfo . name , rightExpression ) ; call . setImplicitThis ( false ) ; visitMethodCallExpression ( call ) ; MethodNode directSetterCandidate = call . getNodeMetaData ( StaticTypesMarker . DIRECT_METHOD_CALL_TARGET ) ; if ( directSetterCandidate == null ) { // this may happen if there's a setter of type boolean/String/Class, and that we are using the property // notation AND that the RHS is not a boolean/String/Class for ( MethodNode setter : setterInfo . setters ) { ClassNode type = getWrapper ( setter . getParameters ( ) [ 0 ] . getOriginType ( ) ) ; if ( Boolean_TYPE . equals ( type ) || STRING_TYPE . equals ( type ) || CLASS_Type . equals ( type ) ) { call = new MethodCallExpression ( ve , setterInfo . name , new CastExpression ( type , rightExpression ) ) ; call . setImplicitThis ( false ) ; visitMethodCallExpression ( call ) ; directSetterCandidate = call . getNodeMetaData ( StaticTypesMarker . DIRECT_METHOD_CALL_TARGET ) ; if ( directSetterCandidate != null ) { break ; } } } } if ( directSetterCandidate != null ) { for ( MethodNode setter : setterInfo . setters ) { if ( setter == directSetterCandidate ) { leftExpression . putNodeMetaData ( StaticTypesMarker . DIRECT_METHOD_CALL_TARGET , directSetterCandidate ) ; storeType ( leftExpression , getType ( rightExpression ) ) ; break ; } } } else { ClassNode firstSetterType = setterInfo . setters . iterator ( ) . next ( ) . getParameters ( ) [ 0 ] . getOriginType ( ) ; addAssignmentError ( firstSetterType , getType ( rightExpression ) , expression ) ; return true ; } return false ; }
Given a binary expression corresponding to an assignment will check that the type of the RHS matches one of the possible setters and if not throw a type checking error .