Background
MethodCheck can now tell which logical type a function belongs to (for example PyList_GetItem belongs to List). However, the generated code still attaches every such function to the physical base class Object:
//go:linkname IsTrue C.Py_IsTrue
func IsTrue(x *Object) c.Int
// llgo:link (*Object).IsTrue C.PyObject_IsTrue
func (self *Object) IsTrue() c.Int { return 0 }
// llgo:link (*Object).Item C.PyList_GetItem
func (self *Object) Item(index *Object) *Object { return self }
Methods of List, Dict, Float and the rest all end up on Object. That pollutes the API surface and invites method-name conflicts (PyList_GetItem and PyDict_GetItem would both want to be Item).
Goal
Put each method on its own logical class, and give users a way to get from the base class to a logical class.
Proposed behavior
-
Logical class. For a function whose MethodCheck result is List, emit the method on a new type List instead of on Object. The logical class embeds the base class, so everything defined on Object stays available on List.
-
Conversion method. For every generated logical class, add a conversion method on the base class named As<Class>, such as (*Object).AsList() *List. The conversion only reinterprets the pointer; it does not call into C and does not check the object's real type.
- The name is hard-coded as
As + class name for now.
- Later it can become configurable, with the default
"As$0", where $0 stands for the logical class name.
-
Lazy generation. A logical class is generated only when at least one function actually resolves to it. No methods, no class, no AsXxx.
-
Base class stays as is. When the logical type is the physical type itself (PyObject_IsTrue resolves to Object), the method stays on Object, and no class or AsObject is generated. Functions with an empty logical type (Py_IsTrue) remain plain package functions.
Expected output
type List struct {
Object
}
func (o *Object) AsList() *List { return (*List)(unsafe.Pointer(o)) }
// llgo:link (*List).Item C.PyList_GetItem
func (self *List) Item(index *Object) *Object { return nil }
Usage in XGo:
echo obj.AsList().Item(idx)
Notes and edge cases
- If a type with the logical class name already exists in the package (generated from the headers or provided through
TypeAlias), reuse it instead of generating a second one, and still add AsXxx when it is missing.
- If
As<Class> collides with an existing method on the base class, keep the existing method and report a diagnostic.
- Generation order must be deterministic so the output is stable across runs.
Acceptance criteria
Out of scope
- Making the conversion method name configurable (planned follow-up, default
"As$0").
- Runtime type checking in
AsXxx.
Background
MethodCheckcan now tell which logical type a function belongs to (for examplePyList_GetItembelongs toList). However, the generated code still attaches every such function to the physical base classObject:Methods of
List,Dict,Floatand the rest all end up onObject. That pollutes the API surface and invites method-name conflicts (PyList_GetItemandPyDict_GetItemwould both want to beItem).Goal
Put each method on its own logical class, and give users a way to get from the base class to a logical class.
Proposed behavior
Logical class. For a function whose
MethodCheckresult isList, emit the method on a new typeListinstead of onObject. The logical class embeds the base class, so everything defined onObjectstays available onList.Conversion method. For every generated logical class, add a conversion method on the base class named
As<Class>, such as(*Object).AsList() *List. The conversion only reinterprets the pointer; it does not call into C and does not check the object's real type.As+ class name for now."As$0", where$0stands for the logical class name.Lazy generation. A logical class is generated only when at least one function actually resolves to it. No methods, no class, no
AsXxx.Base class stays as is. When the logical type is the physical type itself (
PyObject_IsTrueresolves toObject), the method stays onObject, and no class orAsObjectis generated. Functions with an empty logical type (Py_IsTrue) remain plain package functions.Expected output
Usage in XGo:
Notes and edge cases
TypeAlias), reuse it instead of generating a second one, and still addAsXxxwhen it is missing.As<Class>collides with an existing method on the base class, keep the existing method and report a diagnostic.Acceptance criteria
PyList_GetItemis emitted as a method ofList, notObject.ObjectgetsAsList()only becauseListhas at least one method.AsXxx.PyObject_IsTruestays onObjectwith noAsObject;Py_IsTruestays a package function.cl/_testpy(or equivalent) covers the three functions above, plus a name-collision case such asPyDict_GetItem.Out of scope
"As$0").AsXxx.