filters.ml 39 KB

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