@@ -93,6 +93,10 @@ pub type CompiledChild {
9393 is_derived_constructor : Bool ,
9494 is_generator : Bool ,
9595 is_async : Bool ,
96+ /// Stored [[Construct]] capability: True for normal functions and class
97+ /// constructors; False for arrows, generators, async, and methods /
98+ /// getters / setters. (cf. QuickJS `is_constructor` / JSC `ConstructAbility`.)
99+ is_constructor : Bool ,
96100 /// True if this function contains a syntactic `eval(...)` call with
97101 /// identifier callee. Such functions get all locals boxed and a
98102 /// name→index table stored on FuncTemplate so direct eval can see them.
@@ -1026,6 +1030,8 @@ fn collect_hoisted_funcs(
10261030 False ,
10271031 is_gen ,
10281032 is_async ,
1033+ // Function declaration: a constructor unless gen/async.
1034+ ! is_gen && ! is_async ,
10291035 )
10301036 let # ( e , idx ) = add_child_function ( e , child )
10311037 # ( e , [ # ( name , idx ) , .. funcs ] )
@@ -1287,6 +1293,7 @@ fn compile_function_body(
12871293 is_arrow : Bool ,
12881294 is_generator : Bool ,
12891295 is_async : Bool ,
1296+ is_constructor : Bool ,
12901297) -> CompiledChild {
12911298 let stmts = case body {
12921299 ast . BlockStatement ( s ) -> s
@@ -1429,6 +1436,7 @@ fn compile_function_body(
14291436 is_derived_constructor : False ,
14301437 is_generator : ,
14311438 is_async : ,
1439+ is_constructor : ,
14321440 has_eval_call : e . has_eval_call ,
14331441 references_this : e . references_this ,
14341442 )
@@ -2398,7 +2406,17 @@ fn emit_expr(e: Emitter, expr: ast.Expression) -> Result(Emitter, EmitError) {
23982406 // Function expression
23992407 ast . FunctionExpression ( name , params , body , is_gen , is_async ) -> {
24002408 let child =
2401- compile_function_body ( e , name , params , body , False , is_gen , is_async )
2409+ compile_function_body (
2410+ e ,
2411+ name ,
2412+ params ,
2413+ body ,
2414+ False ,
2415+ is_gen ,
2416+ is_async ,
2417+ // Normal function expression: a constructor unless gen/async.
2418+ ! is_gen && ! is_async ,
2419+ )
24022420 let # ( e , idx ) = add_child_function ( e , child )
24032421 Ok ( emit_ir ( e , IrMakeClosure ( idx ) ) )
24042422 }
@@ -2411,7 +2429,16 @@ fn emit_expr(e: Emitter, expr: ast.Expression) -> Result(Emitter, EmitError) {
24112429 ast . ArrowBodyBlock ( stmt ) -> stmt
24122430 }
24132431 let child =
2414- compile_function_body ( e , None , params , body_stmt , True , False , is_async )
2432+ compile_function_body (
2433+ e ,
2434+ None ,
2435+ params ,
2436+ body_stmt ,
2437+ True ,
2438+ False ,
2439+ is_async ,
2440+ False ,
2441+ )
24152442 let # ( e , idx ) = add_child_function ( e , child )
24162443 Ok ( emit_ir ( e , IrMakeClosure ( idx ) ) )
24172444 }
@@ -2693,6 +2720,8 @@ fn emit_named_expr(
26932720 False ,
26942721 is_gen ,
26952722 is_async ,
2723+ // Named function expression: a constructor unless gen/async.
2724+ ! is_gen && ! is_async ,
26962725 )
26972726 let # ( e , idx ) = add_child_function ( e , child )
26982727 Ok ( emit_ir ( e , IrMakeClosure ( idx ) ) )
@@ -2713,6 +2742,8 @@ fn emit_named_expr(
27132742 True ,
27142743 False ,
27152744 is_async ,
2745+ // Arrow function — not a constructor.
2746+ False ,
27162747 )
27172748 let # ( e , idx ) = add_child_function ( e , child )
27182749 Ok ( emit_ir ( e , IrMakeClosure ( idx ) ) )
@@ -2727,6 +2758,36 @@ fn emit_named_expr(
27272758
27282759/// Emit one property in an object literal. Object is already on the stack.
27292760/// All handlers leave the object on the stack for the next property.
2761+ /// Compile an object-literal *method* value — a concise method, getter, or
2762+ /// setter — so it is NOT a constructor (methods/accessors have no
2763+ /// [[Construct]], so `new o.m()` must throw). These values are always
2764+ /// FunctionExpressions; fall back defensively for anything unexpected.
2765+ fn emit_method_value (
2766+ e : Emitter ,
2767+ value : ast . Expression ,
2768+ name : Option ( String ) ,
2769+ ) -> Result ( Emitter , EmitError ) {
2770+ case value {
2771+ ast . FunctionExpression ( _ , params , body , is_gen , is_async ) -> {
2772+ let child =
2773+ compile_function_body (
2774+ e ,
2775+ name ,
2776+ params ,
2777+ body ,
2778+ False ,
2779+ is_gen ,
2780+ is_async ,
2781+ // method / getter / setter — not a constructor
2782+ False ,
2783+ )
2784+ let # ( e , idx ) = add_child_function ( e , child )
2785+ Ok ( emit_ir ( e , IrMakeClosure ( idx ) ) )
2786+ }
2787+ _ -> emit_expr ( e , value )
2788+ }
2789+ }
2790+
27302791fn emit_object_property (
27312792 e : Emitter ,
27322793 prop : ast . Property ,
@@ -2739,16 +2800,22 @@ fn emit_object_property(
27392800 value : ,
27402801 kind : ast . Init ,
27412802 computed : False ,
2803+ method : ,
27422804 .. ,
27432805 )
27442806 | ast . Property (
27452807 key : ast . StringExpression ( name ) ,
27462808 value : ,
27472809 kind : ast . Init ,
27482810 computed : False ,
2811+ method : ,
27492812 .. ,
27502813 ) -> {
2751- use e <- result . map ( emit_named_expr ( e , value , name ) )
2814+ // `{ m() {} }` is a method (not a constructor); `{ x: v }` is data.
2815+ use e <- result . map ( case method {
2816+ True -> emit_method_value ( e , value , Some ( name ) )
2817+ False -> emit_named_expr ( e , value , name )
2818+ } )
27522819 emit_ir ( e , IrDefineField ( name ) )
27532820 }
27542821
@@ -2760,19 +2827,26 @@ fn emit_object_property(
27602827 value : ,
27612828 kind : ast . Init ,
27622829 computed : False ,
2830+ method : ,
27632831 .. ,
27642832 ) -> {
27652833 let e = push_const ( e , JsNumber ( Finite ( n ) ) )
2766- use e <- result . map ( emit_expr ( e , value ) )
2834+ use e <- result . map ( case method {
2835+ True -> emit_method_value ( e , value , None )
2836+ False -> emit_expr ( e , value )
2837+ } )
27672838 emit_ir ( e , IrDefineFieldComputed )
27682839 }
27692840
27702841 // Computed key: {[expr]: value}
27712842 // Emit key, emit value, IrDefineFieldComputed — pops both, keeps obj.
27722843 // The VM handles ToPropertyKey (Symbol preserved, else ToString).
2773- ast . Property ( key : , value : , kind : ast . Init , computed : True , .. ) -> {
2844+ ast . Property ( key : , value : , kind : ast . Init , computed : True , method : , .. ) -> {
27742845 use e <- result . try ( emit_expr ( e , key ) )
2775- use e <- result . map ( emit_expr ( e , value ) )
2846+ use e <- result . map ( case method {
2847+ True -> emit_method_value ( e , value , None )
2848+ False -> emit_expr ( e , value )
2849+ } )
27762850 emit_ir ( e , IrDefineFieldComputed )
27772851 }
27782852
@@ -2800,7 +2874,7 @@ fn emit_object_property(
28002874 computed : False ,
28012875 .. ,
28022876 ) -> {
2803- use e <- result . map ( emit_named_expr ( e , value , "get " <> name ) )
2877+ use e <- result . map ( emit_method_value ( e , value , Some ( "get " <> name ) ) )
28042878 emit_ir ( e , IrDefineAccessor ( name , opcode . Getter ) )
28052879 }
28062880
@@ -2819,20 +2893,20 @@ fn emit_object_property(
28192893 computed : False ,
28202894 .. ,
28212895 ) -> {
2822- use e <- result . map ( emit_named_expr ( e , value , "set " <> name ) )
2896+ use e <- result . map ( emit_method_value ( e , value , Some ( "set " <> name ) ) )
28232897 emit_ir ( e , IrDefineAccessor ( name , opcode . Setter ) )
28242898 }
28252899
28262900 // Computed or exotic-key getter/setter: { get [expr]() {} }
28272901 // Stack: emit key, emit fn → DefineAccessorComputed
28282902 ast . Property ( key : , value : , kind : ast . Get , .. ) -> {
28292903 use e <- result . try ( emit_expr ( e , key ) )
2830- use e <- result . map ( emit_expr ( e , value ) )
2904+ use e <- result . map ( emit_method_value ( e , value , None ) )
28312905 emit_ir ( e , IrDefineAccessorComputed ( opcode . Getter ) )
28322906 }
28332907 ast . Property ( key : , value : , kind : ast . Set , .. ) -> {
28342908 use e <- result . try ( emit_expr ( e , key ) )
2835- use e <- result . map ( emit_expr ( e , value ) )
2909+ use e <- result . map ( emit_method_value ( e , value , None ) )
28362910 emit_ir ( e , IrDefineAccessorComputed ( opcode . Setter ) )
28372911 }
28382912
@@ -4152,6 +4226,8 @@ fn compile_derived_class(
41524226 False ,
41534227 False ,
41544228 False ,
4229+ // Class constructor — IS a constructor.
4230+ True ,
41554231 )
41564232 // Mark as derived constructor
41574233 let child = CompiledChild ( .. child , is_derived_constructor : True )
@@ -4236,6 +4312,8 @@ fn emit_class_methods(
42364312 False ,
42374313 is_gen ,
42384314 is_async ,
4315+ // Class method / getter / setter — not a constructor.
4316+ False ,
42394317 )
42404318 let # ( e , idx ) = add_child_function ( e , child )
42414319 let e = emit_ir ( e , IrMakeClosure ( idx ) )
@@ -4287,7 +4365,17 @@ fn emit_computed_class_method(
42874365 }
42884366 use e <- result . try ( emit_expr ( e , key ) )
42894367 let child =
4290- compile_function_body ( e , None , params , body , False , is_gen , is_async )
4368+ compile_function_body (
4369+ e ,
4370+ None ,
4371+ params ,
4372+ body ,
4373+ False ,
4374+ is_gen ,
4375+ is_async ,
4376+ // Computed class method / getter / setter — not a constructor.
4377+ False ,
4378+ )
42914379 let # ( e , idx ) = add_child_function ( e , child )
42924380 let e = emit_ir ( e , IrMakeClosure ( idx ) )
42934381 let e = case kind {
@@ -4410,6 +4498,8 @@ fn compile_base_class(
44104498 False ,
44114499 False ,
44124500 False ,
4501+ // Class constructor — IS a constructor.
4502+ True ,
44134503 )
44144504 let # ( e , ctor_idx ) = add_child_function ( e , child )
44154505
0 commit comments