@@ -124,22 +124,18 @@ public abstract class Selector {
124124 private static final CallType [] CALL_TYPE_VALUES = CallType .values ();
125125
126126 /**
127- * Returns the Selector
127+ * Returns a Selector or throws a GroovyBugError.
128128 */
129129 public static Selector getSelector (CacheableCallSite callSite , Class <?> sender , String methodName , int callID , boolean safeNavigation , boolean thisCall , boolean spreadCall , Object [] arguments ) {
130130 CallType callType = CALL_TYPE_VALUES [callID ];
131131 return switch (callType ) {
132- case INIT ->
133- new InitSelector (callSite , sender , methodName , callType , safeNavigation , thisCall , spreadCall , arguments );
134- case METHOD ->
135- new MethodSelector (callSite , sender , methodName , callType , safeNavigation , thisCall , spreadCall , arguments );
136- case GET ->
137- new PropertySelector (callSite , sender , methodName , callType , safeNavigation , thisCall , spreadCall , arguments );
138- case SET -> throw new GroovyBugError ("your call tried to do a property set, which is not supported." );
139- case CAST -> new CastSelector (callSite , arguments );
140- case INTERFACE ->
141- new InterfaceSelector (callSite , sender , methodName , callType , safeNavigation , thisCall , spreadCall , arguments );
142- default -> throw new GroovyBugError ("unexpected call type" );
132+ case INIT -> new InitSelector (callSite , sender , methodName , callType , safeNavigation , thisCall , spreadCall , arguments );
133+ case METHOD -> new MethodSelector (callSite , sender , methodName , callType , safeNavigation , thisCall , spreadCall , arguments );
134+ case GET -> new PropertySelector (callSite , sender , methodName , callType , safeNavigation , thisCall , spreadCall , arguments );
135+ case SET -> throw new GroovyBugError ("your call tried to do a property set, which is not supported." );
136+ case CAST -> new CastSelector (callSite , sender , methodName , arguments );
137+ case INTERFACE -> new InterfaceSelector (callSite , sender , methodName , callType , safeNavigation , thisCall , spreadCall , arguments );
138+ default -> throw new GroovyBugError ("unexpected call type" );
143139 };
144140 }
145141
@@ -164,35 +160,37 @@ public Object getCorrectedReceiver() {
164160 private static class CastSelector extends MethodSelector {
165161 private final Class <?> staticSourceType , staticTargetType ;
166162
167- public CastSelector (CacheableCallSite callSite , Object [] arguments ) {
168- super (callSite , Selector . class , "" , CallType .CAST , Boolean .FALSE , Boolean .FALSE , Boolean .FALSE , arguments );
163+ CastSelector (final CacheableCallSite callSite , final Class <?> sender , final String spec , final Object [] args ) {
164+ super (callSite , sender , spec , CallType .CAST , Boolean .FALSE , Boolean .FALSE , Boolean .FALSE , args );
169165 this .staticSourceType = callSite .type ().parameterType (0 );
170166 this .staticTargetType = callSite .type ().returnType ();
171167 }
172168
173169 @ Override
174170 public void setCallSiteTarget () {
175- // target types String, Enum and Class are handled by the compiler
171+ // NOTE: target types String, Class, and Enum are handled by the compiler
176172
177- handleBoolean ();
178- handleNullWithoutBoolean ();
173+ if ( handle == null ) handleBoolean ();
174+ if ( handle == null ) handleNullWithoutBoolean ();
179175
180- // !! from here on args[0] is always not null !!
181- handleInstanceCase ();
176+ // NOTE: !! from here on if handle is null, args[0] is always not null !!
182177
183- // targetType is abstract Collection fitting for HashSet or ArrayList
184- // and object is Collection or array
185- handleCollections ();
186- handleSAM ();
178+ if (handle == null ) handleIsAnInstance ();
179+ if (handle == null ) handleCollections ();
180+ if (handle == null ) handleSAM ();
187181
188182 // will handle :
189183 // * collection case where argument is an array
190184 // * array transformation (staticTargetType.isArray())
191185 // * constructor invocation
192- // * final GroovyCastException
193- castToTypeFallBack ();
186+ // * throw GroovyCastException
187+ if (handle == null ) {
188+ handle = MethodHandles .insertArguments (DTT_CAST_TO_TYPE , 1 , staticTargetType );
189+ }
194190
195- if (!handle .type ().equals (callSite .type ())) castAndSetGuards ();
191+ if (!handle .type ().equals (callSite .type ())) {
192+ castAndSetGuards ();
193+ }
196194 }
197195
198196 private void castAndSetGuards () {
@@ -202,62 +200,34 @@ private void castAndSetGuards() {
202200 }
203201
204202 private void handleNullWithoutBoolean () {
205- if (handle != null || args [0 ] != null ) return ;
206-
207- if ( staticTargetType . isPrimitive ()) {
208- handle = MethodHandles . insertArguments ( GROOVY_CAST_EXCEPTION , 1 , staticTargetType );
209- // need to call here because we used the static target type
210- // it won't be done otherwise because handle.type() == callSite.type()
211- castAndSetGuards ();
212- } else {
213- handle = MethodHandles . identity ( staticSourceType );
203+ if (args [0 ] == null ) {
204+ if ( staticTargetType . isPrimitive ()) {
205+ handle = MethodHandles . insertArguments ( GROOVY_CAST_EXCEPTION , 1 , staticTargetType );
206+ // need to call here because we used the static target type
207+ // it won't be done otherwise because handle. type() == callSite.type()
208+ castAndSetGuards ();
209+ } else {
210+ handle = MethodHandles . identity ( staticSourceType );
211+ }
214212 }
215213 }
216214
217- private void handleInstanceCase () {
218- if (handle != null ) return ;
219-
215+ private void handleIsAnInstance () {
220216 if (staticTargetType .isAssignableFrom (args [0 ].getClass ())) {
221217 handle = MethodHandles .identity (staticSourceType );
222218 }
223219 }
224220
225- private static boolean isAbstractClassOf (Class <?> toTest , Class <?> givenOnCallSite ) {
226- if (!toTest .isAssignableFrom (givenOnCallSite )) return false ;
227- if (givenOnCallSite .isInterface ()) return true ;
228- return Modifier .isAbstract (givenOnCallSite .getModifiers ());
229- }
230-
231- private void handleCollections () {
232- if (handle != null ) return ;
233-
234- if (!(args [0 ] instanceof Collection )) return ;
235- if (isAbstractClassOf (HashSet .class , staticTargetType )) {
236- handle = HASHSET_CONSTRUCTOR ;
237- } else if (isAbstractClassOf (ArrayList .class , staticTargetType )) {
238- handle = ARRAYLIST_CONSTRUCTOR ;
239- }
240- }
241-
242221 private void handleSAM () {
243- if (handle != null ) return ;
244-
245- if (!(args [0 ] instanceof Closure )) return ;
246- Method m = CachedSAMClass .getSAMMethod (staticTargetType );
247- if (m == null ) return ;
248- //TODO: optimize: add guard based on type Closure
249- handle = MethodHandles .insertArguments (SAM_CONVERSION , 1 , m , staticTargetType );
250- }
251-
252- private void castToTypeFallBack () {
253- if (handle != null ) return ;
254-
255- // generic fallback to castToType
256- handle = MethodHandles .insertArguments (DTT_CAST_TO_TYPE , 1 , staticTargetType );
222+ if (args [0 ] instanceof Closure ) {
223+ Method m = CachedSAMClass .getSAMMethod (staticTargetType );
224+ if (m == null ) return ;
225+ // TODO: optimize: add guard based on type Closure
226+ handle = MethodHandles .insertArguments (SAM_CONVERSION , 1 , m , staticTargetType );
227+ }
257228 }
258229
259230 private void handleBoolean () {
260- if (handle != null ) return ;
261231 boolean primitive = (staticTargetType == boolean .class );
262232 if (!primitive && staticTargetType != Boolean .class ) return ;
263233 // boolean->boolean, Boolean->boolean, boolean->Boolean are handled by the compiler
@@ -278,6 +248,24 @@ private void handleBoolean() {
278248
279249 handle = MethodHandles .guardWithTest (ifNull , thenZero , elseCallAsBoolean );
280250 }
251+
252+ /**
253+ * Sets handle if object is Collection and target type is an abstract
254+ * type fitting for HashSet or ArrayList.
255+ */
256+ private void handleCollections () {
257+ if (args [0 ] instanceof Collection ) {
258+ if (isAbstractClassOf (HashSet .class , staticTargetType )) {
259+ handle = HASHSET_CONSTRUCTOR ;
260+ } else if (isAbstractClassOf (ArrayList .class , staticTargetType )) {
261+ handle = ARRAYLIST_CONSTRUCTOR ;
262+ }
263+ }
264+ }
265+
266+ private static boolean isAbstractClassOf (final Class <?> type , final Class <?> callSiteType ) {
267+ return (callSiteType .isInterface () || Modifier .isAbstract (callSiteType .getModifiers ())) && type .isAssignableFrom (callSiteType );
268+ }
281269 }
282270
283271 private static class PropertySelector extends MethodSelector {
0 commit comments