@@ -120,30 +120,68 @@ private static Type generateOpType(OpInfo info,
120120 List <RichOp <Function <?, ?>>> preconverter ,
121121 RichOp <Function <?, ?>> postconverter )
122122 {
123- Type [] inTypes = inTypes (info .inputTypes ().toArray (Type []::new ),
124- preconverter );
123+ Type [] inTypes = inTypes (info .inputTypes (), preconverter );
125124 Type outType = outType (info .outputType (), postconverter );
126125 Class <?> fIface = FunctionalInterfaces .findFrom (info .opType ());
127126 return retypeOpType (fIface , inTypes , outType );
128127 }
129128
130- public ConvertedOpInfo (OpInfo info , Type opType ,
131- List <RichOp <Function <?, ?>>> preconverters ,
132- RichOp <Function <?, ?>> postconverter ,
133- final RichOp <Computers .Arity1 <?, ?>> copyOp , OpEnvironment env )
134- {
129+ public ConvertedOpInfo ( //
130+ OpInfo info , //
131+ Type opType , //
132+ List <RichOp <Function <?, ?>>> preconverters , //
133+ RichOp <Function <?, ?>> postconverter , //
134+ final RichOp <Computers .Arity1 <?, ?>> copyOp , //
135+ OpEnvironment env //
136+ ) {
135137 this .info = info ;
136138 this .opType = opType ;
137139 this .preconverters = preconverters ;
138140 this .postconverter = postconverter ;
139141 this .copyOp = copyOp ;
140142 this .env = env ;
143+ this .struct = generateStruct ( //
144+ info , //
145+ opType , //
146+ preconverters , //
147+ postconverter //
148+ );
149+ this .hints = info .declaredHints ().plus ( //
150+ BaseOpHints .Conversion .FORBIDDEN , //
151+ "converted" //
152+ );
153+ }
141154
142- Type [] inTypes = inTypes (info .inputTypes ().toArray (Type []::new ),
143- preconverters );
155+ /**
156+ * Helper method to generate the new {@link Struct}
157+ *
158+ * @param info the original {@link OpInfo}
159+ * @param opType the new Op's {@link Type}
160+ * @param preconverters the {@link Function}s responsible for converting Op
161+ * parameters
162+ * @param postconverter the {@link Function} responsible for converting the
163+ * Op's return
164+ * @return the {@link Struct} of the converted Op
165+ */
166+ private static Struct generateStruct (OpInfo info , Type opType ,
167+ List <RichOp <Function <?, ?>>> preconverters ,
168+ RichOp <Function <?, ?>> postconverter )
169+ {
170+ List <Type > originalIns = new ArrayList <>(info .inputTypes ());
171+ List <Member <?>> ioMembers = new ArrayList <>(info .struct ().members ());
172+ // If the mutable index differs between the declared Op type and the
173+ // requested Op type, we must move the IO memberr
174+ int fromIOIdx = Conversions .mutableIndexOf (Types .raw (info .opType ()));
175+ int toIOIdx = Conversions .mutableIndexOf (Types .raw (opType ));
176+ if (fromIOIdx != toIOIdx ) {
177+ originalIns .add (toIOIdx , originalIns .remove (fromIOIdx ));
178+ ioMembers .add (toIOIdx , ioMembers .remove (fromIOIdx ));
179+ }
180+ // Determine the new input and output types of the Op
181+ Type [] inTypes = inTypes (originalIns , preconverters );
144182 Type outType = outType (info .outputType (), postconverter );
145183
146- List < Member <?>> ioMembers = info . struct (). members ();
184+ // Create the functional member types of the new OpInfo
147185 int index = 0 ;
148186 List <FunctionalMethodType > fmts = new ArrayList <>();
149187 for (Member <?> m : ioMembers ) {
@@ -152,12 +190,9 @@ public ConvertedOpInfo(OpInfo info, Type opType,
152190 : null ;
153191 fmts .add (new FunctionalMethodType (newType , m .getIOType ()));
154192 }
155- // generate new output fmt
193+ // generate new struct
156194 RetypingRequest r = new RetypingRequest (info .struct (), fmts );
157- this .struct = Structs .from (r , opType , new OpRetypingMemberParser ());
158-
159- this .hints = info .declaredHints ().plus (BaseOpHints .Conversion .FORBIDDEN ,
160- "converted" );
195+ return Structs .from (r , opType , new OpRetypingMemberParser ());
161196 }
162197
163198 public OpInfo srcInfo () {
@@ -310,28 +345,32 @@ public String id() {
310345 return sb .toString ();
311346 }
312347
313- private static Type [] inTypes (Type [] originalInputs ,
314- List <RichOp <Function <?, ?>>> inputFocusers )
348+ private static Type [] inTypes (List < Type > originalInputs ,
349+ List <RichOp <Function <?, ?>>> preconverters )
315350 {
316351 Map <TypeVariable <?>, Type > typeAssigns = new HashMap <>();
317- Type [] inTypes = new Type [originalInputs .length ];
318- // NB: This feels kind of inefficient, but we have to do each individually
319- // to avoid the case that the same Op is being used for different types.
320- // Here's one use edge case - suppose the Op Identity<T> maps A, B, and C.
321- // The new inTypes should thus be A, B, and C, but if we do them all
322- // together we'll get inTypes Object from the output of the focusers, as
323- // there's only one type variable to map across the three inputs.
324- for (int i = 0 ; i < originalInputs .length ; i ++) {
352+ Type [] inTypes = new Type [originalInputs .size ()];
353+ for (int i = 0 ; i < originalInputs .size (); i ++) {
325354 typeAssigns .clear ();
326- if (inputFocusers .get (i ) == null ) {
327- inTypes [i ] = originalInputs [i ];
328- }
329- else {
330- var info = Ops .info (inputFocusers .get (i ));
331- GenericAssignability .inferTypeVariables (new Type [] { info
332- .outputType () }, new Type [] { originalInputs [i ] }, typeAssigns );
333- inTypes [i ] = Types .mapVarToTypes (info .inputTypes ().get (0 ), typeAssigns );
355+ // Start by looking at the input type T of the preconverter
356+ var type = preconverters .get (i ).instance ().getType ();
357+ var pType = (ParameterizedType ) type ;
358+ inTypes [i ] = pType .getActualTypeArguments ()[0 ];
359+ // Sometimes, the type of the Op instance can contain wildcards.
360+ // These do not help us in determining the new type, so we have to
361+ // start over with the input converter input type.
362+ if (inTypes [i ] instanceof WildcardType ) {
363+ inTypes [i ] = Ops .info (preconverters .get (i )).inputTypes ().get (0 );
334364 }
365+ // Infer type variables in the preconverter input w.r.t. the
366+ // parameter types of the ORIGINAL OpInfo
367+ GenericAssignability .inferTypeVariables ( //
368+ new Type [] { pType .getActualTypeArguments ()[1 ] }, //
369+ new Type [] { originalInputs .get (i ) }, //
370+ typeAssigns //
371+ );
372+ // Map type variables in T to Types inferred above
373+ inTypes [i ] = Types .mapVarToTypes (inTypes [i ], typeAssigns );
335374 }
336375 return inTypes ;
337376 }
@@ -340,14 +379,26 @@ private static Type outType( //
340379 Type originalOutput , //
341380 RichOp <Function <?, ?>> postconverter //
342381 ) {
343- Map <TypeVariable <?>, Type > typeAssigns = new HashMap <>();
382+ // Start by looking at the output type T of the postconverter
383+ var type = postconverter .instance ().getType ();
384+ var pType = (ParameterizedType ) type ;
385+ Type outType = pType .getActualTypeArguments ()[1 ];
386+ // Sometimes, the type of the Op instance can contain wildcards.
387+ // These do not help us in determining the new type, so we have to
388+ // start over with the postconverter's output type.
389+ if (outType instanceof WildcardType ) {
390+ outType = Ops .info (postconverter ).outputType ();
391+ }
392+ Map <TypeVariable <?>, Type > vars = new HashMap <>();
393+ // Infer type variables in the postconverter input w.r.t. the
394+ // parameter types of the ORIGINAL OpInfo
344395 GenericAssignability .inferTypeVariables ( //
345- new Type [] { Ops . info ( postconverter ). inputTypes (). get ( 0 ) }, //
396+ new Type [] { pType . getActualTypeArguments ()[ 0 ] }, //
346397 new Type [] { originalOutput }, //
347- typeAssigns //
398+ vars //
348399 );
349- return Types . mapVarToTypes ( Ops . info ( postconverter ). outputType (),
350- typeAssigns );
400+ // map type variables in T to Types inferred in Step 2a
401+ return Types . mapVarToTypes ( outType , vars );
351402 }
352403
353404 @ Override
0 commit comments