3838import java .util .HashMap ;
3939import java .util .List ;
4040import java .util .Map ;
41+ import java .util .function .Consumer ;
4142import java .util .function .Function ;
4243import java .util .stream .Collectors ;
4344
6162import org .scijava .priority .Priority ;
6263import org .scijava .struct .FunctionalMethodType ;
6364import org .scijava .struct .ItemIO ;
65+ import org .scijava .types .Any ;
6466import org .scijava .types .Nil ;
6567import org .scijava .types .Types ;
6668import org .scijava .types .inference .GenericAssignability ;
@@ -117,63 +119,33 @@ public OpCandidate findMatch(MatchingConditions conditions, OpMatcher matcher,
117119 }
118120
119121 try {
120- // resolve adaptor dependencies
121- final Map <TypeVariable <?>, Type > adaptorBounds = new HashMap <>();
122- final Map <TypeVariable <?>, Type > dependencyBounds = new HashMap <>();
122+ // grab the first type parameter from the OpInfo and search for
123+ // an Op that will then be adapted (this will be the only input of the
124+ // adaptor since we know it is a Function)
125+ Type adaptFrom = adaptor .inputTypes ().get (0 );
126+ Type srcOpType = Types .substituteTypeVariables (adaptFrom , map );
127+ final OpRequest srcOpRequest = inferOpRequest (srcOpType , conditions
128+ .request ().getName (), map );
129+ final OpCandidate srcCandidate = matcher .match (MatchingConditions .from (
130+ srcOpRequest , adaptationHints ), env );
131+ // Then, once we've matched an Op, use the bounds of that match
132+ // to refine the bounds on the adaptor (for dependency matching)
133+ captureTypeVarsFromCandidate (adaptFrom , srcCandidate , map );
134+ // Finally, resolve the adaptor's dependencies
123135 List <InfoTree > depTrees = Infos .dependencies (adaptor ).stream () //
124136 .map (d -> {
125137 OpRequest request = inferOpRequest (d , map );
126138 Nil <?> type = Nil .of (request .getType ());
127139 Nil <?>[] args = Arrays .stream (request .getArgs ()).map (Nil ::of )
128140 .toArray (Nil []::new );
129141 Nil <?> outType = Nil .of (request .getOutType ());
130- InfoTree tree = env .infoTree (request .getName (), type , args , outType ,
142+ return env .infoTree (request .getName (), type , args , outType ,
131143 adaptationHints );
132- // Check if the bounds of the dependency can inform the type of the
133- // adapted Op
134- final Type matchedOpType = tree .info ().opType ();
135- // Find adaptor type variable bounds fulfilled by matched Op
136- GenericAssignability .inferTypeVariables ( //
137- new Type [] { d .getType () }, //
138- new Type [] { matchedOpType }, //
139- dependencyBounds //
140- );
141- for (TypeVariable <?> typeVar : map .keySet ()) {
142- // Ignore TypeVariables not present in this particular dependency
143- if (!dependencyBounds .containsKey (typeVar )) continue ;
144- Type matchedType = dependencyBounds .get (typeVar );
145- // Resolve any type variables from the dependency request that we
146- // can
147- GenericAssignability .inferTypeVariables ( //
148- new Type [] { request .getType () }, //
149- new Type [] { matchedOpType }, //
150- adaptorBounds //
151- );
152- Type mapped = Types .mapVarToTypes (matchedType , adaptorBounds );
153- // If the type variable is more specific now, update it
154- if (mapped != null && Types .isAssignable (mapped , map .get (
155- typeVar )))
156- {
157- map .put (typeVar , mapped );
158- }
159- }
160- dependencyBounds .clear ();
161- return tree ;
162144 }).collect (Collectors .toList ());
163- InfoTree adaptorChain = new InfoTree (adaptor , depTrees );
164-
165- // grab the first type parameter from the OpInfo and search for
166- // an Op that will then be adapted (this will be the only input of the
167- // adaptor since we know it is a Function)
168- Type srcOpType = Types .substituteTypeVariables (adaptor .inputs ().get (0 )
169- .getType (), map );
170- final OpRequest srcOpRequest = inferOpRequest (srcOpType , conditions
171- .request ().getName (), map );
172- final OpCandidate srcCandidate = matcher .match (MatchingConditions .from (
173- srcOpRequest , adaptationHints ), env );
174- map .putAll (srcCandidate .typeVarAssigns ());
145+ // And return the Adaptor, wrapped up into an OpCandidate
175146 Type adapterOpType = Types .substituteTypeVariables (adaptor .output ()
176147 .getType (), map );
148+ InfoTree adaptorChain = new InfoTree (adaptor , depTrees );
177149 OpAdaptationInfo adaptedInfo = new OpAdaptationInfo (srcCandidate
178150 .opInfo (), adapterOpType , adaptorChain );
179151 OpCandidate adaptedCandidate = new OpCandidate (env , conditions
@@ -196,6 +168,41 @@ public OpCandidate findMatch(MatchingConditions conditions, OpMatcher matcher,
196168 throw agglomerated ;
197169 }
198170
171+ /**
172+ * Helper method that captures all type variable mappings found in the search
173+ * for an Op that could satisfy an adaptor input {@code srcType}.
174+ *
175+ * @param srcType the type of the Op input to an adaptor
176+ * @param candidate the {@link OpCandidate} matched for the adaptor input
177+ * @param map the mapping
178+ */
179+ private void captureTypeVarsFromCandidate (Type srcType , OpCandidate candidate ,
180+ Map <TypeVariable <?>, Type > map )
181+ {
182+ Consumer <Map <TypeVariable <?>, Type >> typeVarConsumer = assigns -> {
183+ for (var key : assigns .keySet ()) {
184+ if (map .containsKey (key )) {
185+ var existing = map .get (key );
186+ var replacement = assigns .get (key );
187+ // Ignore bounds that are weaker than current bounds.
188+ if (Types .isAssignable (existing , replacement ) && !existing .equals (
189+ Any .class ) && !(existing instanceof Any ))
190+ {
191+ continue ;
192+ }
193+ }
194+ map .put (key , assigns .get (key ));
195+ }
196+ };
197+ // First, capture assignments between the Adaptor and the matched Op
198+ final Map <TypeVariable <?>, Type > srcBounds = new HashMap <>();
199+ GenericAssignability .inferTypeVariables (new Type [] { srcType }, new Type [] {
200+ candidate .getType () }, srcBounds );
201+ typeVarConsumer .accept (srcBounds );
202+ // Then, capture assignments between the original OpRef and the matched Op
203+ typeVarConsumer .accept (candidate .typeVarAssigns ());
204+ }
205+
199206 private OpRequest inferOpRequest (OpDependencyMember <?> dependency ,
200207 Map <TypeVariable <?>, Type > typeVarAssigns )
201208 {
0 commit comments