3030package org .scijava .ops .matcher ;
3131
3232import java .lang .reflect .Type ;
33+ import java .lang .reflect .TypeVariable ;
3334import java .util .ArrayList ;
3435import java .util .Collections ;
36+ import java .util .HashMap ;
3537import java .util .List ;
3638import java .util .function .Predicate ;
3739
4749import org .scijava .struct .Member ;
4850import org .scijava .struct .StructInstance ;
4951import org .scijava .util .Types ;
52+ import org .scijava .util .Types .TypeVarInfo ;
5053
5154/**
5255 * Default service for finding ops which match a request.
@@ -134,28 +137,11 @@ public StructInstance<?> match(final OpCandidate candidate) {
134137 */
135138 @ Override
136139 public boolean typesMatch (final OpCandidate candidate ) {
137- if (checkCandidates (Collections .singletonList (candidate )).isEmpty ())
138- return false ;
139- final Type [] refArgTypes = candidate .paddedArgs ();
140- final Type [] candidateArgTypes = OpUtils .inputTypes (candidate );
141-
142- if (refArgTypes == null )
143- return true ; // no constraints on output types
144-
145- if (candidateArgTypes .length < refArgTypes .length ) {
146- candidate .setStatus (StatusCode .TOO_FEW_ARGS );
147- return false ;
148- } else if (candidateArgTypes .length > refArgTypes .length ) {
149- candidate .setStatus (StatusCode .TOO_MANY_ARGS );
140+ HashMap <TypeVariable <?>, TypeVarInfo > typeBounds = new HashMap <>();
141+ if (!inputsMatch (candidate , typeBounds )) {
150142 return false ;
151143 }
152-
153- int conflictingIndex = Types .isApplicable (refArgTypes , candidateArgTypes );
154- if (conflictingIndex != -1 ) {
155- final Type to = refArgTypes [conflictingIndex ];
156- final Type from = candidateArgTypes [conflictingIndex ];
157- candidate .setStatus (StatusCode .ARG_TYPES_DO_NOT_MATCH , //
158- "request=" + to .getTypeName () + ", actual=" + from .getTypeName ());
144+ if (!outputsMatch (candidate , typeBounds )) {
159145 return false ;
160146 }
161147 candidate .setStatus (StatusCode .MATCH );
@@ -178,7 +164,7 @@ public boolean typesMatch(final OpCandidate candidate) {
178164 private List <OpCandidate > checkCandidates (final List <OpCandidate > candidates ) {
179165 final ArrayList <OpCandidate > validCandidates = new ArrayList <>();
180166 for (final OpCandidate candidate : candidates ) {
181- if (!isValid (candidate ) || ! outputsMatch ( candidate ) )
167+ if (!isValid (candidate ))
182168 continue ;
183169 final Type [] args = candidate .paddedArgs ();
184170 if (args == null )
@@ -323,14 +309,42 @@ private boolean isValid(final OpCandidate candidate) {
323309 return false ;
324310 }
325311
312+ private boolean inputsMatch (final OpCandidate candidate , HashMap <TypeVariable <?>, TypeVarInfo > typeBounds ) {
313+ if (checkCandidates (Collections .singletonList (candidate )).isEmpty ())
314+ return false ;
315+ final Type [] refArgTypes = candidate .paddedArgs ();
316+ final Type [] candidateArgTypes = OpUtils .inputTypes (candidate );
317+
318+ if (refArgTypes == null )
319+ return true ; // no constraints on output types
320+
321+ if (candidateArgTypes .length < refArgTypes .length ) {
322+ candidate .setStatus (StatusCode .TOO_FEW_ARGS );
323+ return false ;
324+ } else if (candidateArgTypes .length > refArgTypes .length ) {
325+ candidate .setStatus (StatusCode .TOO_MANY_ARGS );
326+ return false ;
327+ }
328+
329+ int conflictingIndex = Types .isApplicable (refArgTypes , candidateArgTypes , typeBounds );
330+ if (conflictingIndex != -1 ) {
331+ final Type to = refArgTypes [conflictingIndex ];
332+ final Type from = candidateArgTypes [conflictingIndex ];
333+ candidate .setStatus (StatusCode .ARG_TYPES_DO_NOT_MATCH , //
334+ "request=" + to .getTypeName () + ", actual=" + from .getTypeName ());
335+ return false ;
336+ }
337+ return true ;
338+ }
339+
326340 /**
327341 * Checks whether the output types of the candidate satisfy the output types of the {@link OpRef}.
328342 * Sets candidate status code if there are too many, to few, or not matching types.
329343 *
330344 * @param candidate the candidate to check outputs for
331345 * @return whether the output types are satisfied
332346 */
333- private boolean outputsMatch (final OpCandidate candidate ) {
347+ private boolean outputsMatch (final OpCandidate candidate , HashMap < TypeVariable <?>, TypeVarInfo > typeBounds ) {
334348 final Type [] refOutTypes = candidate .getRef ().getOutTypes ();
335349 if (refOutTypes == null )
336350 return true ; // no constraints on output types
@@ -344,7 +358,7 @@ private boolean outputsMatch(final OpCandidate candidate) {
344358 return false ;
345359 }
346360
347- int conflictingIndex = Types . isApplicable (candidateOutTypes , refOutTypes );
361+ int conflictingIndex = MatchingUtils . checkGenericOutputsAssignability (candidateOutTypes , refOutTypes , typeBounds );
348362 if (conflictingIndex != -1 ) {
349363 final Type to = refOutTypes [conflictingIndex ];
350364 final Type from = candidateOutTypes [conflictingIndex ];
0 commit comments