overloadingConstructor.ml 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  1. (*
  2. The Haxe Compiler
  3. Copyright (C) 2005-2019 Haxe Foundation
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  15. *)
  16. open Option
  17. open Common
  18. open Type
  19. open Gencommon
  20. (* ******************************************* *)
  21. (* overloading reflection constructors *)
  22. (* ******************************************* *)
  23. (*
  24. this module works on languages that support function overloading and
  25. enable function hiding via static functions.
  26. it takes the constructor body out of the constructor and adds it to a special ctor
  27. static function. The static function will receive the same parameters as the constructor,
  28. plus the special "me" var, which will replace "this"
  29. Then it always adds two constructors to the class: one that receives a special marker class,
  30. indicating that the object should be constructed without executing constructor body,
  31. and one that executes its normal constructor.
  32. Both will only include a super() call to the superclasses' emtpy constructor.
  33. This enables two things:
  34. empty construction without the need of incompatibility with the platform's native construction method
  35. the ability to call super() constructor in any place in the constructor
  36. *)
  37. let rec prev_ctor c tl =
  38. match c.cl_super with
  39. | None ->
  40. raise Not_found
  41. | Some (sup,stl) ->
  42. let stl = List.map (apply_params c.cl_params tl) stl in
  43. match sup.cl_constructor with
  44. | None -> prev_ctor sup stl
  45. | Some ctor -> ctor, sup, stl
  46. let make_static_ctor_name cl =
  47. let name = mk_internal_name "hx" "ctor" in
  48. name ^ "_" ^ (String.concat "_" (fst cl.cl_path)) ^ "_" ^ (snd cl.cl_path)
  49. (* replaces super() call with last static constructor call *)
  50. let replace_super_call com c tl with_params me p follow_type =
  51. let rec loop_super c tl =
  52. match c.cl_super with
  53. | None ->
  54. raise Not_found
  55. | Some(sup,stl) ->
  56. let stl = List.map (apply_params c.cl_params tl) stl in
  57. try
  58. let static_ctor_name = make_static_ctor_name sup in
  59. sup, stl, PMap.find static_ctor_name sup.cl_statics
  60. with Not_found ->
  61. loop_super sup stl
  62. in
  63. let sup, stl, cf = loop_super c tl in
  64. let with_params = (mk (TLocal me) me.v_type p) :: with_params in
  65. let cf =
  66. try
  67. (* choose best super function *)
  68. List.iter (fun e -> replace_mono e.etype) with_params;
  69. List.find (fun cf ->
  70. replace_mono cf.cf_type;
  71. let args, _ = get_fun (apply_params cf.cf_params stl cf.cf_type) in
  72. try
  73. List.for_all2 (fun (_,_,t) e -> try
  74. let e_etype = follow_type e.etype in
  75. let t = follow_type t in
  76. unify e_etype t; true
  77. with Unify_error _ ->
  78. false
  79. ) args with_params
  80. with Invalid_argument _ ->
  81. false
  82. ) (cf :: cf.cf_overloads)
  83. with Not_found ->
  84. com.error "No suitable overload for the super call arguments was found" p; cf
  85. in
  86. {
  87. eexpr = TCall(
  88. {
  89. eexpr = TField(Texpr.Builder.make_static_this sup p, FStatic(sup,cf));
  90. etype = apply_params cf.cf_params stl cf.cf_type;
  91. epos = p
  92. },
  93. with_params
  94. );
  95. etype = com.basic.tvoid;
  96. epos = p;
  97. }
  98. (* will create a static counterpart of 'ctor', and replace its contents to a call to the static version*)
  99. let create_static_ctor com ~empty_ctor_expr cl ctor follow_type =
  100. match Meta.has Meta.SkipCtor ctor.cf_meta with
  101. | true -> ()
  102. | false when is_none ctor.cf_expr -> ()
  103. | false ->
  104. let static_ctor_name = make_static_ctor_name cl in
  105. (* create the static constructor *)
  106. let ctor_types = List.map (fun tp -> {tp with ttp_type = TInst(map_param (get_cl_t tp.ttp_type), [])}) cl.cl_params in
  107. let ctor_type_params = extract_param_types ctor_types in
  108. List.iter (function {ttp_type=TInst(c,[])} -> (
  109. match c.cl_kind with
  110. | KTypeParameter (hd :: tail) ->
  111. let before = hd :: tail in
  112. let after = List.map (apply_params cl.cl_params ctor_type_params) (before) in
  113. c.cl_kind <- KTypeParameter(after)
  114. | _ -> ())
  115. | _ -> ()) ctor_types;
  116. let me = alloc_var "__hx_this" (TInst(cl, extract_param_types ctor_types)) in
  117. add_var_flag me VCaptured;
  118. let fn_args, _ = get_fun ctor.cf_type in
  119. let ctor_params = extract_param_types ctor_types in
  120. let fn_type = TFun((me.v_name,false, me.v_type) :: List.map (fun (n,o,t) -> (n,o,apply_params cl.cl_params ctor_params t)) fn_args, com.basic.tvoid) in
  121. let cur_tf_args = match ctor.cf_expr with
  122. | Some { eexpr = TFunction(tf) } -> tf.tf_args
  123. | _ -> Globals.die "" __LOC__
  124. in
  125. let changed_tf_args = List.map (fun (v,_) -> (v,None)) cur_tf_args in
  126. let local_map = Hashtbl.create (List.length cur_tf_args) in
  127. let static_tf_args = (me, None) :: List.map (fun (v,b) ->
  128. let new_v = alloc_var v.v_name (apply_params cl.cl_params ctor_params v.v_type) in
  129. add_var_flag new_v VCaptured;
  130. Hashtbl.add local_map v.v_id new_v;
  131. (new_v, b)
  132. ) cur_tf_args in
  133. let static_ctor = mk_class_field ~static:true static_ctor_name fn_type false ctor.cf_pos (Method MethNormal) ctor_types in
  134. let static_ctor_meta = if has_class_flag cl CFinal then Meta.Private else Meta.Protected in
  135. static_ctor.cf_meta <- (static_ctor_meta,[],ctor.cf_pos) :: static_ctor.cf_meta;
  136. (* change ctor contents to reference the 'me' var instead of 'this' *)
  137. let actual_super_call = ref None in
  138. let rec map_expr ~is_first e = match e.eexpr with
  139. | TCall (({ eexpr = TConst TSuper } as tsuper), params) -> (try
  140. let params = List.map (fun e -> map_expr ~is_first:false e) params in
  141. actual_super_call := Some { e with eexpr = TCall(tsuper, [empty_ctor_expr]) };
  142. replace_super_call com cl ctor_params params me e.epos follow_type
  143. with | Not_found ->
  144. (* last static function was not found *)
  145. actual_super_call := Some e;
  146. if not is_first then
  147. com.error "Super call must be the first call when extending native types" e.epos;
  148. { e with eexpr = TBlock([]) })
  149. | TFunction tf when is_first ->
  150. do_map ~is_first:true e
  151. | TConst TThis ->
  152. mk_local me e.epos
  153. | TBlock (fst :: bl) ->
  154. let fst = map_expr ~is_first:is_first fst in
  155. { e with eexpr = TBlock(fst :: List.map (fun e -> map_expr ~is_first:false e) bl); etype = apply_params cl.cl_params ctor_params e.etype }
  156. | _ ->
  157. do_map e
  158. and do_map ?(is_first=false) e =
  159. let do_t = apply_params cl.cl_params ctor_params in
  160. let do_v v = try
  161. Hashtbl.find local_map v.v_id
  162. with | Not_found ->
  163. v.v_type <- do_t v.v_type; v
  164. in
  165. Type.map_expr_type (map_expr ~is_first:is_first) do_t do_v e
  166. in
  167. let expr = do_map ~is_first:true (get ctor.cf_expr) in
  168. let expr = match expr.eexpr with
  169. | TFunction(tf) ->
  170. { expr with etype = fn_type; eexpr = TFunction({ tf with tf_args = static_tf_args }) }
  171. | _ -> Globals.die "" __LOC__ in
  172. static_ctor.cf_expr <- Some expr;
  173. (* add to the statics *)
  174. (try
  175. let stat = PMap.find static_ctor_name cl.cl_statics in
  176. stat.cf_overloads <- static_ctor :: stat.cf_overloads
  177. with | Not_found ->
  178. cl.cl_ordered_statics <- static_ctor :: cl.cl_ordered_statics;
  179. cl.cl_statics <- PMap.add static_ctor_name static_ctor cl.cl_statics);
  180. (* change current super call *)
  181. match ctor.cf_expr with
  182. | Some({ eexpr = TFunction(tf) } as e) ->
  183. let block_contents, p = match !actual_super_call with
  184. | None -> [], ctor.cf_pos
  185. | Some super -> [super], super.epos
  186. in
  187. let el_args =
  188. let rec loop fn_args cur_args =
  189. match cur_args with
  190. | [] -> []
  191. | (v,_) :: cur_args ->
  192. let local = mk_local v p in
  193. match fn_args, cur_args with
  194. | [_,_,t], [] when ExtType.is_rest (follow t) ->
  195. [mk (TUnop(Spread,Prefix,local)) v.v_type p]
  196. | [], _ ->
  197. local :: loop fn_args cur_args
  198. | _ :: fn_args, _ ->
  199. local :: loop fn_args cur_args
  200. in
  201. loop fn_args cur_tf_args
  202. in
  203. let block_contents = block_contents @ [{
  204. eexpr = TCall(
  205. {
  206. eexpr = TField(
  207. Texpr.Builder.make_static_this cl p,
  208. FStatic(cl, static_ctor));
  209. etype = apply_params static_ctor.cf_params (extract_param_types cl.cl_params) static_ctor.cf_type;
  210. epos = p
  211. },
  212. [{ eexpr = TConst TThis; etype = TInst(cl, extract_param_types cl.cl_params); epos = p }]
  213. @ el_args
  214. );
  215. etype = com.basic.tvoid;
  216. epos = p
  217. }] in
  218. ctor.cf_expr <- Some { e with eexpr = TFunction({ tf with tf_expr = { tf.tf_expr with eexpr = TBlock block_contents }; tf_args = changed_tf_args }) }
  219. | _ -> Globals.die "" __LOC__
  220. (* makes constructors that only call super() for the 'ctor' argument *)
  221. let clone_ctors com ctor sup stl cl =
  222. let clone cf =
  223. let ncf = mk_class_field "new" (apply_params sup.cl_params stl cf.cf_type) (has_class_field_flag cf CfPublic) cf.cf_pos cf.cf_kind cf.cf_params in
  224. if Meta.has Meta.Protected cf.cf_meta then
  225. ncf.cf_meta <- (Meta.Protected,[],ncf.cf_pos) :: ncf.cf_meta;
  226. let args, ret = get_fun ncf.cf_type in
  227. (* single expression: call to super() *)
  228. let tf_args = List.map (fun (name,_,t) ->
  229. (* the constructor will have no optional arguments, as presumably this will be handled by the underlying expr *)
  230. alloc_var name t, None
  231. ) args in
  232. let super_call =
  233. {
  234. eexpr = TCall(
  235. { eexpr = TConst TSuper; etype = TInst(cl, extract_param_types cl.cl_params); epos = ctor.cf_pos },
  236. List.map (fun (v,_) -> mk_local v ctor.cf_pos) tf_args);
  237. etype = com.basic.tvoid;
  238. epos = ctor.cf_pos;
  239. } in
  240. ncf.cf_expr <- Some
  241. {
  242. eexpr = TFunction {
  243. tf_args = tf_args;
  244. tf_type = com.basic.tvoid;
  245. tf_expr = mk_block super_call;
  246. };
  247. etype = ncf.cf_type;
  248. epos = ctor.cf_pos;
  249. };
  250. ncf
  251. in
  252. (* take off createEmpty *)
  253. let all = List.filter (fun cf -> replace_mono cf.cf_type; not (Meta.has Meta.SkipCtor cf.cf_meta)) (ctor :: ctor.cf_overloads) in
  254. let clones = List.map clone all in
  255. match clones with
  256. | [] ->
  257. (* raise Not_found *)
  258. Globals.die "" __LOC__ (* should never happen *)
  259. | cf :: [] -> cf
  260. | cf :: overl ->
  261. add_class_field_flag cf CfOverload;
  262. cf.cf_overloads <- overl; cf
  263. let rec descends_from_native_or_skipctor cl =
  264. not (is_hxgen (TClassDecl cl)) || Meta.has Meta.SkipCtor cl.cl_meta || match cl.cl_super with
  265. | None -> false
  266. | Some(c,_) -> descends_from_native_or_skipctor c
  267. let ensure_super_is_first com cf =
  268. let rec loop e =
  269. match e.eexpr with
  270. | TBlock (b :: block) ->
  271. loop b
  272. | TBlock []
  273. | TCall({ eexpr = TConst TSuper },_) -> ()
  274. | _ ->
  275. com.error "Types that derive from a native class must have its super() call as the first statement in the constructor" cf.cf_pos
  276. in
  277. match cf.cf_expr with
  278. | None -> ()
  279. | Some e -> Type.iter loop e
  280. let init com (empty_ctor_type : t) (empty_ctor_expr : texpr) (follow_type : t -> t) =
  281. let basic = com.basic in
  282. let should_change cl = not (has_class_flag cl CInterface) && (not (has_class_flag cl CExtern) || is_hxgen (TClassDecl cl)) && (match cl.cl_kind with KAbstractImpl _ | KModuleFields _ -> false | _ -> true) in
  283. let msize = List.length com.types in
  284. let processed, empty_ctors = Hashtbl.create msize, Hashtbl.create msize in
  285. let rec get_last_empty cl =
  286. try
  287. Hashtbl.find empty_ctors cl.cl_path
  288. with | Not_found ->
  289. match cl.cl_super with
  290. | None -> raise Not_found
  291. | Some (sup,_) -> get_last_empty sup
  292. in
  293. let rec change cl =
  294. if not (Hashtbl.mem processed cl.cl_path) then begin
  295. Hashtbl.add processed cl.cl_path true;
  296. (* make sure we've processed the super types *)
  297. Option.may (fun (super,_) -> if should_change super then change super) cl.cl_super;
  298. (* implement static hx_ctor and reimplement constructors *)
  299. (try
  300. let ctor =
  301. match cl.cl_constructor with
  302. | Some ctor ->
  303. ctor
  304. | None ->
  305. try
  306. let sctor, sup, stl = prev_ctor cl (extract_param_types cl.cl_params) in
  307. (* we'll make constructors that will only call super() *)
  308. let ctor = clone_ctors com sctor sup stl cl in
  309. cl.cl_constructor <- Some ctor;
  310. ctor
  311. with Not_found -> (* create default constructor *)
  312. let ctor = mk_class_field "new" (TFun ([], basic.tvoid)) false cl.cl_pos (Method MethNormal) [] in
  313. ctor.cf_expr <- Some {
  314. eexpr = TFunction {
  315. tf_args = [];
  316. tf_type = basic.tvoid;
  317. tf_expr = mk (TBlock []) basic.tvoid cl.cl_pos;
  318. };
  319. etype = ctor.cf_type;
  320. epos = ctor.cf_pos;
  321. };
  322. cl.cl_constructor <- Some ctor;
  323. ctor
  324. in
  325. let has_super_constructor =
  326. match cl.cl_super with
  327. | None -> false
  328. | Some (csup,_) -> has_constructor csup
  329. in
  330. (* now that we made sure we have a constructor, exit if native gen *)
  331. if not (is_hxgen (TClassDecl cl)) || Meta.has Meta.SkipCtor cl.cl_meta then begin
  332. if descends_from_native_or_skipctor cl && has_super_constructor then
  333. List.iter (fun cf -> ensure_super_is_first com cf) (ctor :: ctor.cf_overloads);
  334. raise Exit
  335. end;
  336. (* if cl descends from a native class, we cannot use the static constructor strategy *)
  337. if descends_from_native_or_skipctor cl && has_super_constructor then
  338. List.iter (fun cf -> ensure_super_is_first com cf) (ctor :: ctor.cf_overloads)
  339. else
  340. (* now that we have a current ctor, create the static counterparts *)
  341. List.iter (fun cf -> create_static_ctor com ~empty_ctor_expr:empty_ctor_expr cl cf follow_type) (ctor :: ctor.cf_overloads)
  342. with Exit -> ());
  343. (* implement empty ctor *)
  344. (try
  345. (* now that we made sure we have a constructor, exit if native gen *)
  346. if not (is_hxgen (TClassDecl cl)) then raise Exit;
  347. (* get first *)
  348. let empty_type = TFun (["empty",false,empty_ctor_type],basic.tvoid) in
  349. let super =
  350. match cl.cl_super with
  351. | None -> (* implement empty *)
  352. []
  353. | Some (sup,_) ->
  354. try
  355. ignore (get_last_empty sup);
  356. let esuper = mk (TConst TSuper) (TInst (cl, extract_param_types cl.cl_params)) cl.cl_pos in
  357. [mk (TCall (esuper, [empty_ctor_expr])) basic.tvoid cl.cl_pos]
  358. with Not_found ->
  359. try
  360. (* super type is native: find super constructor with least arguments *)
  361. let sctor, sup, stl = prev_ctor cl (extract_param_types cl.cl_params) in
  362. let rec loop remaining (best,n) =
  363. match remaining with
  364. | [] -> best
  365. | cf :: r ->
  366. let args,_ = get_fun cf.cf_type in
  367. if (List.length args) < n then
  368. loop r (cf,List.length args)
  369. else
  370. loop r (best,n)
  371. in
  372. let args,_ = get_fun sctor.cf_type in
  373. let best = loop sctor.cf_overloads (sctor, List.length args) in
  374. let args,_ = get_fun (apply_params sup.cl_params stl best.cf_type) in
  375. let esuper = mk (TConst TSuper) (TInst (sup, stl)) cl.cl_pos in
  376. [mk (TCall (esuper, List.map (fun (n,o,t) -> null t cl.cl_pos) args)) basic.tvoid cl.cl_pos]
  377. with Not_found ->
  378. (* extends native type, but no ctor found *)
  379. []
  380. in
  381. let ctor = mk_class_field "new" empty_type false cl.cl_pos (Method MethNormal) [] in
  382. ctor.cf_expr <- Some {
  383. eexpr = TFunction {
  384. tf_type = basic.tvoid;
  385. tf_args = [alloc_var "empty" empty_ctor_type, None];
  386. tf_expr = mk (TBlock super) basic.tvoid cl.cl_pos
  387. };
  388. etype = empty_type;
  389. epos = cl.cl_pos;
  390. };
  391. ctor.cf_meta <- [Meta.SkipCtor, [], ctor.cf_pos];
  392. Hashtbl.add empty_ctors cl.cl_path ctor;
  393. match cl.cl_constructor with
  394. | None ->
  395. cl.cl_constructor <- Some ctor
  396. | Some c ->
  397. c.cf_overloads <- ctor :: c.cf_overloads
  398. with Exit -> ());
  399. end
  400. in
  401. let module_filter md =
  402. (match md with
  403. | TClassDecl cl when should_change cl ->
  404. change cl;
  405. | _ ->
  406. ());
  407. md
  408. in
  409. module_filter
  410. let init_expr_filter create_empty =
  411. let rec run e =
  412. match e.etype, e.eexpr with
  413. | TInst (cl, params), TCall ({ eexpr = TField (_, FStatic ({cl_path = [],"Type"}, {cf_name = "createEmptyInstance"})) }, [{eexpr = TTypeExpr ((TClassDecl cl_arg) as mt_arg) }]) when cl == cl_arg && is_hxgen mt_arg ->
  414. create_empty cl params e.epos
  415. | _ ->
  416. Type.map_expr run e
  417. in
  418. run
  419. let priority = 0.0
  420. let name = "overloading_constructor"
  421. let configure gen ~empty_ctor_type ~empty_ctor_expr =
  422. gen.gtools.r_create_empty <- (fun cl params pos -> mk (TNew(cl,params,[empty_ctor_expr])) (TInst(cl,params)) pos);
  423. let module_filter = init gen.gcon empty_ctor_type empty_ctor_expr (run_follow gen) in
  424. gen.gmodule_filters#add name (PCustom priority) module_filter;
  425. let expr_filter = init_expr_filter gen.gtools.r_create_empty in
  426. gen.gexpr_filters#add name (PCustom priority) expr_filter