فهرست منبع

[js] fixed rest args in ctors for ES <= 5 (closes #10490)

Aleksandr Kuzmenko 3 سال پیش
والد
کامیت
a598963a57
2فایلهای تغییر یافته به همراه41 افزوده شده و 19 حذف شده
  1. 1 0
      extra/CHANGES.txt
  2. 40 19
      src/generators/genjs.ml

+ 1 - 0
extra/CHANGES.txt

@@ -3,6 +3,7 @@
 	Bugfixes:
 
 	all : fixed compiler crash in complex constraints chains (#10445)
+	js : fixed constructors with rest arguments when compiling for ES3, ES5 (#10490)
 	nullsafety : fixed false error on extern var fields without initialization (#10448)
 
 2021-10-22 4.2.4:

+ 40 - 19
src/generators/genjs.ml

@@ -424,22 +424,35 @@ let is_code_injection_function e =
 let var ctx =
 	if ctx.es_version >= 6 then "let" else "var"
 
-let rec gen_call ctx e el in_value =
-	let apply,el =
-		if ctx.es_version < 6 then
-			match List.rev el with
-			| [{ eexpr = TUnop (Spread,Ast.Prefix,rest) }] ->
-				true,[rest]
-			| { eexpr = TUnop (Spread,Ast.Prefix,rest) } :: args_rev ->
-				(* [arg1, arg2, ..., argN].concat(rest) *)
-				let arr = mk (TArrayDecl (List.rev args_rev)) t_dynamic null_pos in
-				let concat = mk (TField (arr, FDynamic "concat")) t_dynamic null_pos in
-				true,[mk (TCall (concat, [rest])) t_dynamic null_pos]
-			| _ ->
-				false,el
-		else
+(**
+	Returns `(needs_apply,element_list)` tuple where `needs_apply` indicates if
+	a call should be generated as `<function>.apply(<this>, element_list)` instead
+	of `<function>(el)`.
+
+	If `add_null_context` is provided then `element_list` will have `null` as the
+	first expr if needed.
+*)
+let apply_args ?(add_null_context=false) ctx el =
+	if ctx.es_version < 6 then
+		match List.rev el with
+		| [{ eexpr = TUnop (Spread,Ast.Prefix,rest) }] when not add_null_context ->
+			true,[rest]
+		| { eexpr = TUnop (Spread,Ast.Prefix,rest) } :: args_rev ->
+			(* [arg1, arg2, ..., argN].concat(rest) *)
+			let args =
+				if add_null_context then (null t_dynamic null_pos) :: List.rev args_rev
+				else List.rev args_rev
+			in
+			let arr = mk (TArrayDecl args) t_dynamic null_pos in
+			let concat = mk (TField (arr, FDynamic "concat")) t_dynamic null_pos in
+			true,[mk (TCall (concat, [rest])) t_dynamic null_pos]
+		| _ ->
 			false,el
-	in
+	else
+		false,el
+
+let rec gen_call ctx e el in_value =
+	let apply,el = apply_args ctx el in
 	match e.eexpr , el with
 	| TConst TSuper , params when ctx.es_version < 6 ->
 		(match ctx.current.cl_super with
@@ -758,12 +771,20 @@ and gen_expr ctx e =
 	| TNew ({ cl_path = [],"Array" },_,[]) ->
 		print ctx "[]"
 	| TNew (c,_,el) ->
+		let apply,el = apply_args ~add_null_context:true ctx el in
 		(match c.cl_constructor with
 		| Some cf when Meta.has Meta.SelfCall cf.cf_meta -> ()
-		| _ -> print ctx "new ");
-		print ctx "%s(" (ctx.type_accessor (TClassDecl c));
-		concat ctx "," (gen_value ctx) el;
-		spr ctx ")"
+		| _ -> print ctx (if apply then "(new" else "new "));
+		let cls = ctx.type_accessor (TClassDecl c) in
+		if apply then begin
+			print ctx "(Function.prototype.bind.apply(%s," cls;
+			concat ctx "," (gen_value ctx) el;
+			print ctx ")))"
+		end else begin
+			print ctx "%s(" cls;
+			concat ctx "," (gen_value ctx) el;
+			spr ctx ")"
+		end;
 	| TIf (cond,e,eelse) ->
 		spr ctx "if";
 		gen_value ctx cond;