@@ -2754,6 +2754,11 @@ partial def evalSubscriptValue (obj idx : Value) : InterpM Value := do
27542754 match cd.ns["__class_getitem__" ]? with
27552755 | some fn => callValueDispatch fn [idx] []
27562756 | none => return .none -- default: subscripting a class returns .none (for typing)
2757+ | .builtin name =>
2758+ -- Allow subscripting on builtin type names for type annotations (list[ int ] , dict[str, int], etc.)
2759+ match name with
2760+ | "list" | "dict" | "set" | "tuple" | "frozenset" | "type" => return .none
2761+ | _ => throwTypeError s! "'{ typeName obj} ' object is not subscriptable"
27572762 | _ => throwTypeError s! "'{ typeName obj} ' object is not subscriptable"
27582763
27592764-- Assignment target resolution
@@ -2979,30 +2984,37 @@ partial def getBuiltinModule (name : String) : InterpM (Option Value) := do
29792984 -- Stub common typing names as none so imports don't fail
29802985 for n in ["Any" , "Optional" , "List" , "Dict" , "Set" , "Tuple" , "FrozenSet" ,
29812986 "Self" , "Union" , "Callable" , "Protocol" ,
2982- "runtime_checkable" , " NamedTuple" ,
2987+ "NamedTuple" ,
29832988 "NoReturn" , "SupportsInt" , "SupportsIndex" ,
29842989 "TypeAlias" , "Literal" , "IO" , "Sequence" , "Mapping" ,
29852990 "Iterator" , "Iterable" , "Generator" , "Coroutine" ,
29862991 "Awaitable" , "AsyncIterator" , "AsyncGenerator" ,
29872992 "Type" , "Generic" , "Annotated" ,
2988- "overload" , "cast" , " no_type_check" ] do
2993+ "no_type_check" ] do
29892994 ns := ns.insert n .none
29902995 -- ClassVar and Final are distinct markers (not .none) so Pydantic can skip them
29912996 ns := ns.insert "ClassVar" (.builtin "typing.ClassVar" )
29922997 ns := ns.insert "Final" (.builtin "typing.Final" )
29932998 -- TypeVar is callable (returns .none as a stub type variable)
29942999 ns := ns.insert "TypeVar" (.builtin "typing.TypeVar" )
2995- -- override is a callable identity decorator (not .none )
3000+ -- Identity decorators (return their argument unchanged )
29963001 ns := ns.insert "override" (.builtin "typing.override" )
3002+ ns := ns.insert "overload" (.builtin "typing.overload" )
3003+ ns := ns.insert "runtime_checkable" (.builtin "typing.runtime_checkable" )
3004+ -- cast(type, value) returns the value unchanged
3005+ ns := ns.insert "cast" (.builtin "typing.cast" )
29973006 some <$> mkMod ns
29983007 | "typing_extensions" =>
29993008 -- Alias for typing for compatibility
30003009 let mut ns : Std.HashMap String Value := {}
30013010 ns := ns.insert "TYPE_CHECKING" (.bool false )
3002- for n in ["Self" , "Protocol" , "runtime_checkable" ,
3011+ for n in ["Self" , "Protocol" ,
30033012 "Annotated" , "TypeAlias" , "get_type_hints" ] do
30043013 ns := ns.insert n .none
30053014 ns := ns.insert "override" (.builtin "typing.override" )
3015+ ns := ns.insert "overload" (.builtin "typing.overload" )
3016+ ns := ns.insert "runtime_checkable" (.builtin "typing.runtime_checkable" )
3017+ ns := ns.insert "cast" (.builtin "typing.cast" )
30063018 some <$> mkMod ns
30073019 | "abc" => do
30083020 -- Create real ABC base class
@@ -3740,6 +3752,30 @@ partial def execStmt (s : Stmt) : InterpM Unit := do
37403752 let cd' ← heapGetClassData cref
37413753 heapSetClassData cref { cd' with mro := mro }
37423754 | _ => pure ()
3755+ -- Call __init_subclass__ on each direct base class (Python semantics)
3756+ for base in bases do
3757+ match base with
3758+ | .classObj bref => do
3759+ let bcd ← heapGetClassData bref
3760+ match bcd.ns["__init_subclass__" ]? with
3761+ | some fn => do
3762+ -- __init_subclass__ is a classmethod; call with the new class as cls
3763+ let actualFn := match fn with
3764+ | .classMethod inner => inner
3765+ | other => other
3766+ -- Inject __class__ into the function's scope for super() support
3767+ match actualFn with
3768+ | .function fref => do
3769+ let fd ← heapGetFunc fref
3770+ let scope ← bindFuncParams fd.params [classVal] [] fd.defaults fd.kwDefaults
3771+ let scopeWithClass := scope.insert "__class__" base
3772+ let _ ← callRegularFunc fd scopeWithClass
3773+ pure ()
3774+ | _ =>
3775+ let _ ← callValueDispatch actualFn [classVal] []
3776+ pure ()
3777+ | none => pure ()
3778+ | _ => pure ()
37433779 -- Post-process Pydantic BaseModel subclasses
37443780 let isPydanticModel ← isBaseModelSubclass bases.toArray
37453781 if isPydanticModel then
@@ -4165,14 +4201,28 @@ partial def callBoundMethod (receiver : Value) (method : String) (args : List Va
41654201 let args' ← if kwargs.isEmpty then pure args else
41664202 match method with
41674203 | "to_bytes" =>
4168- let length := kwargs.find? (·.1 == "length" ) |>.map (·.2 ) |>.getD (.int 1 )
4169- let byteorder := kwargs.find? (·.1 == "byteorder" ) |>.map (·.2 ) |>.getD (.str "big" )
4170- pure (args ++ [length, byteorder])
4204+ -- Support: .to_bytes(length, byteorder), .to_bytes(length, byteorder=...), .to_bytes(byteorder=..., length=...)
4205+ let posLength := args.head?
4206+ let length := posLength.orElse fun _ => (kwargs.find? (·.1 == "length" ) |>.map (·.2 ))
4207+ let posByteorder := if args.length > 1 then args.tail.head? else none
4208+ let byteorder := posByteorder.orElse fun _ => (kwargs.find? (·.1 == "byteorder" ) |>.map (·.2 ))
4209+ pure [length.getD (.int 1 ), byteorder.getD (.str "big" )]
41714210 | _ => pure args
41724211 callIntMethod n method args'
41734212 | .bytes b => callBytesMethod b method args
41744213 | .tuple arr => callTupleMethod arr method args
4175- | .builtin name => callBuiltinTypeMethod name method args
4214+ | .builtin name => do
4215+ -- Convert kwargs to positional for builtin type methods
4216+ let args' ← if kwargs.isEmpty then pure args else
4217+ match name, method with
4218+ | "int" , "from_bytes" =>
4219+ let posBytes := args.head?
4220+ let bytes_ := posBytes.orElse fun _ => (kwargs.find? (·.1 == "bytes" ) |>.map (·.2 ))
4221+ let posByteorder := if args.length > 1 then args.tail.head? else none
4222+ let byteorder := posByteorder.orElse fun _ => (kwargs.find? (·.1 == "byteorder" ) |>.map (·.2 ))
4223+ pure [bytes_.getD (.bytes ByteArray.empty), byteorder.getD (.str "big" )]
4224+ | _, _ => pure args
4225+ callBuiltinTypeMethod name method args'
41764226 | .generator ref => callGeneratorMethod ref method args
41774227 | .property getter setter deleter =>
41784228 match method with
@@ -4328,7 +4378,10 @@ partial def callBoundMethod (receiver : Value) (method : String) (args : List Va
43284378 -- Builtins in synthetic type classes: prepend inst (self/cls)
43294379 callValueDispatch fn (inst :: args) kwargs
43304380 | _ => callValueDispatch fn (inst :: args) kwargs
4331- | none => throwAttributeError s! "'super' object has no attribute '{ method} '"
4381+ | none =>
4382+ -- object.__init_subclass__ is a no-op in Python
4383+ if method == "__init_subclass__" then return .none
4384+ else throwAttributeError s! "'super' object has no attribute '{ method} '"
43324385 | _ => throwAttributeError s! "'super' object has no attribute '{ method} '"
43334386 | _ => throwAttributeError s! "'{ typeName receiver} ' object has no attribute '{ method} '"
43344387
0 commit comments