filters.ml 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134
  1. open Ast
  2. open Common
  3. open Type
  4. open Typecore
  5. (* PASS 1 begin *)
  6. (*
  7. Wraps implicit blocks in TIf, TFor, TWhile, TFunction and TTry with real ones
  8. *)
  9. let rec blockify_ast e =
  10. match e.eexpr with
  11. | TIf(e1,e2,eo) ->
  12. {e with eexpr = TIf(blockify_ast e1,mk_block (blockify_ast e2),match eo with None -> None | Some e -> Some (mk_block (blockify_ast e)))}
  13. | TFor(v,e1,e2) ->
  14. {e with eexpr = TFor(v,blockify_ast e1,mk_block (blockify_ast e2))}
  15. | TWhile(e1,e2,flag) ->
  16. {e with eexpr = TWhile(blockify_ast e1,mk_block (blockify_ast e2),flag)}
  17. | TFunction tf ->
  18. {e with eexpr = TFunction {tf with tf_expr = mk_block (blockify_ast tf.tf_expr)}}
  19. | TTry(e1,cl) ->
  20. {e with eexpr = TTry(blockify_ast e1,List.map (fun (v,e) -> v,mk_block (blockify_ast e)) cl)}
  21. | _ ->
  22. Type.map_expr blockify_ast e
  23. (*
  24. Generates a block context which can be used to add temporary variables. It returns a tuple:
  25. - a mapping function for expression lists to be used on TBlock elements
  26. - the function to be called for declaring temporary variables
  27. - the function to be called for closing the block, returning the block elements
  28. *)
  29. let mk_block_context com gen_temp =
  30. let block_el = ref [] in
  31. let push e = block_el := e :: !block_el in
  32. let declare_temp t eo p =
  33. let v = gen_temp t in
  34. let e = mk (TVar (v,eo)) com.basic.tvoid p in
  35. push e;
  36. mk (TLocal v) t p
  37. in
  38. let push_block () =
  39. let cur = !block_el in
  40. block_el := [];
  41. fun () ->
  42. let added = !block_el in
  43. block_el := cur;
  44. List.rev added
  45. in
  46. let rec block f el =
  47. let close = push_block() in
  48. List.iter (fun e ->
  49. push (f e)
  50. ) el;
  51. close()
  52. in
  53. block,declare_temp,fun () -> !block_el
  54. (*
  55. Moves expressions to temporary variables in order to ensure correct evaluation order. This effects
  56. - call arguments (from TCall and TNew)
  57. - array declaration arguments
  58. - object fields
  59. - binary operators (respects boolean short-circuit)
  60. - array access
  61. *)
  62. let handle_side_effects com gen_temp e =
  63. let block,declare_temp,close_block = mk_block_context com gen_temp in
  64. let rec loop e =
  65. match e.eexpr with
  66. | TBlock el ->
  67. {e with eexpr = TBlock (block loop el)}
  68. | TCall({eexpr = TLocal v},_) when Meta.has Meta.Unbound v.v_meta ->
  69. e
  70. | TCall(e1,el) ->
  71. let e1 = loop e1 in
  72. {e with eexpr = TCall(e1,ordered_list el)}
  73. | TNew(c,tl,el) ->
  74. {e with eexpr = TNew(c,tl,ordered_list el)}
  75. | TArrayDecl el ->
  76. {e with eexpr = TArrayDecl (ordered_list el)}
  77. | TObjectDecl fl ->
  78. let el = ordered_list (List.map snd fl) in
  79. {e with eexpr = TObjectDecl (List.map2 (fun (n,_) e -> n,e) fl el)}
  80. | TBinop(OpBoolAnd | OpBoolOr as op,e1,e2) when Optimizer.has_side_effect e1 || Optimizer.has_side_effect e2 ->
  81. let e1 = loop e1 in
  82. let e_then = mk (TBlock (block loop [e2])) e2.etype e2.epos in
  83. let e_if,e_else = if op = OpBoolOr then
  84. mk (TUnop(Not,Prefix,e1)) com.basic.tbool e.epos,mk (TConst (TBool(true))) com.basic.tbool e.epos
  85. else
  86. e1,mk (TConst (TBool(false))) com.basic.tbool e.epos
  87. in
  88. mk (TIf(e_if,e_then,Some e_else)) com.basic.tbool e.epos
  89. | TBinop((OpAssign | OpAssignOp _) as op,{eexpr = TArray(e11,e12)},e2) ->
  90. let e1 = match ordered_list [e11;e12] with
  91. | [e1;e2] ->
  92. {e with eexpr = TArray(e1,e2)}
  93. | _ ->
  94. assert false
  95. in
  96. let e2 = loop e2 in
  97. {e with eexpr = TBinop(op,e1,e2)}
  98. | TBinop(op,e1,e2) ->
  99. begin match ordered_list [e1;e2] with
  100. | [e1;e2] ->
  101. {e with eexpr = TBinop(op,e1,e2)}
  102. | _ ->
  103. assert false
  104. end
  105. | TArray(e1,e2) ->
  106. begin match ordered_list [e1;e2] with
  107. | [e1;e2] ->
  108. {e with eexpr = TArray(e1,e2)}
  109. | _ ->
  110. assert false
  111. end
  112. | TWhile(e1,e2,flag) when (match e1.eexpr with TParenthesis {eexpr = TConst(TBool true)} -> false | _ -> true) ->
  113. let p = e.epos in
  114. let e_break = mk TBreak t_dynamic p in
  115. let e_not = mk (TUnop(Not,Prefix,Codegen.mk_parent e1)) e1.etype e1.epos in
  116. let e_if = mk (TIf(e_not,e_break,None)) com.basic.tvoid p in
  117. let e_block = if flag = NormalWhile then Type.concat e_if e2 else Type.concat e2 e_if in
  118. let e_true = mk (TConst (TBool true)) com.basic.tbool p in
  119. let e = mk (TWhile(Codegen.mk_parent e_true,e_block,NormalWhile)) e.etype p in
  120. loop e
  121. | _ ->
  122. Type.map_expr loop e
  123. and ordered_list el =
  124. let bind e =
  125. declare_temp e.etype (Some (loop e)) e.epos
  126. in
  127. let rec no_side_effect e =
  128. if Optimizer.has_side_effect e then
  129. bind e
  130. else
  131. e
  132. in
  133. List.map no_side_effect el
  134. in
  135. let e = loop e in
  136. match close_block() with
  137. | [] ->
  138. e
  139. | el ->
  140. mk (TBlock (List.rev (e :: el))) e.etype e.epos
  141. (*
  142. Pushes complex right-hand side expression inwards.
  143. return { exprs; value; } -> { exprs; return value; }
  144. x = { exprs; value; } -> { exprs; x = value; }
  145. var x = { exprs; value; } -> { var x; exprs; x = value; }
  146. *)
  147. let promote_complex_rhs ctx e =
  148. let rec is_complex e = match e.eexpr with
  149. | TBlock _ | TSwitch _ | TIf _ | TTry _ | TCast(_,Some _) -> true
  150. | TBinop(_,e1,e2) -> is_complex e1 || is_complex e2
  151. | TParenthesis e | TMeta(_,e) | TCast(e, None) -> is_complex e
  152. | _ -> false
  153. in
  154. let rec loop f e = match e.eexpr with
  155. | TBlock(el) ->
  156. begin match List.rev el with
  157. | elast :: el -> {e with eexpr = TBlock(block (List.rev ((loop f elast) :: el)))}
  158. | [] -> e
  159. end
  160. | TSwitch(es,cases,edef) ->
  161. {e with eexpr = TSwitch(es,List.map (fun (el,e) -> List.map find el,loop f e) cases,match edef with None -> None | Some e -> Some (loop f e))}
  162. | TIf(eif,ethen,eelse) ->
  163. {e with eexpr = TIf(find eif, loop f ethen, match eelse with None -> None | Some e -> Some (loop f e))}
  164. | TTry(e1,el) ->
  165. {e with eexpr = TTry(loop f e1, List.map (fun (el,e) -> el,loop f e) el)}
  166. | TParenthesis e1 when not (Common.defined ctx Define.As3) ->
  167. {e with eexpr = TParenthesis(loop f e1)}
  168. | TMeta(m,e1) ->
  169. { e with eexpr = TMeta(m,loop f e1)}
  170. | TReturn _ | TThrow _ ->
  171. find e
  172. | TCast(e1,None) when ctx.config.pf_ignore_unsafe_cast ->
  173. loop f e1
  174. | _ ->
  175. f (find e)
  176. and block el =
  177. let r = ref [] in
  178. List.iter (fun e ->
  179. match e.eexpr with
  180. | TVar(v,eo) ->
  181. begin match eo with
  182. | Some e when is_complex e ->
  183. r := (loop (fun e -> mk (TBinop(OpAssign,mk (TLocal v) v.v_type e.epos,e)) v.v_type e.epos) e)
  184. :: ((mk (TVar (v,None)) ctx.basic.tvoid e.epos))
  185. :: !r
  186. | Some e ->
  187. r := (mk (TVar (v,Some (find e))) ctx.basic.tvoid e.epos) :: !r
  188. | None -> r := (mk (TVar (v,None)) ctx.basic.tvoid e.epos) :: !r
  189. end
  190. | _ -> r := (find e) :: !r
  191. ) el;
  192. List.rev !r
  193. and find e = match e.eexpr with
  194. | TReturn (Some e1) -> loop (fun e -> {e with eexpr = TReturn (Some e)}) e1
  195. | TBinop(OpAssign | OpAssignOp _ as op, ({eexpr = TLocal _ | TField _ | TArray _} as e1), e2) -> loop (fun er -> {e with eexpr = TBinop(op, e1, er)}) e2
  196. | TBlock(el) -> {e with eexpr = TBlock (block el)}
  197. | _ -> Type.map_expr find e
  198. in
  199. find e
  200. (* Adds final returns to functions as required by some platforms *)
  201. let rec add_final_return e =
  202. let rec loop e t =
  203. let def_return p =
  204. let c = (match follow t with
  205. | TAbstract ({ a_path = [],"Int" },_) -> TInt 0l
  206. | TAbstract ({ a_path = [],"Float" },_) -> TFloat "0."
  207. | TAbstract ({ a_path = [],"Bool" },_) -> TBool false
  208. | _ -> TNull
  209. ) in
  210. { eexpr = TReturn (Some { eexpr = TConst c; epos = p; etype = t }); etype = t; epos = p }
  211. in
  212. match e.eexpr with
  213. | TBlock el ->
  214. (match List.rev el with
  215. | [] -> e
  216. | elast :: el ->
  217. match loop elast t with
  218. | { eexpr = TBlock el2 } -> { e with eexpr = TBlock ((List.rev el) @ el2) }
  219. | elast -> { e with eexpr = TBlock (List.rev (elast :: el)) })
  220. | TReturn _ ->
  221. e
  222. | _ ->
  223. { e with eexpr = TBlock [e;def_return e.epos] }
  224. in
  225. let e = Type.map_expr add_final_return e in
  226. match e.eexpr with
  227. | TFunction f ->
  228. let f = (match follow f.tf_type with
  229. | TAbstract ({ a_path = [],"Void" },[]) -> f
  230. | t -> { f with tf_expr = loop f.tf_expr t }
  231. ) in
  232. { e with eexpr = TFunction f }
  233. | _ -> e
  234. (* -------------------------------------------------------------------------- *)
  235. (* CHECK LOCAL VARS INIT *)
  236. let check_local_vars_init e =
  237. let intersect vl1 vl2 =
  238. PMap.mapi (fun v t -> t && PMap.find v vl2) vl1
  239. in
  240. let join vars cvars =
  241. List.iter (fun v -> vars := intersect !vars v) cvars
  242. in
  243. let restore vars old_vars declared =
  244. (* restore variables declared in this block to their previous state *)
  245. vars := List.fold_left (fun acc v ->
  246. try PMap.add v (PMap.find v old_vars) acc with Not_found -> PMap.remove v acc
  247. ) !vars declared;
  248. in
  249. let declared = ref [] in
  250. let rec loop vars e =
  251. match e.eexpr with
  252. | TLocal v ->
  253. let init = (try PMap.find v.v_id !vars with Not_found -> true) in
  254. if not init then begin
  255. if v.v_name = "this" then error "Missing this = value" e.epos
  256. else error ("Local variable " ^ v.v_name ^ " used without being initialized") e.epos
  257. end
  258. | TVar (v,eo) ->
  259. begin
  260. match eo with
  261. | None ->
  262. declared := v.v_id :: !declared;
  263. vars := PMap.add v.v_id false !vars
  264. | Some e ->
  265. loop vars e
  266. end
  267. | TBlock el ->
  268. let old = !declared in
  269. let old_vars = !vars in
  270. declared := [];
  271. List.iter (loop vars) el;
  272. restore vars old_vars (List.rev !declared);
  273. declared := old;
  274. | TBinop (OpAssign,{ eexpr = TLocal v },e) when PMap.mem v.v_id !vars ->
  275. loop vars e;
  276. vars := PMap.add v.v_id true !vars
  277. | TIf (e1,e2,eo) ->
  278. loop vars e1;
  279. let vbase = !vars in
  280. loop vars e2;
  281. (match eo with
  282. | None -> vars := vbase
  283. (* ignore else false cases (they are added by the side-effect handler) *)
  284. | Some {eexpr = TConst (TBool(false))} -> ()
  285. | Some e ->
  286. let v1 = !vars in
  287. vars := vbase;
  288. loop vars e;
  289. vars := intersect !vars v1)
  290. | TWhile (cond,e,flag) ->
  291. (match flag with
  292. | NormalWhile when (match cond.eexpr with TParenthesis {eexpr = TConst (TBool true)} -> false | _ -> true) ->
  293. loop vars cond;
  294. let old = !vars in
  295. loop vars e;
  296. vars := old;
  297. | _ ->
  298. loop vars e;
  299. loop vars cond)
  300. | TTry (e,catches) ->
  301. let cvars = List.map (fun (v,e) ->
  302. let old = !vars in
  303. loop vars e;
  304. let v = !vars in
  305. vars := old;
  306. v
  307. ) catches in
  308. loop vars e;
  309. join vars cvars;
  310. | TSwitch (e,cases,def) ->
  311. loop vars e;
  312. let cvars = List.map (fun (ec,e) ->
  313. let old = !vars in
  314. List.iter (loop vars) ec;
  315. vars := old;
  316. loop vars e;
  317. let v = !vars in
  318. vars := old;
  319. v
  320. ) cases in
  321. (match def with
  322. | None when (match e.eexpr with TMeta((Meta.Exhaustive,_,_),_) | TParenthesis({eexpr = TMeta((Meta.Exhaustive,_,_),_)}) -> true | _ -> false) ->
  323. (match cvars with
  324. | cv :: cvars ->
  325. PMap.iter (fun i b -> if b then vars := PMap.add i b !vars) cv;
  326. join vars cvars
  327. | [] -> ())
  328. | None -> ()
  329. | Some e ->
  330. loop vars e;
  331. join vars cvars)
  332. | TPatMatch dt ->
  333. let cvars = ref [] in
  334. let rec fdt dt = match dt with
  335. | DTExpr e ->
  336. let old = !vars in
  337. loop vars e;
  338. restore vars old [];
  339. cvars := !vars :: !cvars
  340. | DTSwitch(e,cl,dto) ->
  341. loop vars e;
  342. List.iter (fun (_,dt) -> fdt dt) cl;
  343. (match dto with None -> () | Some dt -> fdt dt)
  344. | DTGuard(e,dt1,dt2) ->
  345. fdt dt1;
  346. (match dt2 with None -> () | Some dt -> fdt dt)
  347. | DTBind(_,dt) -> fdt dt
  348. | DTGoto _ -> ()
  349. in
  350. Array.iter fdt dt.dt_dt_lookup;
  351. join vars !cvars
  352. (* mark all reachable vars as initialized, since we don't exit the block *)
  353. | TBreak | TContinue | TReturn None ->
  354. vars := PMap.map (fun _ -> true) !vars
  355. | TThrow e | TReturn (Some e) ->
  356. loop vars e;
  357. vars := PMap.map (fun _ -> true) !vars
  358. | _ ->
  359. Type.iter (loop vars) e
  360. in
  361. loop (ref PMap.empty) e;
  362. e
  363. (* -------------------------------------------------------------------------- *)
  364. (* BLOCK VARIABLES CAPTURE *)
  365. (*
  366. For some platforms, it will simply mark the variables which are used in closures
  367. using the v_capture flag so it can be processed in a more optimized
  368. For Flash/JS platforms, it will ensure that variables used in loop sub-functions
  369. have an unique scope. It transforms the following expression :
  370. for( x in array )
  371. funs.push(function() return x++);
  372. Into the following :
  373. for( _x in array ) {
  374. var x = [_x];
  375. funs.push(function(x) { function() return x[0]++; }(x));
  376. }
  377. *)
  378. type usage =
  379. | Block of ((usage -> unit) -> unit)
  380. | Loop of ((usage -> unit) -> unit)
  381. | Function of ((usage -> unit) -> unit)
  382. | Declare of tvar
  383. | Use of tvar
  384. let rec local_usage f e =
  385. match e.eexpr with
  386. | TLocal v ->
  387. f (Use v)
  388. | TVar (v,eo) ->
  389. (match eo with None -> () | Some e -> local_usage f e);
  390. f (Declare v);
  391. | TFunction tf ->
  392. let cc f =
  393. List.iter (fun (v,_) -> f (Declare v)) tf.tf_args;
  394. local_usage f tf.tf_expr;
  395. in
  396. f (Function cc)
  397. | TBlock l ->
  398. f (Block (fun f -> List.iter (local_usage f) l))
  399. | TFor (v,it,e) ->
  400. local_usage f it;
  401. f (Loop (fun f ->
  402. f (Declare v);
  403. local_usage f e;
  404. ))
  405. | TWhile _ ->
  406. f (Loop (fun f ->
  407. iter (local_usage f) e
  408. ))
  409. | TTry (e,catchs) ->
  410. local_usage f e;
  411. List.iter (fun (v,e) ->
  412. f (Block (fun f ->
  413. f (Declare v);
  414. local_usage f e;
  415. ))
  416. ) catchs;
  417. | TPatMatch dt ->
  418. List.iter (fun (v,eo) ->
  419. f (Declare v);
  420. match eo with None -> () | Some e -> local_usage f e
  421. ) dt.dt_var_init;
  422. let rec fdt dt = match dt with
  423. | DTBind(bl,dt) ->
  424. List.iter (fun ((v,_),e) ->
  425. f (Declare v);
  426. local_usage f e
  427. ) bl;
  428. fdt dt
  429. | DTExpr e -> local_usage f e
  430. | DTGuard(e,dt1,dt2) ->
  431. local_usage f e;
  432. fdt dt1;
  433. (match dt2 with None -> () | Some dt -> fdt dt)
  434. | DTSwitch(e,cl,dto) ->
  435. local_usage f e;
  436. List.iter (fun (e,dt) ->
  437. local_usage f e;
  438. fdt dt
  439. ) cl;
  440. (match dto with None -> () | Some dt -> fdt dt)
  441. | DTGoto _ -> ()
  442. in
  443. Array.iter fdt dt.dt_dt_lookup
  444. | _ ->
  445. iter (local_usage f) e
  446. let captured_vars com e =
  447. let t = com.basic in
  448. let rec mk_init av v pos =
  449. mk (TVar (av,Some (mk (TArrayDecl [mk (TLocal v) v.v_type pos]) av.v_type pos))) t.tvoid pos
  450. and mk_var v used =
  451. let v2 = alloc_var v.v_name (PMap.find v.v_id used) in
  452. v2.v_meta <- v.v_meta;
  453. v2
  454. and wrap used e =
  455. match e.eexpr with
  456. | TVar (v,ve) ->
  457. let v,ve =
  458. if PMap.mem v.v_id used then
  459. v, Some (mk (TArrayDecl (match ve with None -> [] | Some e -> [wrap used e])) v.v_type e.epos)
  460. else
  461. v, (match ve with None -> None | Some e -> Some (wrap used e))
  462. in
  463. { e with eexpr = TVar (v,ve) }
  464. | TLocal v when PMap.mem v.v_id used ->
  465. mk (TArray ({ e with etype = v.v_type },mk (TConst (TInt 0l)) t.tint e.epos)) e.etype e.epos
  466. | TFor (v,it,expr) when PMap.mem v.v_id used ->
  467. let vtmp = mk_var v used in
  468. let it = wrap used it in
  469. let expr = wrap used expr in
  470. mk (TFor (vtmp,it,Type.concat (mk_init v vtmp e.epos) expr)) e.etype e.epos
  471. | TTry (expr,catchs) ->
  472. let catchs = List.map (fun (v,e) ->
  473. let e = wrap used e in
  474. try
  475. let vtmp = mk_var v used in
  476. vtmp, Type.concat (mk_init v vtmp e.epos) e
  477. with Not_found ->
  478. v, e
  479. ) catchs in
  480. mk (TTry (wrap used expr,catchs)) e.etype e.epos
  481. (* TODO: find out this does *)
  482. (* | TMatch (expr,enum,cases,def) ->
  483. let cases = List.map (fun (il,vars,e) ->
  484. let pos = e.epos in
  485. let e = ref (wrap used e) in
  486. let vars = match vars with
  487. | None -> None
  488. | Some l ->
  489. Some (List.map (fun v ->
  490. match v with
  491. | Some v when PMap.mem v.v_id used ->
  492. let vtmp = mk_var v used in
  493. e := concat (mk_init v vtmp pos) !e;
  494. Some vtmp
  495. | _ -> v
  496. ) l)
  497. in
  498. il, vars, !e
  499. ) cases in
  500. let def = match def with None -> None | Some e -> Some (wrap used e) in
  501. mk (TMatch (wrap used expr,enum,cases,def)) e.etype e.epos *)
  502. | TFunction f ->
  503. (*
  504. list variables that are marked as used, but also used in that
  505. function and which are not declared inside it !
  506. *)
  507. let fused = ref PMap.empty in
  508. let tmp_used = ref used in
  509. let rec browse = function
  510. | Block f | Loop f | Function f -> f browse
  511. | Use v ->
  512. if PMap.mem v.v_id !tmp_used then fused := PMap.add v.v_id v !fused;
  513. | Declare v ->
  514. tmp_used := PMap.remove v.v_id !tmp_used
  515. in
  516. local_usage browse e;
  517. let vars = PMap.fold (fun v acc -> v :: acc) !fused [] in
  518. (* in case the variable has been marked as used in a parallel scope... *)
  519. let fexpr = ref (wrap used f.tf_expr) in
  520. let fargs = List.map (fun (v,o) ->
  521. if PMap.mem v.v_id used then
  522. let vtmp = mk_var v used in
  523. fexpr := Type.concat (mk_init v vtmp e.epos) !fexpr;
  524. vtmp, o
  525. else
  526. v, o
  527. ) f.tf_args in
  528. let e = { e with eexpr = TFunction { f with tf_args = fargs; tf_expr = !fexpr } } in
  529. (*
  530. Create a new function scope to make sure that the captured loop variable
  531. will not be overwritten in next loop iteration
  532. *)
  533. if com.config.pf_capture_policy = CPLoopVars then
  534. mk (TCall (
  535. Codegen.mk_parent (mk (TFunction {
  536. tf_args = List.map (fun v -> v, None) vars;
  537. tf_type = e.etype;
  538. tf_expr = mk_block (mk (TReturn (Some e)) e.etype e.epos);
  539. }) (TFun (List.map (fun v -> v.v_name,false,v.v_type) vars,e.etype)) e.epos),
  540. List.map (fun v -> mk (TLocal v) v.v_type e.epos) vars)
  541. ) e.etype e.epos
  542. else
  543. e
  544. | _ ->
  545. map_expr (wrap used) e
  546. and do_wrap used e =
  547. if PMap.is_empty used then
  548. e
  549. else
  550. let used = PMap.map (fun v ->
  551. let vt = v.v_type in
  552. v.v_type <- t.tarray vt;
  553. v.v_capture <- true;
  554. vt
  555. ) used in
  556. wrap used e
  557. and out_loop e =
  558. match e.eexpr with
  559. | TFor _ | TWhile _ ->
  560. (*
  561. collect variables that are declared in loop but used in subfunctions
  562. *)
  563. let vars = ref PMap.empty in
  564. let used = ref PMap.empty in
  565. let depth = ref 0 in
  566. let rec collect_vars in_loop = function
  567. | Block f ->
  568. let old = !vars in
  569. f (collect_vars in_loop);
  570. vars := old;
  571. | Loop f ->
  572. let old = !vars in
  573. f (collect_vars true);
  574. vars := old;
  575. | Function f ->
  576. incr depth;
  577. f (collect_vars false);
  578. decr depth;
  579. | Declare v ->
  580. if in_loop then vars := PMap.add v.v_id !depth !vars;
  581. | Use v ->
  582. try
  583. let d = PMap.find v.v_id !vars in
  584. if d <> !depth then used := PMap.add v.v_id v !used;
  585. with Not_found ->
  586. ()
  587. in
  588. local_usage (collect_vars false) e;
  589. do_wrap !used e
  590. | _ ->
  591. map_expr out_loop e
  592. and all_vars e =
  593. let vars = ref PMap.empty in
  594. let used = ref PMap.empty in
  595. let depth = ref 0 in
  596. let rec collect_vars = function
  597. | Block f ->
  598. let old = !vars in
  599. f collect_vars;
  600. vars := old;
  601. | Loop f ->
  602. let old = !vars in
  603. f collect_vars;
  604. vars := old;
  605. | Function f ->
  606. incr depth;
  607. f collect_vars;
  608. decr depth;
  609. | Declare v ->
  610. vars := PMap.add v.v_id !depth !vars;
  611. | Use v ->
  612. try
  613. let d = PMap.find v.v_id !vars in
  614. if d <> !depth then used := PMap.add v.v_id v !used;
  615. with Not_found -> ()
  616. in
  617. local_usage collect_vars e;
  618. !used
  619. in
  620. (* mark all capture variables - also used in rename_local_vars at later stage *)
  621. let captured = all_vars e in
  622. PMap.iter (fun _ v -> v.v_capture <- true) captured;
  623. match com.config.pf_capture_policy with
  624. | CPNone -> e
  625. | CPWrapRef -> do_wrap captured e
  626. | CPLoopVars -> out_loop e
  627. (* -------------------------------------------------------------------------- *)
  628. (* RENAME LOCAL VARS *)
  629. let rename_local_vars com e =
  630. let cfg = com.config in
  631. let all_scope = (not cfg.pf_captured_scope) || (not cfg.pf_locals_scope) in
  632. let vars = ref PMap.empty in
  633. let all_vars = ref PMap.empty in
  634. let vtemp = alloc_var "~" t_dynamic in
  635. let rebuild_vars = ref false in
  636. let rebuild m =
  637. PMap.fold (fun v acc -> PMap.add v.v_name v acc) m PMap.empty
  638. in
  639. let save() =
  640. let old = !vars in
  641. if cfg.pf_unique_locals || not cfg.pf_locals_scope then (fun() -> ()) else (fun() -> vars := if !rebuild_vars then rebuild old else old)
  642. in
  643. let rename vars v =
  644. let count = ref 1 in
  645. while PMap.mem (v.v_name ^ string_of_int !count) vars do
  646. incr count;
  647. done;
  648. v.v_name <- v.v_name ^ string_of_int !count;
  649. in
  650. let declare v p =
  651. (match follow v.v_type with
  652. | TAbstract ({a_path = [],"Void"},_) -> error "Arguments and variables of type Void are not allowed" p
  653. | _ -> ());
  654. (* chop escape char for all local variables generated *)
  655. if String.unsafe_get v.v_name 0 = String.unsafe_get gen_local_prefix 0 then v.v_name <- "_g" ^ String.sub v.v_name 1 (String.length v.v_name - 1);
  656. let look_vars = (if not cfg.pf_captured_scope && v.v_capture then !all_vars else !vars) in
  657. (try
  658. let v2 = PMap.find v.v_name look_vars in
  659. (*
  660. block_vars will create some wrapper-functions that are declaring
  661. the same variable twice. In that case do not perform a rename since
  662. we are sure it's actually the same variable
  663. *)
  664. if v == v2 then raise Not_found;
  665. rename look_vars v;
  666. with Not_found ->
  667. ());
  668. vars := PMap.add v.v_name v !vars;
  669. if all_scope then all_vars := PMap.add v.v_name v !all_vars;
  670. in
  671. (*
  672. This is quite a rare case, when a local variable would otherwise prevent
  673. accessing a type because it masks the type value or the package name.
  674. *)
  675. let check t =
  676. match (t_infos t).mt_path with
  677. | [], name | name :: _, _ ->
  678. let vars = if cfg.pf_locals_scope then vars else all_vars in
  679. (try
  680. let v = PMap.find name !vars in
  681. if v == vtemp then raise Not_found; (* ignore *)
  682. rename (!vars) v;
  683. rebuild_vars := true;
  684. vars := PMap.add v.v_name v !vars
  685. with Not_found ->
  686. ());
  687. vars := PMap.add name vtemp !vars
  688. in
  689. let check_type t =
  690. match follow t with
  691. | TInst (c,_) -> check (TClassDecl c)
  692. | TEnum (e,_) -> check (TEnumDecl e)
  693. | TType (t,_) -> check (TTypeDecl t)
  694. | TAbstract (a,_) -> check (TAbstractDecl a)
  695. | TMono _ | TLazy _ | TAnon _ | TDynamic _ | TFun _ -> ()
  696. in
  697. let rec loop e =
  698. match e.eexpr with
  699. | TVar (v,eo) ->
  700. if not cfg.pf_locals_scope then declare v e.epos;
  701. (match eo with None -> () | Some e -> loop e);
  702. if cfg.pf_locals_scope then declare v e.epos;
  703. | TFunction tf ->
  704. let old = save() in
  705. List.iter (fun (v,_) -> declare v e.epos) tf.tf_args;
  706. loop tf.tf_expr;
  707. old()
  708. | TBlock el ->
  709. let old = save() in
  710. List.iter loop el;
  711. old()
  712. | TFor (v,it,e1) ->
  713. loop it;
  714. let old = save() in
  715. declare v e.epos;
  716. loop e1;
  717. old()
  718. | TTry (e,catchs) ->
  719. loop e;
  720. List.iter (fun (v,e) ->
  721. let old = save() in
  722. declare v e.epos;
  723. check_type v.v_type;
  724. loop e;
  725. old()
  726. ) catchs;
  727. | TPatMatch dt ->
  728. let rec fdt dt = match dt with
  729. | DTSwitch(e,cl,dto) ->
  730. loop e;
  731. List.iter (fun (_,dt) ->
  732. let old = save() in
  733. fdt dt;
  734. old();
  735. ) cl;
  736. (match dto with None -> () | Some dt ->
  737. let old = save() in
  738. fdt dt;
  739. old())
  740. | DTBind(bl,dt) ->
  741. List.iter (fun ((v,p),e) ->
  742. declare v e.epos
  743. ) bl;
  744. fdt dt
  745. | DTExpr e -> loop e;
  746. | DTGuard(e,dt1,dt2) ->
  747. loop e;
  748. fdt dt1;
  749. (match dt2 with None -> () | Some dt -> fdt dt)
  750. | DTGoto _ ->
  751. ()
  752. in
  753. Array.iter fdt dt.dt_dt_lookup
  754. | TTypeExpr t ->
  755. check t
  756. | TNew (c,_,_) ->
  757. Type.iter loop e;
  758. check (TClassDecl c);
  759. | TCast (e,Some t) ->
  760. loop e;
  761. check t;
  762. | _ ->
  763. Type.iter loop e
  764. in
  765. declare (alloc_var "this" t_dynamic) Ast.null_pos; (* force renaming of 'this' vars in abstract *)
  766. loop e;
  767. e
  768. let check_unification com e t =
  769. begin match follow e.etype,follow t with
  770. | TEnum _,TDynamic _ ->
  771. add_feature com "may_print_enum";
  772. | _ ->
  773. ()
  774. end;
  775. e
  776. (* PASS 1 end *)
  777. (* Saves a class state so it can be restored later, e.g. after DCE or native path rewrite *)
  778. let save_class_state ctx t = match t with
  779. | TClassDecl c ->
  780. let meta = c.cl_meta and path = c.cl_path and ext = c.cl_extern in
  781. let fl = c.cl_fields and ofl = c.cl_ordered_fields and st = c.cl_statics and ost = c.cl_ordered_statics in
  782. let cst = c.cl_constructor and over = c.cl_overrides in
  783. let oflk = List.map (fun f -> f.cf_kind,f.cf_expr,f.cf_type) ofl in
  784. let ostk = List.map (fun f -> f.cf_kind,f.cf_expr,f.cf_type) ost in
  785. c.cl_restore <- (fun() ->
  786. c.cl_meta <- meta;
  787. c.cl_extern <- ext;
  788. c.cl_path <- path;
  789. c.cl_fields <- fl;
  790. c.cl_ordered_fields <- ofl;
  791. c.cl_statics <- st;
  792. c.cl_ordered_statics <- ost;
  793. c.cl_constructor <- cst;
  794. c.cl_overrides <- over;
  795. (* DCE might modify the cf_kind, so let's restore it as well *)
  796. List.iter2 (fun f (k,e,t) -> f.cf_kind <- k; f.cf_expr <- e; f.cf_type <- t;) ofl oflk;
  797. List.iter2 (fun f (k,e,t) -> f.cf_kind <- k; f.cf_expr <- e; f.cf_type <- t;) ost ostk;
  798. )
  799. | _ ->
  800. ()
  801. (* PASS 2 begin *)
  802. let is_removable_class c = c.cl_kind = KGeneric && (Codegen.has_ctor_constraint c || Meta.has Meta.Remove c.cl_meta)
  803. let remove_generic_base ctx t = match t with
  804. | TClassDecl c when is_removable_class c ->
  805. c.cl_extern <- true
  806. | _ ->
  807. ()
  808. (* Removes extern and macro fields, also checks for Void fields *)
  809. let is_removable_field ctx f =
  810. Meta.has Meta.Extern f.cf_meta || Meta.has Meta.Generic f.cf_meta
  811. || (match f.cf_kind with
  812. | Var {v_read = AccRequire (s,_)} -> true
  813. | Method MethMacro -> not ctx.in_macro
  814. | _ -> false)
  815. let remove_extern_fields ctx t = match t with
  816. | TClassDecl c ->
  817. if not (Common.defined ctx.com Define.DocGen) then begin
  818. c.cl_ordered_fields <- List.filter (fun f ->
  819. let b = is_removable_field ctx f in
  820. if b then c.cl_fields <- PMap.remove f.cf_name c.cl_fields;
  821. not b
  822. ) c.cl_ordered_fields;
  823. c.cl_ordered_statics <- List.filter (fun f ->
  824. let b = is_removable_field ctx f in
  825. if b then c.cl_statics <- PMap.remove f.cf_name c.cl_statics;
  826. not b
  827. ) c.cl_ordered_statics;
  828. end
  829. | _ ->
  830. ()
  831. (* PASS 2 end *)
  832. (* PASS 3 begin *)
  833. (* Checks if a private class' path clashes with another path *)
  834. let check_private_path ctx t = match t with
  835. | TClassDecl c when c.cl_private ->
  836. let rpath = (fst c.cl_module.m_path,"_" ^ snd c.cl_module.m_path) in
  837. if Hashtbl.mem ctx.g.types_module rpath then error ("This private class name will clash with " ^ s_type_path rpath) c.cl_pos;
  838. | _ ->
  839. ()
  840. (* Rewrites class or enum paths if @:native metadata is set *)
  841. let apply_native_paths ctx t =
  842. let get_real_path meta path =
  843. let (_,e,mp) = Meta.get Meta.Native meta in
  844. match e with
  845. | [Ast.EConst (Ast.String name),p] ->
  846. (Meta.RealPath,[Ast.EConst (Ast.String (s_type_path path)),p],mp),parse_path name
  847. | _ ->
  848. error "String expected" mp
  849. in
  850. try
  851. (match t with
  852. | TClassDecl c ->
  853. let meta,path = get_real_path c.cl_meta c.cl_path in
  854. c.cl_meta <- meta :: c.cl_meta;
  855. c.cl_path <- path;
  856. | TEnumDecl e ->
  857. let meta,path = get_real_path e.e_meta e.e_path in
  858. e.e_meta <- meta :: e.e_meta;
  859. e.e_path <- path;
  860. | TAbstractDecl a ->
  861. let meta,path = get_real_path a.a_meta a.a_path in
  862. a.a_meta <- meta :: a.a_meta;
  863. a.a_path <- path;
  864. | _ ->
  865. ())
  866. with Not_found ->
  867. ()
  868. (* Adds the __rtti field if required *)
  869. let add_rtti ctx t =
  870. let rec has_rtti c =
  871. Meta.has Meta.Rtti c.cl_meta || match c.cl_super with None -> false | Some (csup,_) -> has_rtti csup
  872. in
  873. match t with
  874. | TClassDecl c when has_rtti c && not (PMap.mem "__rtti" c.cl_statics) ->
  875. let f = mk_field "__rtti" ctx.t.tstring c.cl_pos in
  876. let str = Genxml.gen_type_string ctx.com t in
  877. f.cf_expr <- Some (mk (TConst (TString str)) f.cf_type c.cl_pos);
  878. c.cl_ordered_statics <- f :: c.cl_ordered_statics;
  879. c.cl_statics <- PMap.add f.cf_name f c.cl_statics;
  880. | _ ->
  881. ()
  882. (* Adds member field initializations as assignments to the constructor *)
  883. let add_field_inits ctx t =
  884. let is_as3 = Common.defined ctx.com Define.As3 && not ctx.in_macro in
  885. let apply c =
  886. let ethis = mk (TConst TThis) (TInst (c,List.map snd c.cl_types)) c.cl_pos in
  887. (* TODO: we have to find a variable name which is not used in any of the functions *)
  888. let v = alloc_var "_g" ethis.etype in
  889. let need_this = ref false in
  890. let inits,fields = List.fold_left (fun (inits,fields) cf ->
  891. match cf.cf_kind,cf.cf_expr with
  892. | Var _, Some _ ->
  893. if is_as3 then (inits, cf :: fields) else (cf :: inits, cf :: fields)
  894. | Method MethDynamic, Some e when is_as3 ->
  895. (* TODO : this would have a better place in genSWF9 I think - NC *)
  896. (* we move the initialization of dynamic functions to the constructor and also solve the
  897. 'this' problem along the way *)
  898. let rec use_this v e = match e.eexpr with
  899. | TConst TThis ->
  900. need_this := true;
  901. mk (TLocal v) v.v_type e.epos
  902. | _ -> Type.map_expr (use_this v) e
  903. in
  904. let e = Type.map_expr (use_this v) e in
  905. let cf2 = {cf with cf_expr = Some e} in
  906. (* if the method is an override, we have to remove the class field to not get invalid overrides *)
  907. let fields = if List.memq cf c.cl_overrides then begin
  908. c.cl_fields <- PMap.remove cf.cf_name c.cl_fields;
  909. fields
  910. end else
  911. cf2 :: fields
  912. in
  913. (cf2 :: inits, fields)
  914. | _ -> (inits, cf :: fields)
  915. ) ([],[]) c.cl_ordered_fields in
  916. c.cl_ordered_fields <- (List.rev fields);
  917. match inits with
  918. | [] -> ()
  919. | _ ->
  920. let el = List.map (fun cf ->
  921. match cf.cf_expr with
  922. | None -> assert false
  923. | Some e ->
  924. let lhs = mk (TField(ethis,FInstance (c,cf))) cf.cf_type e.epos in
  925. cf.cf_expr <- None;
  926. let eassign = mk (TBinop(OpAssign,lhs,e)) e.etype e.epos in
  927. if is_as3 then begin
  928. let echeck = mk (TBinop(OpEq,lhs,(mk (TConst TNull) lhs.etype e.epos))) ctx.com.basic.tbool e.epos in
  929. mk (TIf(echeck,eassign,None)) eassign.etype e.epos
  930. end else
  931. eassign;
  932. ) inits in
  933. let el = if !need_this then (mk (TVar((v, Some ethis))) ethis.etype ethis.epos) :: el else el in
  934. match c.cl_constructor with
  935. | None ->
  936. let ct = TFun([],ctx.com.basic.tvoid) in
  937. let ce = mk (TFunction {
  938. tf_args = [];
  939. tf_type = ctx.com.basic.tvoid;
  940. tf_expr = mk (TBlock el) ctx.com.basic.tvoid c.cl_pos;
  941. }) ct c.cl_pos in
  942. let ctor = mk_field "new" ct c.cl_pos in
  943. ctor.cf_kind <- Method MethNormal;
  944. c.cl_constructor <- Some { ctor with cf_expr = Some ce };
  945. | Some cf ->
  946. match cf.cf_expr with
  947. | Some { eexpr = TFunction f } ->
  948. let bl = match f.tf_expr with {eexpr = TBlock b } -> b | x -> [x] in
  949. let ce = mk (TFunction {f with tf_expr = mk (TBlock (el @ bl)) ctx.com.basic.tvoid c.cl_pos }) cf.cf_type cf.cf_pos in
  950. c.cl_constructor <- Some {cf with cf_expr = Some ce }
  951. | _ ->
  952. assert false
  953. in
  954. match t with
  955. | TClassDecl c ->
  956. apply c
  957. | _ ->
  958. ()
  959. (* Adds the __meta__ field if required *)
  960. let add_meta_field ctx t = match t with
  961. | TClassDecl c ->
  962. (match Codegen.build_metadata ctx.com t with
  963. | None -> ()
  964. | Some e ->
  965. let f = mk_field "__meta__" t_dynamic c.cl_pos in
  966. f.cf_expr <- Some e;
  967. c.cl_ordered_statics <- f :: c.cl_ordered_statics;
  968. c.cl_statics <- PMap.add f.cf_name f c.cl_statics)
  969. | _ ->
  970. ()
  971. (* Removes interfaces tagged with @:remove metadata *)
  972. let check_remove_metadata ctx t = match t with
  973. | TClassDecl c ->
  974. c.cl_implements <- List.filter (fun (c,_) -> not (Meta.has Meta.Remove c.cl_meta)) c.cl_implements;
  975. | _ ->
  976. ()
  977. (* Checks for Void class fields *)
  978. let check_void_field ctx t = match t with
  979. | TClassDecl c ->
  980. let check f =
  981. match follow f.cf_type with TAbstract({a_path=[],"Void"},_) -> error "Fields of type Void are not allowed" f.cf_pos | _ -> ();
  982. in
  983. List.iter check c.cl_ordered_fields;
  984. List.iter check c.cl_ordered_statics;
  985. | _ ->
  986. ()
  987. (* PASS 3 end *)
  988. let run_expression_filters ctx filters t =
  989. match t with
  990. | TClassDecl c when is_removable_class c -> ()
  991. | TClassDecl c ->
  992. let process_field f =
  993. match f.cf_expr with
  994. | Some e when not (is_removable_field ctx f) ->
  995. Codegen.Abstract.cast_stack := f :: !Codegen.Abstract.cast_stack;
  996. f.cf_expr <- Some (List.fold_left (fun e f -> f e) e filters);
  997. Codegen.Abstract.cast_stack := List.tl !Codegen.Abstract.cast_stack;
  998. | _ -> ()
  999. in
  1000. List.iter process_field c.cl_ordered_fields;
  1001. List.iter process_field c.cl_ordered_statics;
  1002. (match c.cl_constructor with
  1003. | None -> ()
  1004. | Some f -> process_field f);
  1005. (match c.cl_init with
  1006. | None -> ()
  1007. | Some e ->
  1008. c.cl_init <- Some (List.fold_left (fun e f -> f e) e filters));
  1009. | TEnumDecl _ -> ()
  1010. | TTypeDecl _ -> ()
  1011. | TAbstractDecl _ -> ()
  1012. let pp_counter = ref 1
  1013. let post_process ctx filters t =
  1014. (* ensure that we don't process twice the same (cached) module *)
  1015. let m = (t_infos t).mt_module.m_extra in
  1016. if m.m_processed = 0 then m.m_processed <- !pp_counter;
  1017. if m.m_processed = !pp_counter then
  1018. run_expression_filters ctx filters t
  1019. let post_process_end() =
  1020. incr pp_counter
  1021. let run com tctx main =
  1022. if com.display = DMUsage then
  1023. Codegen.detect_usage com;
  1024. if not (Common.defined com Define.NoDeprecationWarnings) then
  1025. Codegen.DeprecationCheck.run com;
  1026. (* PASS 1: general expression filters *)
  1027. let filters = [
  1028. Codegen.UnificationCallback.run (check_unification com);
  1029. Codegen.Abstract.handle_abstract_casts tctx;
  1030. blockify_ast;
  1031. (match com.platform with
  1032. | Cpp | Flash8 -> (fun e ->
  1033. let save = save_locals tctx in
  1034. let e = handle_side_effects com (Typecore.gen_local tctx) e in
  1035. save();
  1036. e)
  1037. | _ -> fun e -> e);
  1038. if com.foptimize then (fun e -> Optimizer.reduce_expression tctx (Optimizer.inline_constructors tctx e)) else Optimizer.sanitize tctx;
  1039. check_local_vars_init;
  1040. captured_vars com;
  1041. ] in
  1042. List.iter (post_process tctx filters) com.types;
  1043. post_process_end();
  1044. List.iter (fun f -> f()) (List.rev com.filters);
  1045. (* save class state *)
  1046. List.iter (save_class_state tctx) com.types;
  1047. (* PASS 2: destructive type and expression filters *)
  1048. let filters = [
  1049. promote_complex_rhs com;
  1050. if com.config.pf_add_final_return then add_final_return else (fun e -> e);
  1051. rename_local_vars com; (* TODO: it shouldn't be necessary to have this here if promote_complex_rhs can generate proper variable names *)
  1052. ] in
  1053. List.iter (fun t ->
  1054. remove_generic_base tctx t;
  1055. remove_extern_fields tctx t;
  1056. run_expression_filters tctx filters t;
  1057. ) com.types;
  1058. (* update cache dependencies before DCE is run *)
  1059. Codegen.update_cache_dependencies com;
  1060. (* DCE *)
  1061. let dce_mode = (try Common.defined_value com Define.Dce with _ -> "no") in
  1062. if not (Common.defined com Define.As3 || dce_mode = "no" || Common.defined com Define.DocGen) then Dce.run com main (dce_mode = "full" && not (Common.defined com Define.Interp));
  1063. (* always filter empty abstract implementation classes (issue #1885) *)
  1064. List.iter (fun mt -> match mt with
  1065. | TClassDecl({cl_kind = KAbstractImpl _} as c) when c.cl_ordered_statics = [] && c.cl_ordered_fields = [] && not (Meta.has Meta.Used c.cl_meta) -> c.cl_extern <- true
  1066. | _ -> ()
  1067. ) com.types;
  1068. (* PASS 3: type filters *)
  1069. let type_filters = [
  1070. check_private_path;
  1071. apply_native_paths;
  1072. add_rtti;
  1073. (match com.platform with | Java | Cs -> (fun _ _ -> ()) | _ -> add_field_inits);
  1074. add_meta_field;
  1075. check_remove_metadata;
  1076. check_void_field;
  1077. ] in
  1078. List.iter (fun t -> List.iter (fun f -> f tctx t) type_filters) com.types