1414
1515package net .starlark .java .eval ;
1616
17+ import static com .google .common .collect .ImmutableSet .toImmutableSet ;
1718import static java .util .Arrays .stream ;
1819
1920import com .google .common .base .Preconditions ;
2324import com .google .errorprone .annotations .CheckReturnValue ;
2425import java .lang .reflect .InvocationTargetException ;
2526import java .lang .reflect .Method ;
27+ import java .lang .reflect .ParameterizedType ;
28+ import java .lang .reflect .Type ;
29+ import java .math .BigInteger ;
2630import java .util .Arrays ;
2731import javax .annotation .Nullable ;
2832import net .starlark .java .annot .Param ;
@@ -141,7 +145,7 @@ private MethodDescriptor(
141145
142146 private StarlarkType buildStarlarkType () {
143147 if (getAnnotation ().structField ()) {
144- StarlarkType returnType = TypeChecker . fromJava (getMethod ().getGenericReturnType ());
148+ StarlarkType returnType = starlarkTypeFromJava (getMethod ().getGenericReturnType ());
145149 if (allowReturnNones ) {
146150 returnType = Types .union (returnType , Types .NONE );
147151 }
@@ -169,9 +173,9 @@ private StarlarkType buildStarlarkType() {
169173 ParamType [] allowedTypes = annotation .parameters ()[i ].allowedTypes ();
170174 // User supplied type
171175 if (allowedTypes .length > 0 ) {
172- parameterTypes .add (TypeChecker . fromAnnotation (allowedTypes ));
176+ parameterTypes .add (starlarkTypeFromAnnotation (allowedTypes ));
173177 } else {
174- parameterTypes .add (TypeChecker . fromJava (method .getGenericParameterTypes ()[i ]));
178+ parameterTypes .add (starlarkTypeFromJava (method .getGenericParameterTypes ()[i ]));
175179 }
176180 if (parameters [i ].getDefaultValue () == null ) {
177181 mandatoryParameters .add (parameters [i ].getName ());
@@ -181,7 +185,7 @@ private StarlarkType buildStarlarkType() {
181185 if (getMethod ().getReturnType () == Object .class ) {
182186 returnType = Types .ANY ;
183187 } else {
184- returnType = TypeChecker . fromJava (getMethod ().getGenericReturnType ());
188+ returnType = starlarkTypeFromJava (getMethod ().getGenericReturnType ());
185189 if (allowReturnNones ) {
186190 returnType = Types .union (returnType , Types .NONE );
187191 }
@@ -199,6 +203,79 @@ private StarlarkType buildStarlarkType() {
199203 returnType );
200204 }
201205
206+ private static class ParameterizedTypeImpl implements ParameterizedType {
207+ private final Type rawType ;
208+ private final Type [] actualTypeArguments ;
209+
210+ private ParameterizedTypeImpl (Type rawType , Type [] actualTypeArguments ) {
211+ this .rawType = rawType ;
212+ this .actualTypeArguments = actualTypeArguments ;
213+ }
214+
215+ @ Override
216+ public Type [] getActualTypeArguments () {
217+ return actualTypeArguments ;
218+ }
219+
220+ @ Override
221+ public Type getRawType () {
222+ return rawType ;
223+ }
224+
225+ @ Override
226+ public Type getOwnerType () {
227+ return null ;
228+ }
229+ }
230+
231+ static StarlarkType starlarkTypeFromAnnotation (ParamType [] paramTypes ) {
232+ return Types .union (
233+ Arrays .stream (paramTypes )
234+ .map (
235+ paramType -> {
236+ if (paramType .type ().getTypeParameters ().length == 1 ) {
237+ return new ParameterizedTypeImpl (
238+ paramType .type (), new Type [] {paramType .generic1 ()});
239+ } else {
240+ return paramType .type ();
241+ }
242+ })
243+ .map (MethodDescriptor ::starlarkTypeFromJava )
244+ .collect (toImmutableSet ()));
245+ }
246+
247+ /** Returns the Starlark type corresponding to the given Java type. */
248+ static StarlarkType starlarkTypeFromJava (Type cls ) {
249+ if (cls == NoneType .class || cls == void .class ) {
250+ return Types .NONE ;
251+ } else if (cls == String .class ) {
252+ return Types .STR ;
253+ } else if (cls == Boolean .class || cls == boolean .class ) {
254+ return Types .BOOL ;
255+ } else if (cls == int .class
256+ || cls == long .class
257+ || cls == Integer .class
258+ || cls == Long .class
259+ || cls == StarlarkInt .class
260+ || (cls instanceof Class <?> c && BigInteger .class .isAssignableFrom (c ))) {
261+ return Types .INT ;
262+ } else if (cls == double .class || cls == Double .class || cls == StarlarkFloat .class ) {
263+ return Types .FLOAT ;
264+ } else if (cls instanceof ParameterizedType ptype && ptype .getRawType () == StarlarkList .class ) {
265+ return Types .list (starlarkTypeFromJava (ptype .getActualTypeArguments ()[0 ]));
266+ } else if (cls instanceof ParameterizedType ptype
267+ && ptype .getRawType () == StarlarkIterable .class ) {
268+ return Types .collection (starlarkTypeFromJava (ptype .getActualTypeArguments ()[0 ]));
269+ } else if (cls instanceof ParameterizedType ptype && ptype .getRawType () == Sequence .class ) {
270+ return Types .sequence (starlarkTypeFromJava (ptype .getActualTypeArguments ()[0 ]));
271+ } else if (cls == Object .class || cls == StarlarkValue .class ) {
272+ return Types .OBJECT ;
273+ } else {
274+ // TODO(ilist@): handle more complex types
275+ return Types .ANY ;
276+ }
277+ }
278+
202279 private static boolean paramUsableAsPositionalWithoutChecks (ParamDescriptor param ) {
203280 return param .isPositional ()
204281 && param .conditionalCheck == null
0 commit comments