matcher.ml 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441
  1. (*
  2. * Copyright (C)2005-2013 Haxe Foundation
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20. * DEALINGS IN THE SOFTWARE.
  21. *)
  22. open Ast
  23. open Common
  24. open Type
  25. open Typecore
  26. type pvar = tvar * pos
  27. type con_def =
  28. | CEnum of tenum * tenum_field
  29. | CConst of tconstant
  30. | CAny
  31. | CType of module_type
  32. | CArray of int
  33. | CFields of int * (string * tclass_field) list
  34. | CExpr of texpr
  35. and con = {
  36. c_def : con_def;
  37. c_type : t;
  38. c_pos : pos;
  39. }
  40. and st_def =
  41. | SVar of tvar
  42. | SField of st * tclass_field
  43. | SEnum of st * tenum_field * int
  44. | SArray of st * int
  45. | STuple of st * int * int
  46. and st = {
  47. st_def : st_def;
  48. st_type : t;
  49. st_pos : pos;
  50. }
  51. and dt =
  52. | Switch of st * (con * dt) list
  53. | Bind of ((tvar * pos) * st) list * dt
  54. | Goto of int
  55. | Expr of int
  56. | Guard of int * dt * dt option
  57. (* Pattern *)
  58. type pat_def =
  59. | PAny
  60. | PVar of pvar
  61. | PCon of con * pat list
  62. | POr of pat * pat
  63. | PBind of pvar * pat
  64. | PTuple of pat array
  65. and pat = {
  66. p_def : pat_def;
  67. p_type : t;
  68. p_pos : pos;
  69. }
  70. type out = {
  71. mutable o_pos : pos;
  72. o_id : int;
  73. o_catch_all : bool;
  74. mutable o_num_paths : int;
  75. }
  76. type pat_vec = pat array * out
  77. type pat_matrix = pat_vec list
  78. (* Context *)
  79. type pattern_ctx = {
  80. mutable pc_locals : (string, pvar) PMap.t;
  81. mutable pc_sub_vars : (string, pvar) PMap.t option;
  82. mutable pc_reify : bool;
  83. mutable pc_is_complex : bool;
  84. }
  85. type matcher = {
  86. ctx : typer;
  87. need_val : bool;
  88. dt_lut : dt DynArray.t;
  89. dt_cache : (dt,int) Hashtbl.t;
  90. mutable dt_count : int;
  91. mutable outcomes : out list;
  92. mutable toplevel_or : bool;
  93. mutable has_extractor : bool;
  94. mutable expr_map : (int,texpr * texpr option) PMap.t;
  95. mutable is_exhaustive : bool;
  96. }
  97. type type_finiteness =
  98. | Infinite (* type has inifite constructors (e.g. Int, String) *)
  99. | CompileTimeFinite (* type is considered finite only at compile-time but has inifite possible run-time values (enum abstracts) *)
  100. | RunTimeFinite (* type is truly finite (Bool, enums) *)
  101. exception Not_exhaustive of pat * st
  102. exception Unrecognized_pattern of Ast.expr
  103. let arity con = match con.c_def with
  104. | CEnum (_,{ef_type = TFun(args,_)}) -> List.length args
  105. | CEnum _ -> 0
  106. | CConst _ -> 0
  107. | CType mt -> 0
  108. | CArray i -> i
  109. | CFields (i,_) -> i
  110. | CExpr _ -> 0
  111. | CAny -> 0
  112. let mk_st def t p = {
  113. st_def = def;
  114. st_type = t;
  115. st_pos = p;
  116. }
  117. let mk_out mctx id e eg is_catch_all p =
  118. let out = {
  119. o_pos = p;
  120. o_id = id;
  121. o_catch_all = is_catch_all;
  122. o_num_paths = 0;
  123. } in
  124. mctx.outcomes <- out :: mctx.outcomes;
  125. mctx.expr_map <- PMap.add id (e,eg) mctx.expr_map;
  126. out
  127. let clone_out mctx out p =
  128. let out = {out with o_pos = p; } in
  129. mctx.outcomes <- out :: mctx.outcomes;
  130. out
  131. let get_guard mctx id =
  132. snd (PMap.find id mctx.expr_map)
  133. let get_expr mctx id =
  134. fst (PMap.find id mctx.expr_map)
  135. let mk_pat pdef t p = {
  136. p_def = pdef;
  137. p_type = t;
  138. p_pos = p;
  139. }
  140. let mk_con cdef t p = {
  141. c_def = cdef;
  142. c_type = t;
  143. c_pos = p;
  144. }
  145. let mk_con_pat cdef pl t p = mk_pat (PCon(mk_con cdef t p,pl)) t p
  146. let mk_any t p = mk_pat PAny t p
  147. let any = mk_any t_dynamic Ast.null_pos
  148. let fake_tuple_type = TInst(mk_class null_module ([],"-Tuple") null_pos, [])
  149. let mk_type_pat ctx mt t p =
  150. let rec loop = function
  151. | TClassDecl _ -> "Class"
  152. | TEnumDecl _ -> "Enum"
  153. | TAbstractDecl a when Meta.has Meta.RuntimeValue a.a_meta -> "Class"
  154. | TTypeDecl t ->
  155. begin match follow (monomorphs t.t_params t.t_type) with
  156. | TInst(c,_) -> loop (TClassDecl c)
  157. | TEnum(en,_) -> loop (TEnumDecl en)
  158. | TAbstract(a,_) -> loop (TAbstractDecl a)
  159. | _ -> error "Cannot use this type as a value" p
  160. end
  161. | _ -> error "Cannot use this type as a value" p
  162. in
  163. let tcl = Typeload.load_instance ctx {tname=loop mt;tpackage=[];tsub=None;tparams=[]} p true in
  164. let t2 = match tcl with TAbstract(a,_) -> TAbstract(a,[mk_mono()]) | _ -> assert false in
  165. unify ctx t t2 p;
  166. mk_con_pat (CType mt) [] t2 p
  167. let mk_subs st con =
  168. let map = match follow st.st_type with
  169. | TInst(c,pl) -> apply_params c.cl_params pl
  170. | TEnum(en,pl) -> apply_params en.e_params pl
  171. | TAbstract(a,pl) -> apply_params a.a_params pl
  172. | _ -> fun t -> t
  173. in
  174. match con.c_def with
  175. | CFields (_,fl) -> List.map (fun (s,cf) -> mk_st (SField(st,cf)) (map cf.cf_type) st.st_pos) fl
  176. | CEnum (en,({ef_type = TFun _} as ef)) ->
  177. let rec loop t = match follow t with
  178. | TEnum(_,pl) -> pl
  179. | TAbstract({a_path = [],"EnumValue"},[]) -> []
  180. | TAbstract(a,pl) -> loop (Abstract.get_underlying_type a pl)
  181. | _ -> []
  182. in
  183. let pl = loop con.c_type in
  184. begin match apply_params en.e_params pl (monomorphs ef.ef_params ef.ef_type) with
  185. | TFun(args,r) ->
  186. ExtList.List.mapi (fun i (_,_,t) ->
  187. mk_st (SEnum(st,ef,i)) t st.st_pos
  188. ) args
  189. | _ ->
  190. assert false
  191. end
  192. | CArray 0 -> []
  193. | CArray i ->
  194. let t = match follow con.c_type with TInst({cl_path=[],"Array"},[t]) -> t | TDynamic _ as t -> t | _ -> assert false in
  195. ExtList.List.init i (fun i -> mk_st (SArray(st,i)) t st.st_pos)
  196. | CEnum _ | CConst _ | CType _ | CExpr _ | CAny ->
  197. []
  198. let get_tuple_params t = match t with
  199. | TFun(tl,tr) when tr == fake_tuple_type -> Some tl
  200. | _ -> None
  201. (* Printing *)
  202. let s_type = s_type (print_context())
  203. let rec s_con con = match con.c_def with
  204. | CEnum(_,ef) -> ef.ef_name
  205. | CAny -> "_"
  206. | CConst c -> s_const c
  207. | CType mt -> s_type_path (t_path mt)
  208. | CArray i -> "[" ^(string_of_int i) ^ "]"
  209. | CFields (_,fl) -> String.concat "," (List.map (fun (s,_) -> s) fl)
  210. | CExpr e -> s_expr s_type e
  211. let rec s_pat pat = match pat.p_def with
  212. | PVar (v,_) -> v.v_name
  213. | PCon (c,[]) -> s_con c
  214. | PCon (c,pl) -> s_con c ^ "(" ^ (String.concat "," (List.map s_pat pl)) ^ ")"
  215. | POr (pat1,pat2) -> s_pat pat1 ^ " | " ^ s_pat pat2
  216. | PAny -> "_"
  217. | PBind((v,_),pat) -> v.v_name ^ "=" ^ s_pat pat
  218. | PTuple pl -> "(" ^ (String.concat " " (Array.to_list (Array.map s_pat pl))) ^ ")"
  219. let rec s_pat_vec pl =
  220. String.concat " " (Array.to_list (Array.map s_pat pl))
  221. let rec s_pat_matrix pmat =
  222. String.concat "\n" (List.map (fun (pl,out) -> (s_pat_vec pl) ^ "->" ^ "") pmat)
  223. let st_args l r v =
  224. (if l > 0 then (String.concat "," (ExtList.List.make l "_")) ^ "," else "")
  225. ^ v ^
  226. (if r > 0 then "," ^ (String.concat "," (ExtList.List.make r "_")) else "")
  227. let rec s_st st =
  228. (match st.st_def with
  229. | SVar v -> v.v_name
  230. | SEnum (st,ef,i) -> s_st st ^ "." ^ ef.ef_name ^ "." ^ (string_of_int i)
  231. | SArray (st,i) -> s_st st ^ "[" ^ (string_of_int i) ^ "]"
  232. | STuple (st,i,a) -> "(" ^ (st_args i (a - i - 1) (s_st st)) ^ ")"
  233. | SField (st,cf) -> s_st st ^ "." ^ cf.cf_name)
  234. (* Pattern parsing *)
  235. let unify_enum_field en pl ef t =
  236. let t2 = match follow ef.ef_type with
  237. | TFun(_,r) -> r
  238. | t2 -> t2
  239. in
  240. let t2 = (apply_params en.e_params pl (monomorphs ef.ef_params t2)) in
  241. Type.unify t2 t
  242. let unify ctx a b p =
  243. try unify_raise ctx a b p with Error (Unify l,p) -> error (error_msg (Unify l)) p
  244. let rec is_value_type = function
  245. | TMono r ->
  246. (match !r with None -> false | Some t -> is_value_type t)
  247. | TType (t,tl) ->
  248. is_value_type (apply_params t.t_params tl t.t_type)
  249. | TInst({cl_path=[],"String"},[]) ->
  250. true
  251. | TAbstract _ ->
  252. true
  253. | _ ->
  254. false
  255. (* Determines if a type allows null-matching. This is similar to is_nullable, but it infers Null<T> on monomorphs,
  256. and enums are not considered nullable *)
  257. let rec matches_null ctx t = match t with
  258. | TMono r ->
  259. (match !r with None -> r := Some (ctx.t.tnull (mk_mono())); true | Some t -> matches_null ctx t)
  260. | TType ({ t_path = ([],"Null") },[_]) ->
  261. true
  262. | TLazy f ->
  263. matches_null ctx (!f())
  264. | TType (t,tl) ->
  265. matches_null ctx (apply_params t.t_params tl t.t_type)
  266. | TFun _ | TEnum _ ->
  267. false
  268. | TAbstract (a,_) -> not (Meta.has Meta.NotNull a.a_meta)
  269. | _ ->
  270. true
  271. let to_pattern ctx e t =
  272. let perror p = error "Unrecognized pattern" p in
  273. let verror n p = error ("Variable " ^ n ^ " must appear exactly once in each sub-pattern") p in
  274. let mk_var tctx s t p =
  275. let v = match tctx.pc_sub_vars with
  276. | Some vmap -> fst (try PMap.find s vmap with Not_found -> verror s p)
  277. | None -> alloc_var s t
  278. in
  279. unify ctx t v.v_type p;
  280. if PMap.mem s tctx.pc_locals then verror s p;
  281. tctx.pc_locals <- PMap.add s (v,p) tctx.pc_locals;
  282. v
  283. in
  284. let rec loop pctx e t =
  285. let p = pos e in
  286. match fst e with
  287. | ECheckType(e, CTPath({tpackage=["haxe";"macro"]; tname="Expr"})) ->
  288. let old = pctx.pc_reify in
  289. pctx.pc_reify <- true;
  290. let e = loop pctx e t in
  291. pctx.pc_reify <- old;
  292. e
  293. | EParenthesis e ->
  294. loop pctx e t
  295. | ECast(e1,None) ->
  296. loop pctx e1 t
  297. | EConst(Ident "null") ->
  298. if not (matches_null ctx t) then error ("Null-patterns are only allowed on nullable types (found " ^ (s_type t) ^ ")") p;
  299. mk_con_pat (CConst TNull) [] t p
  300. | EConst((Ident ("false" | "true") | Int _ | String _ | Float _) as c) ->
  301. let e = Codegen.type_constant ctx.com c p in
  302. unify ctx e.etype t p;
  303. let c = match e.eexpr with TConst c -> c | _ -> assert false in
  304. mk_con_pat (CConst c) [] t p
  305. | EMeta((Meta.Macro,[],_),(ECall (e1,args),_)) ->
  306. let path, field, args = Codegen.get_macro_path ctx e1 args p in
  307. begin match ctx.g.do_macro ctx MExpr path field args p with
  308. | Some e -> loop pctx e t
  309. | None -> error "Macro failure" p
  310. end
  311. | EField _ ->
  312. let e = type_expr ctx e (WithType t) in
  313. let e = match Optimizer.make_constant_expression ctx ~concat_strings:true e with Some e -> e | None -> e in
  314. (match e.eexpr with
  315. | TConst c | TCast({eexpr = TConst c},None) ->
  316. mk_con_pat (CConst c) [] t p
  317. | TTypeExpr mt ->
  318. mk_type_pat ctx mt t p
  319. | TField(_, FStatic(_,cf)) when is_value_type cf.cf_type ->
  320. mk_con_pat (CExpr e) [] cf.cf_type p
  321. | TField(_, FEnum(en,ef)) ->
  322. begin try
  323. unify_enum_field en (List.map (fun _ -> mk_mono()) en.e_params) ef t
  324. with Unify_error l ->
  325. error (error_msg (Unify l)) p
  326. end;
  327. mk_con_pat (CEnum(en,ef)) [] t p
  328. | _ -> error "Constant expression expected" p)
  329. | ECall(ec,el) ->
  330. let ec = type_expr ctx ec (WithType t) in
  331. (match follow ec.etype with
  332. | TEnum(en,pl)
  333. | TFun(_,TEnum(en,pl)) ->
  334. let ef = match ec.eexpr with
  335. | TField (_,FEnum (_,f)) -> f
  336. | _ -> error ("Expected constructor for enum " ^ (s_type_path en.e_path)) p
  337. in
  338. let monos = List.map (fun _ -> mk_mono()) ef.ef_params in
  339. let tl,r = match apply_params en.e_params pl (apply_params ef.ef_params monos ef.ef_type) with
  340. | TFun(args,r) ->
  341. unify ctx r t p;
  342. List.map (fun (n,_,t) -> t) args,r
  343. | _ -> error "No arguments expected" p
  344. in
  345. let rec loop2 i el tl = match el,tl with
  346. | (EConst(Ident "_"),pany) :: [], t :: tl ->
  347. let pat = mk_pat PAny t_dynamic pany in
  348. (ExtList.List.make ((List.length tl) + 1) pat)
  349. | e :: el, t :: tl ->
  350. let pat = loop pctx e t in
  351. pat :: loop2 (i + 1) el tl
  352. | e :: _, [] ->
  353. error "Too many arguments" (pos e);
  354. | [],_ :: _ ->
  355. error "Not enough arguments" p;
  356. | [],[] ->
  357. []
  358. in
  359. let el = loop2 0 el tl in
  360. List.iter2 (fun m (_,t) -> match follow m with TMono _ -> Type.unify m t | _ -> ()) monos ef.ef_params;
  361. pctx.pc_is_complex <- true;
  362. mk_con_pat (CEnum(en,ef)) el r p
  363. | _ -> perror p)
  364. | EConst(Ident "_") ->
  365. begin match get_tuple_params t with
  366. | Some tl ->
  367. let pl = List.map (fun (_,_,t) -> mk_any t p) tl in
  368. mk_pat (PTuple (Array.of_list pl)) t_dynamic p
  369. | None ->
  370. mk_any t p
  371. end
  372. | EConst(Ident s) ->
  373. begin try
  374. let ec = match follow t with
  375. | TEnum(en,pl) ->
  376. let ef = try
  377. PMap.find s en.e_constrs
  378. with Not_found when not (is_lower_ident s) ->
  379. error (string_error s en.e_names ("Expected constructor for enum " ^ (s_type_path en.e_path))) p
  380. in
  381. (match ef.ef_type with
  382. | TFun (args,_) ->
  383. let msg = Printf.sprintf "Enum constructor %s.%s requires parameters %s"
  384. (s_type_path en.e_path)
  385. ef.ef_name
  386. (String.concat ", " (List.map (fun (n,_,t) -> n ^ ":" ^ (s_type t)) args))
  387. in
  388. error msg p
  389. | _ -> ());
  390. let et = mk (TTypeExpr (TEnumDecl en)) (TAnon { a_fields = PMap.empty; a_status = ref (EnumStatics en) }) p in
  391. mk (TField (et,FEnum (en,ef))) (apply_params en.e_params pl ef.ef_type) p
  392. | TAbstract({a_impl = Some c} as a,_) when Meta.has Meta.Enum a.a_meta ->
  393. let cf = PMap.find s c.cl_statics in
  394. Type.unify (follow cf.cf_type) t;
  395. let e = begin match cf.cf_expr with
  396. | Some ({eexpr = TConst c | TCast({eexpr = TConst c},None)} as e) -> e
  397. | _ -> raise Not_found
  398. end in
  399. e
  400. | _ ->
  401. let old = ctx.untyped in
  402. ctx.untyped <- true;
  403. let e = try type_expr ctx e (WithType t) with _ -> ctx.untyped <- old; raise Not_found in
  404. ctx.untyped <- old;
  405. e
  406. in
  407. let ec = match Optimizer.make_constant_expression ctx ~concat_strings:true ec with Some e -> e | None -> ec in
  408. (match ec.eexpr with
  409. | TField (_,FEnum (en,ef)) ->
  410. begin try unify_raise ctx ec.etype t ec.epos with Error (Unify _,_) -> raise Not_found end;
  411. begin try
  412. unify_enum_field en (List.map (fun _ -> mk_mono()) en.e_params) ef t;
  413. with Unify_error l ->
  414. error (error_msg (Unify l)) p
  415. end;
  416. mk_con_pat (CEnum(en,ef)) [] t p
  417. | TConst c | TCast({eexpr = TConst c},None) ->
  418. begin try unify_raise ctx ec.etype t ec.epos with Error (Unify _,_) -> raise Not_found end;
  419. unify ctx ec.etype t p;
  420. mk_con_pat (CConst c) [] t p
  421. | TTypeExpr mt ->
  422. mk_type_pat ctx mt t p
  423. | _ ->
  424. raise Not_found);
  425. with Not_found ->
  426. begin match get_tuple_params t with
  427. | Some tl ->
  428. let s = String.concat "," (List.map (fun (_,_,t) -> s_type t) tl) in
  429. error ("Pattern should be tuple [" ^ s ^ "]") p
  430. | None ->
  431. if not (is_lower_ident s) && s.[0] <> '`' then error "Capture variables must be lower-case" p;
  432. let v = mk_var pctx s t p in
  433. mk_pat (PVar (v,p)) v.v_type p
  434. end
  435. end
  436. | (EObjectDecl fl) ->
  437. let is_matchable cf = match cf.cf_kind with Method _ -> false | _ -> true in
  438. let is_valid_field_name fields co n p =
  439. try
  440. let cf = PMap.find n fields in
  441. begin match co with
  442. | Some c when not (Typer.can_access ctx c cf false) -> error ("Cannot match against private field " ^ n) p
  443. | _ -> ()
  444. end
  445. with Not_found ->
  446. error ((s_type t) ^ " has no field " ^ n ^ " that can be matched against") p;
  447. in
  448. pctx.pc_is_complex <- true;
  449. let loop_fields fields =
  450. let sl,pl,i = PMap.foldi (fun n cf (sl,pl,i) ->
  451. if not (is_matchable cf) then
  452. sl,pl,i
  453. else
  454. let pat = try
  455. if pctx.pc_reify && cf.cf_name = "pos" then raise Not_found;
  456. loop pctx (List.assoc cf.cf_name fl) cf.cf_type
  457. with Not_found ->
  458. (mk_any cf.cf_type p)
  459. in
  460. (n,cf) :: sl,pat :: pl,i + 1
  461. ) fields ([],[],0) in
  462. mk_con_pat (CFields(i,sl)) pl t p
  463. in
  464. let fields = match follow t with
  465. | TAnon {a_fields = fields} ->
  466. fields
  467. | TInst(c,tl) ->
  468. let fields = ref PMap.empty in
  469. let rec loop c tl =
  470. begin match c.cl_super with
  471. | Some (csup,tlsup) -> loop csup (List.map (apply_params c.cl_params tl) tlsup)
  472. | None -> ()
  473. end;
  474. PMap.iter (fun n cf -> fields := PMap.add n {cf with cf_type = apply_params c.cl_params tl (monomorphs cf.cf_params cf.cf_type)} !fields) c.cl_fields
  475. in
  476. loop c tl;
  477. !fields
  478. | TAbstract({a_impl = Some c} as a,tl) ->
  479. let fields = List.fold_left (fun acc cf ->
  480. if Meta.has Meta.Impl cf.cf_meta then
  481. PMap.add cf.cf_name cf acc
  482. else acc
  483. ) PMap.empty c.cl_ordered_statics in
  484. PMap.map (fun cf -> {cf with cf_type = apply_params a.a_params tl (monomorphs cf.cf_params cf.cf_type)}) fields
  485. | _ ->
  486. error ((s_type t) ^ " cannot be matched against a structure") p
  487. in
  488. List.iter (fun (n,(_,p)) -> is_valid_field_name fields None n p) fl;
  489. loop_fields fields
  490. | EArrayDecl [] ->
  491. mk_con_pat (CArray 0) [] t p
  492. | EArrayDecl el ->
  493. pctx.pc_is_complex <- true;
  494. begin match follow t with
  495. | TInst({cl_path=[],"Array"},[t2]) | (TDynamic _ as t2) ->
  496. let pl = ExtList.List.mapi (fun i e ->
  497. loop pctx e t2
  498. ) el in
  499. mk_con_pat (CArray (List.length el)) pl t p
  500. | TFun(tl,tr) when tr == fake_tuple_type ->
  501. let pl = try
  502. List.map2 (fun e (_,_,t) -> loop pctx e t) el tl
  503. with Invalid_argument _ ->
  504. error ("Invalid number of arguments: expected " ^ (string_of_int (List.length tl)) ^ ", found " ^ (string_of_int (List.length el))) p
  505. in
  506. mk_pat (PTuple (Array.of_list pl)) t p
  507. | _ ->
  508. error ((s_type t) ^ " should be Array") p
  509. end
  510. | EBinop(OpAssign,(EConst(Ident s),p2),e1) ->
  511. let v = mk_var pctx s t p in
  512. let pat1 = loop pctx e1 t in
  513. mk_pat (PBind((v,p),pat1)) t p2
  514. | EBinop(OpOr,(EBinop(OpOr,e1,e2),p2),e3) ->
  515. loop pctx (EBinop(OpOr,e1,(EBinop(OpOr,e2,e3),p2)),p) t
  516. | EBinop(OpOr,e1,e2) ->
  517. let old = pctx.pc_locals in
  518. let pat1 = loop pctx e1 t in
  519. begin match pat1.p_def with
  520. | PAny | PVar _ ->
  521. display_error ctx "This pattern is unused" (pos e2);
  522. pat1
  523. | _ ->
  524. let pctx2 = {
  525. pc_sub_vars = Some pctx.pc_locals;
  526. pc_locals = old;
  527. pc_reify = pctx.pc_reify;
  528. pc_is_complex = pctx.pc_is_complex;
  529. } in
  530. let pat2 = loop pctx2 e2 t in
  531. pctx.pc_is_complex <- pctx2.pc_is_complex;
  532. PMap.iter (fun s (_,p) -> if not (PMap.mem s pctx2.pc_locals) then verror s p) pctx.pc_locals;
  533. mk_pat (POr(pat1,pat2)) pat2.p_type (punion pat1.p_pos pat2.p_pos);
  534. end
  535. | _ ->
  536. raise (Unrecognized_pattern e)
  537. in
  538. let pctx = {
  539. pc_locals = PMap.empty;
  540. pc_sub_vars = None;
  541. pc_reify = false;
  542. pc_is_complex = false;
  543. } in
  544. let x = loop pctx e t in
  545. x, pctx.pc_locals, pctx.pc_is_complex
  546. let get_pattern_locals ctx e t =
  547. try
  548. let _,locals,_ = to_pattern ctx e t in
  549. PMap.foldi (fun n v acc -> PMap.add n v acc) locals PMap.empty
  550. with Unrecognized_pattern _ ->
  551. PMap.empty
  552. (* Match compilation *)
  553. let expr_eq e1 e2 = e1 == e2 || match e1.eexpr,e2.eexpr with
  554. | TConst ct1,TConst ct2 ->
  555. ct1 = ct2
  556. | TField(_,FStatic(c1,cf1)),TField(_,FStatic(c2,cf2)) ->
  557. c1 == c2 && cf1.cf_name = cf2.cf_name
  558. | _ ->
  559. false
  560. let unify_con con1 con2 = match con1.c_def,con2.c_def with
  561. | CExpr e1, CExpr e2 ->
  562. expr_eq e1 e2
  563. | CConst c1,CConst c2 ->
  564. c1 = c2
  565. | CEnum(e1,ef1),CEnum(e2,ef2) ->
  566. e1 == e2 && ef1.ef_name = ef2.ef_name
  567. | CFields (i1,fl1),CFields (i2,fl2) ->
  568. (try
  569. List.iter (fun (s,_) -> if not (List.mem_assoc s fl1) then raise Not_found) fl2;
  570. true
  571. with Not_found ->
  572. false)
  573. | CType mt1,CType mt2 ->
  574. t_path mt1 = t_path mt2
  575. | CArray a1, CArray a2 ->
  576. a1 == a2
  577. | CAny, CAny ->
  578. true
  579. | _ ->
  580. false
  581. let array_tl arr = Array.sub arr 1 (Array.length arr - 1)
  582. let spec mctx con pmat =
  583. let a = arity con in
  584. let r = DynArray.create () in
  585. let add pv out =
  586. DynArray.add r (pv,out)
  587. in
  588. let rec loop2 pv out = match pv.(0).p_def with
  589. | PCon(c2,pl) when unify_con c2 con ->
  590. add (Array.append (Array.of_list pl) (array_tl pv)) out
  591. | PCon(c2,pl) ->
  592. ()
  593. | PAny | PVar _->
  594. add (Array.append (Array.make a (mk_any (pv.(0).p_type) (pv.(0).p_pos))) (array_tl pv)) out
  595. | PBind(_,pat) ->
  596. loop2 (Array.append [|pat|] (array_tl pv)) out
  597. | PTuple tl ->
  598. loop2 tl out
  599. | POr _ ->
  600. assert false
  601. in
  602. let rec loop pmat = match pmat with
  603. | (pv,out) :: pl ->
  604. loop2 pv out;
  605. loop pl
  606. | [] ->
  607. ()
  608. in
  609. loop pmat;
  610. DynArray.to_list r
  611. let default mctx pmat =
  612. let r = DynArray.create () in
  613. let add pv out =
  614. DynArray.add r (pv,out)
  615. in
  616. let rec loop2 pv out = match pv.(0).p_def with
  617. | PCon _ ->
  618. ()
  619. | PAny | PVar _->
  620. add (array_tl pv) out
  621. | PBind(_,pat) ->
  622. loop2 (Array.append [|pat|] (array_tl pv)) out
  623. | PTuple tl ->
  624. loop2 tl out
  625. | POr _ ->
  626. assert false
  627. in
  628. let rec loop pmat = match pmat with
  629. | (pv,out) :: pl ->
  630. loop2 pv out;
  631. loop pl;
  632. | [] ->
  633. ()
  634. in
  635. loop pmat;
  636. DynArray.to_list r
  637. let pick_column pmat =
  638. let rec loop i pv = if Array.length pv = 0 then -1 else match pv.(0).p_def with
  639. | PVar _ | PAny ->
  640. loop (i + 1) (array_tl pv)
  641. | PTuple pl ->
  642. loop i pl
  643. | _ ->
  644. i
  645. in
  646. loop 0 (fst (List.hd pmat))
  647. let swap_pmat_columns i pmat =
  648. List.map (fun (pv,out) ->
  649. let pv = match pv with [|{p_def = PTuple pt}|] -> pt | _ -> pv in
  650. let tmp = pv.(i) in
  651. Array.set pv i pv.(0);
  652. Array.set pv 0 tmp;
  653. pv,out
  654. ) pmat
  655. let swap_columns i (row : 'a list) : 'a list =
  656. match row with
  657. | rh :: rt ->
  658. let rec loop count acc col = match col with
  659. | [] -> acc
  660. | ch :: cl when i = count ->
  661. ch :: (List.rev acc) @ [rh] @ cl
  662. | ch :: cl ->
  663. loop (count + 1) (ch :: acc) cl
  664. in
  665. loop 1 [] rt
  666. | _ ->
  667. []
  668. let expand_or mctx (pmat : pat_matrix) =
  669. let rec loop pat = match pat.p_def with
  670. | POr(pat1,pat2) ->
  671. let pat1 = loop pat1 in
  672. let pat2 = loop pat2 in
  673. pat1 @ pat2
  674. | PBind(v,pat1) ->
  675. let pat1 = loop pat1 in
  676. List.map (fun pat1 ->
  677. {pat with p_def = PBind(v,pat1)}
  678. ) pat1
  679. | PTuple(pl) ->
  680. let pat1 = loop pl.(0) in
  681. List.map (fun pat1 ->
  682. let a1 = Array.copy pl in
  683. a1.(0) <- pat1;
  684. {pat with p_def = PTuple a1}
  685. ) pat1
  686. | _ ->
  687. [pat]
  688. in
  689. let rec loop2 pmat = match pmat with
  690. | (pv,out) :: pmat ->
  691. let pat = loop pv.(0) in
  692. let pat' = ExtList.List.mapi (fun i pat ->
  693. (* TODO: This should really be active, but currently causes problems with or-patterns in
  694. tuples (issue #2610). We will disable this for the 3.1.0 release, which means issue
  695. #2508 is open again. *)
  696. (* let out = if i = 0 then out else clone_out mctx out pat.p_pos in *)
  697. let a1 = Array.copy pv in
  698. a1.(0) <- pat;
  699. a1,out
  700. ) pat in
  701. pat' @ (loop2 pmat)
  702. | [] ->
  703. []
  704. in
  705. loop2 pmat
  706. let column_sigma mctx st pmat =
  707. let acc = ref [] in
  708. let bindings = ref [] in
  709. let unguarded = Hashtbl.create 0 in
  710. let add c g =
  711. if not (List.exists (fun c2 -> unify_con c2 c) !acc) then acc := c :: !acc;
  712. if not g then Hashtbl.replace unguarded c.c_def true;
  713. in
  714. let bind_st out st v =
  715. if not (List.exists (fun ((v2,p),_) -> v2.v_id == (fst v).v_id) !bindings) then bindings := (v,st) :: !bindings
  716. in
  717. let rec loop pmat = match pmat with
  718. | (pv,out) :: pr ->
  719. let rec loop2 out = function
  720. | PCon (c,_) ->
  721. add c ((get_guard mctx out.o_id) <> None);
  722. | PVar v ->
  723. bind_st out st v;
  724. | PBind(v,pat) ->
  725. bind_st out st v;
  726. loop2 out pat.p_def
  727. | PAny ->
  728. ()
  729. | PTuple tl ->
  730. loop2 out tl.(0).p_def
  731. | POr _ ->
  732. assert false
  733. in
  734. loop2 out pv.(0).p_def;
  735. loop pr
  736. | [] ->
  737. ()
  738. in
  739. loop pmat;
  740. List.rev_map (fun con -> con,not (Hashtbl.mem unguarded con.c_def)) !acc,!bindings
  741. let rec all_ctors mctx t =
  742. let h = ref PMap.empty in
  743. if is_explicit_null t then h := PMap.add (CConst TNull) Ast.null_pos !h;
  744. match follow t with
  745. | TAbstract({a_path = [],"Bool"},_) ->
  746. h := PMap.add (CConst(TBool true)) Ast.null_pos !h;
  747. h := PMap.add (CConst(TBool false)) Ast.null_pos !h;
  748. h,RunTimeFinite
  749. | TAbstract({a_impl = Some c} as a,pl) when Meta.has Meta.Enum a.a_meta ->
  750. List.iter (fun cf ->
  751. ignore(follow cf.cf_type);
  752. if Meta.has Meta.Impl cf.cf_meta then match cf.cf_expr with
  753. | Some {eexpr = TConst c | TCast ({eexpr = TConst c},None)} -> h := PMap.add (CConst c) cf.cf_pos !h
  754. | _ -> ()
  755. ) c.cl_ordered_statics;
  756. h,CompileTimeFinite
  757. | TAbstract(a,pl) when not (Meta.has Meta.CoreType a.a_meta) -> all_ctors mctx (Abstract.get_underlying_type a pl)
  758. | TInst({cl_path=[],"String"},_)
  759. | TInst({cl_path=[],"Array"},_) ->
  760. h,Infinite
  761. | TEnum(en,pl) ->
  762. PMap.iter (fun _ ef ->
  763. let tc = monomorphs mctx.ctx.type_params t in
  764. try unify_enum_field en pl ef tc;
  765. h := PMap.add (CEnum(en,ef)) ef.ef_pos !h
  766. with Unify_error _ ->
  767. ()
  768. ) en.e_constrs;
  769. h,RunTimeFinite
  770. | TAnon a ->
  771. h,CompileTimeFinite
  772. | TInst(_,_) ->
  773. h,CompileTimeFinite
  774. | _ ->
  775. h,Infinite
  776. let rec collapse_pattern pl = match pl with
  777. | pat :: [] ->
  778. pat
  779. | pat :: pl ->
  780. let pat2 = collapse_pattern pl in
  781. mk_pat (POr(pat,pat2)) pat.p_type (punion pat.p_pos pat2.p_pos)
  782. | [] ->
  783. assert false
  784. let bind_remaining out pv stl =
  785. let rec loop stl pv =
  786. if Array.length pv = 0 then
  787. []
  788. else
  789. match stl,pv.(0).p_def with
  790. | st :: stl,PAny ->
  791. loop stl (array_tl pv)
  792. | st :: stl,PVar v ->
  793. (v,st) :: loop stl (array_tl pv)
  794. | stl,PTuple pl ->
  795. loop stl pl
  796. | _ :: _,_->
  797. loop stl (array_tl pv)
  798. | [],_ ->
  799. []
  800. in
  801. loop stl pv
  802. let get_cache mctx dt =
  803. match dt with Goto _ -> dt | _ ->
  804. try
  805. Goto (Hashtbl.find mctx.dt_cache dt)
  806. with Not_found ->
  807. Hashtbl.replace mctx.dt_cache dt mctx.dt_count;
  808. mctx.dt_count <- mctx.dt_count + 1;
  809. DynArray.add mctx.dt_lut dt;
  810. dt
  811. let rec compile mctx stl pmat toplevel =
  812. let guard id dt1 dt2 = get_cache mctx (Guard(id,dt1,dt2)) in
  813. let expr id = get_cache mctx (Expr id) in
  814. let bind bl dt = get_cache mctx (Bind(bl,dt)) in
  815. let switch st cl = get_cache mctx (Switch(st,cl)) in
  816. get_cache mctx (match pmat with
  817. | [] ->
  818. (match stl with
  819. | st :: stl ->
  820. let all,inf = all_ctors mctx st.st_type in
  821. let pl = PMap.foldi (fun cd p acc -> (mk_con_pat cd [] t_dynamic p) :: acc) !all [] in
  822. begin match pl,inf with
  823. | _,Infinite
  824. | [],_ ->
  825. raise (Not_exhaustive(any,st))
  826. | _ ->
  827. raise (Not_exhaustive(collapse_pattern pl,st))
  828. end
  829. | _ ->
  830. (* This can happen in cases a value is required and all default cases are guarded (issue #3150).
  831. Not a particularly elegant solution, may want to revisit this later. *)
  832. raise Exit)
  833. | ([|{p_def = PTuple pt}|],out) :: pl ->
  834. compile mctx stl ((pt,out) :: pl) toplevel
  835. | (pv,out) :: pl ->
  836. let i = pick_column pmat in
  837. if i = -1 then begin
  838. out.o_num_paths <- out.o_num_paths + 1;
  839. let bl = bind_remaining out pv stl in
  840. let dt = match (get_guard mctx out.o_id) with
  841. | None ->
  842. expr out.o_id
  843. | Some _ ->
  844. let dt = match pl,mctx.need_val with
  845. | [],false ->
  846. None
  847. | _ ->
  848. Some (compile mctx stl pl false)
  849. in
  850. guard out.o_id (expr out.o_id) dt
  851. in
  852. (if bl = [] then dt else bind bl dt)
  853. end else if i > 0 then begin
  854. let pmat = swap_pmat_columns i pmat in
  855. let stls = swap_columns i stl in
  856. compile mctx stls pmat toplevel
  857. end else begin
  858. let st_head,st_tail = match stl with st :: stl -> st,stl | _ -> assert false in
  859. let pmat = expand_or mctx pmat in
  860. let sigma,bl = column_sigma mctx st_head pmat in
  861. let all,inf = all_ctors mctx pv.(0).p_type in
  862. let cases = List.map (fun (c,g) ->
  863. if not g then all := PMap.remove c.c_def !all;
  864. let spec = spec mctx c pmat in
  865. let hsubs = mk_subs st_head c in
  866. let subs = hsubs @ st_tail in
  867. let dt = compile mctx subs spec false in
  868. c,dt
  869. ) sigma in
  870. let def = default mctx pmat in
  871. let dt = match def,cases with
  872. | _ when inf = RunTimeFinite && PMap.is_empty !all ->
  873. switch st_head cases
  874. | [],_ when inf = CompileTimeFinite && PMap.is_empty !all ->
  875. switch st_head cases
  876. | [],_ when inf = Infinite && not mctx.need_val && toplevel ->
  877. (* ignore exhaustiveness, but mark context so we do not generate @:exhaustive metadata *)
  878. mctx.is_exhaustive <- false;
  879. switch st_head cases
  880. | [],_ when inf = Infinite ->
  881. raise (Not_exhaustive(any,st_head))
  882. | [],_ ->
  883. let pl = PMap.foldi (fun cd p acc -> (mk_con_pat cd [] t_dynamic p) :: acc) !all [] in
  884. (* toplevel null can be omitted because the French dig runtime errors (issue #3054) *)
  885. if toplevel && (match pl with
  886. | [{p_def = PCon ({c_def = (CConst TNull)},_)}] -> true
  887. | _ -> false) then
  888. switch st_head cases
  889. else
  890. raise (Not_exhaustive(collapse_pattern pl,st_head))
  891. | def,[] ->
  892. compile mctx st_tail def false
  893. | def,_ ->
  894. let cdef = mk_con CAny t_dynamic st_head.st_pos in
  895. let def = try
  896. compile mctx st_tail def false
  897. with Exit ->
  898. raise (Not_exhaustive(any,st_head))
  899. in
  900. let cases = cases @ [cdef,def] in
  901. switch st_head cases
  902. in
  903. if bl = [] then dt else bind bl dt
  904. end)
  905. let rec collapse_case el = match el with
  906. | e :: [] ->
  907. e
  908. | e :: el ->
  909. let e2 = collapse_case el in
  910. EBinop(OpOr,e,e2),punion (pos e) (pos e2)
  911. | [] ->
  912. assert false
  913. let mk_const ctx p = function
  914. | TString s -> mk (TConst (TString s)) ctx.com.basic.tstring p
  915. | TInt i -> mk (TConst (TInt i)) ctx.com.basic.tint p
  916. | TFloat f -> mk (TConst (TFloat f)) ctx.com.basic.tfloat p
  917. | TBool b -> mk (TConst (TBool b)) ctx.com.basic.tbool p
  918. | TNull -> mk (TConst TNull) (ctx.com.basic.tnull (mk_mono())) p
  919. | _ -> error "Unsupported constant" p
  920. let rec convert_st ctx st = match st.st_def with
  921. | SVar v -> mk (TLocal v) v.v_type st.st_pos
  922. | SField (sts,cf) ->
  923. let e = convert_st ctx sts in
  924. Typer.acc_get ctx (Typer.type_field ctx e cf.cf_name st.st_pos Typer.MGet) st.st_pos
  925. | SArray (sts,i) -> mk (TArray(convert_st ctx sts,mk_const ctx st.st_pos (TInt (Int32.of_int i)))) st.st_type st.st_pos
  926. | STuple (st,_,_) -> convert_st ctx st
  927. | SEnum (sts,ef,i) -> mk (TEnumParameter(convert_st ctx sts, ef, i)) st.st_type st.st_pos
  928. let convert_con ctx con = match con.c_def with
  929. | CConst c -> mk_const ctx con.c_pos c
  930. | CType mt -> mk (TTypeExpr mt) t_dynamic con.c_pos
  931. | CExpr e -> e
  932. | CEnum(e,ef) -> mk_const ctx con.c_pos (TInt (Int32.of_int ef.ef_index))
  933. | CArray i -> mk_const ctx con.c_pos (TInt (Int32.of_int i))
  934. | CAny | CFields _ -> assert false
  935. let convert_switch mctx st cases loop =
  936. let ctx = mctx.ctx in
  937. let e_st = convert_st ctx st in
  938. let p = e_st.epos in
  939. let mk_index_call () =
  940. let ttype = match follow (Typeload.load_instance ctx { tpackage = ["std"]; tname="Type"; tparams=[]; tsub = None} p true) with TInst(c,_) -> c | t -> assert false in
  941. let cf = PMap.find "enumIndex" ttype.cl_statics in
  942. let ec = (!type_module_type_ref) ctx (TClassDecl ttype) None p in
  943. let ef = mk (TField(ec, FStatic(ttype,cf))) (tfun [e_st.etype] ctx.t.tint) p in
  944. let e = make_call ctx ef [e_st] ctx.t.tint p in
  945. e
  946. in
  947. let wrap_exhaustive e =
  948. if mctx.is_exhaustive then
  949. mk (TMeta((Meta.Exhaustive,[],e.epos),e)) e.etype e.epos
  950. else
  951. e
  952. in
  953. let e = match follow st.st_type with
  954. | TEnum(_) ->
  955. wrap_exhaustive (mk_index_call())
  956. | TAbstract(a,pl) when (match Abstract.get_underlying_type a pl with TEnum(_) -> true | _ -> false) ->
  957. wrap_exhaustive (mk_index_call())
  958. | TInst({cl_path = [],"Array"},_) as t ->
  959. mk (TField (e_st,quick_field t "length")) ctx.t.tint p
  960. | TAbstract(a,_) when Meta.has Meta.Enum a.a_meta ->
  961. wrap_exhaustive (e_st)
  962. | TAbstract({a_path = [],"Bool"},_) ->
  963. wrap_exhaustive (e_st)
  964. | _ ->
  965. let rec loop cases = match cases with
  966. | [] -> e_st
  967. | (con,_) :: cases ->
  968. begin match con.c_def with
  969. | CEnum _ -> mk_index_call()
  970. | CArray _ -> mk (TField (e_st,FDynamic "length")) ctx.t.tint p
  971. | _ -> loop cases
  972. end
  973. in
  974. loop cases
  975. in
  976. let null = ref None in
  977. let def = ref None in
  978. let cases = List.filter (fun (con,dt) ->
  979. match con.c_def with
  980. | CConst TNull ->
  981. null := Some (loop dt);
  982. false
  983. | CAny ->
  984. def := Some (loop dt);
  985. false
  986. | _ ->
  987. true
  988. ) cases in
  989. let dt = match cases with
  990. | [{c_def = CFields _},dt] -> loop dt
  991. | _ -> DTSwitch(e, List.map (fun (c,dt) -> convert_con ctx c, loop dt) cases, !def)
  992. in
  993. match !null with
  994. | None when is_explicit_null st.st_type && (!def <> None || not mctx.need_val) ->
  995. let econd = mk (TBinop(OpNotEq,e_st,mk (TConst TNull) (mk_mono()) p)) ctx.t.tbool p in
  996. DTGuard(econd,dt,!def)
  997. | None ->
  998. dt
  999. | Some dt_null ->
  1000. let econd = mk (TBinop(OpEq,e_st,mk (TConst TNull) (mk_mono()) p)) ctx.t.tbool p in
  1001. DTGuard(econd,dt_null,Some dt)
  1002. (* Decision tree compilation *)
  1003. let transform_extractors eval cases p =
  1004. let efail = (EThrow(EConst(Ident "false"),p)),p in
  1005. let cfail = [(EConst (Ident "_"),p)],None,Some efail in
  1006. let has_extractor = ref false in
  1007. let rec loop cases = match cases with
  1008. | (epat,eg,e) :: cases ->
  1009. let ex = ref [] in
  1010. let exc = ref 0 in
  1011. let rec find_ex in_or e = match fst e with
  1012. | EBinop(OpArrow,_,_) when in_or ->
  1013. error "Extractors in or patterns are not allowed" (pos e)
  1014. | EBinop(OpArrow, e1, e2) ->
  1015. let ec = EConst (Ident ("__ex" ^ string_of_int (!exc))),snd e in
  1016. let rec map_left e = match fst e with
  1017. | EConst(Ident "_") -> ec
  1018. | _ -> Ast.map_expr map_left e
  1019. in
  1020. let ecall = map_left e1 in
  1021. ex := (ecall,e2) :: !ex;
  1022. incr exc;
  1023. has_extractor := true;
  1024. ec
  1025. | EBinop(OpOr,e1,e2) ->
  1026. let e1 = find_ex true e1 in
  1027. let e2 = find_ex true e2 in
  1028. (EBinop(OpOr,e1,e2)),(pos e)
  1029. | _ ->
  1030. Ast.map_expr (find_ex in_or) e
  1031. in
  1032. let p = match e with None -> p | Some e -> pos e in
  1033. let epat = match epat with
  1034. | [epat] -> [find_ex false epat]
  1035. | _ -> List.map (find_ex true) epat
  1036. in
  1037. let cases = loop cases in
  1038. if !exc = 0 then
  1039. (epat,eg,e) :: cases
  1040. else begin
  1041. let esubjects = EArrayDecl (List.map fst !ex),p in
  1042. let case1 = [EArrayDecl (List.map snd !ex),p],eg,e in
  1043. let cases2 = match cases with
  1044. | [] -> [case1]
  1045. | [[EConst (Ident "_"),_],_,e] -> case1 :: [[(EConst (Ident "_"),p)],None,e]
  1046. | _ ->
  1047. case1 :: [[(EConst (Ident "_"),p)],None,Some (ESwitch(eval,cases,None),p)]
  1048. in
  1049. let eswitch = (ESwitch(esubjects,cases2,None)),p in
  1050. let case = epat,None,Some eswitch in
  1051. begin match epat with
  1052. | [EConst(Ident _),_] ->
  1053. [case;cfail]
  1054. | _ ->
  1055. case :: cases
  1056. end
  1057. end
  1058. | [] ->
  1059. []
  1060. in
  1061. let cases = loop cases in
  1062. cases,!has_extractor
  1063. let extractor_depth = ref 0
  1064. let match_expr ctx e cases def with_type p =
  1065. let need_val,with_type,tmono = match with_type with
  1066. | NoValue -> false,NoValue,None
  1067. | WithType t | WithTypeResume t when (match follow t with TMono _ -> true | _ -> false) ->
  1068. (* we don't want to unify with each case individually, but instead at the end after unify_min *)
  1069. true,Value,Some with_type
  1070. | t -> true,t,None
  1071. in
  1072. (* turn default into case _ *)
  1073. let cases = match cases,def with
  1074. | [],None -> []
  1075. | cases,Some def ->
  1076. let p = match def with
  1077. | None -> p
  1078. | Some (_,p) -> p
  1079. in
  1080. cases @ [[(EConst(Ident "_")),p],None,def]
  1081. | _ -> cases
  1082. in
  1083. let cases,has_extractor = transform_extractors e cases p in
  1084. (* type subject(s) *)
  1085. let array_match = ref false in
  1086. let evals = match fst e with
  1087. | EArrayDecl el | EParenthesis(EArrayDecl el,_) when (match el with [(EFor _ | EWhile _),_] -> false | _ -> true) ->
  1088. array_match := true;
  1089. List.map (fun e -> type_expr ctx e Value) el
  1090. | _ ->
  1091. let e = type_expr ctx e Value in
  1092. begin match follow e.etype with
  1093. (* TODO: get rid of the XmlType check *)
  1094. | TEnum(en,_) when (match en.e_path with (["neko" | "php" | "flash" | "cpp"],"XmlType") -> true | _ -> Meta.has Meta.FakeEnum en.e_meta) ->
  1095. raise Exit
  1096. | TAbstract({a_path=[],("Int" | "Float" | "Bool")},_) | TInst({cl_path = [],"String"},_) when (Common.defined ctx.com Common.Define.NoPatternMatching) ->
  1097. raise Exit;
  1098. | _ ->
  1099. ()
  1100. end;
  1101. [e]
  1102. in
  1103. let var_inits = ref [] in
  1104. let save = save_locals ctx in
  1105. let a = List.length evals in
  1106. (* turn subjects to subterms and handle variable initialization where necessary *)
  1107. let stl = ExtList.List.mapi (fun i e ->
  1108. let rec loop e = match e.eexpr with
  1109. | TParenthesis e | TMeta(_,e) ->
  1110. loop e
  1111. | TLocal v ->
  1112. mk_st (SVar v) e.etype e.epos
  1113. | _ ->
  1114. let v = gen_local ctx e.etype in
  1115. var_inits := (v, Some e) :: !var_inits;
  1116. ctx.locals <- PMap.add v.v_name v ctx.locals;
  1117. mk_st (SVar v) e.etype e.epos
  1118. in
  1119. let st = loop e in
  1120. if a = 1 then st else mk_st (STuple(st,i,a)) st.st_type st.st_pos
  1121. ) evals in
  1122. let tl = List.map (fun st -> st.st_type) stl in
  1123. (* create matcher context *)
  1124. let mctx = {
  1125. ctx = ctx;
  1126. need_val = need_val;
  1127. outcomes = [];
  1128. toplevel_or = false;
  1129. dt_lut = DynArray.create ();
  1130. dt_cache = Hashtbl.create 0;
  1131. dt_count = 0;
  1132. has_extractor = has_extractor;
  1133. expr_map = PMap.empty;
  1134. is_exhaustive = true;
  1135. } in
  1136. (* flatten cases *)
  1137. let cases = List.map (fun (el,eg,e) ->
  1138. List.iter (fun e -> match fst e with EBinop(OpOr,_,_) -> mctx.toplevel_or <- true; | _ -> ()) el;
  1139. match el with
  1140. | [] ->
  1141. let p = match e with None -> p | Some e -> pos e in
  1142. error "case without a pattern is not allowed" p
  1143. | _ ->
  1144. collapse_case el,eg,e
  1145. ) cases in
  1146. let is_complex = ref false in
  1147. if mctx.has_extractor then incr extractor_depth;
  1148. let add_pattern_locals (pat,locals,complex) =
  1149. PMap.iter (fun n (v,p) -> ctx.locals <- PMap.add n v ctx.locals) locals;
  1150. if complex then is_complex := true;
  1151. pat
  1152. in
  1153. (* evaluate patterns *)
  1154. let pl = ExtList.List.mapi (fun i (ep,eg,e) ->
  1155. let save = save_locals ctx in
  1156. (* type case patterns *)
  1157. let pl,restore,with_type =
  1158. try
  1159. (* context type parameters are turned into monomorphs until the pattern has been typed *)
  1160. let monos = List.map (fun _ -> mk_mono()) ctx.type_params in
  1161. let t = match tl with [t] when not !array_match -> t | tl -> tfun tl fake_tuple_type in
  1162. let t = apply_params ctx.type_params monos t in
  1163. let pl = [add_pattern_locals (to_pattern ctx ep t)] in
  1164. let old_ret = ctx.ret in
  1165. ctx.ret <- apply_params ctx.type_params monos ctx.ret;
  1166. let restore = PMap.fold (fun v acc ->
  1167. (* apply context monomorphs to locals and replace them back after typing the case body *)
  1168. let t = v.v_type in
  1169. v.v_type <- apply_params ctx.type_params monos v.v_type;
  1170. (fun () -> v.v_type <- t) :: acc
  1171. ) ctx.locals [fun() -> ctx.ret <- old_ret] in
  1172. (* turn any still unknown types back to type parameters *)
  1173. List.iter2 (fun m (_,t) -> match follow m with TMono _ -> Type.unify m t | _ -> ()) monos ctx.type_params;
  1174. pl,restore,(match with_type with
  1175. | WithType t -> WithType (apply_params ctx.type_params monos t)
  1176. | WithTypeResume t -> WithTypeResume (apply_params ctx.type_params monos t)
  1177. | _ -> with_type);
  1178. with Unrecognized_pattern (e,p) ->
  1179. error "Case expression must be a constant value or a pattern, not an arbitrary expression" p
  1180. in
  1181. let is_catch_all = match pl with
  1182. | [{p_def = PAny | PVar _}] -> true
  1183. | _ -> false
  1184. in
  1185. (* type case body *)
  1186. let e = match e with
  1187. | None ->
  1188. mk (TBlock []) ctx.com.basic.tvoid (pos ep)
  1189. | Some e ->
  1190. type_expr ctx e with_type
  1191. in
  1192. let e = match with_type with
  1193. | WithType t ->
  1194. Codegen.AbstractCast.cast_or_unify ctx t e e.epos;
  1195. | WithTypeResume t ->
  1196. (try Codegen.AbstractCast.cast_or_unify_raise ctx t e e.epos with Error (Unify l,p) -> raise (Typer.WithTypeError (l,p)));
  1197. | _ -> e
  1198. in
  1199. (* type case guard *)
  1200. let eg = match eg with
  1201. | None -> None
  1202. | Some e ->
  1203. let eg = type_expr ctx e (WithType ctx.com.basic.tbool) in
  1204. unify ctx eg.etype ctx.com.basic.tbool eg.epos;
  1205. Some eg
  1206. in
  1207. List.iter (fun f -> f()) restore;
  1208. save();
  1209. let out = mk_out mctx i e eg is_catch_all (pos ep) in
  1210. Array.of_list pl,out
  1211. ) cases in
  1212. let check_unused () =
  1213. let unused p =
  1214. display_error ctx "This pattern is unused" p;
  1215. let old_error = ctx.on_error in
  1216. ctx.on_error <- (fun ctx s p -> ctx.on_error <- old_error; raise Exit);
  1217. let check_expr e p =
  1218. try begin match fst e with
  1219. | EConst(Ident ("null" | "true" | "false")) -> ()
  1220. | EConst(Ident _) ->
  1221. ignore (type_expr ctx e Value);
  1222. display_error ctx "Case expression must be a constant value or a pattern, not an arbitrary expression" (pos e)
  1223. | _ -> ()
  1224. end with Exit -> ()
  1225. in
  1226. let rec loop prev cl = match cl with
  1227. | (_,Some _,_) :: cl -> loop prev cl
  1228. | ((e,p2),_,_) :: cl ->
  1229. if p2.pmin >= p.pmin then check_expr prev p else loop (e,p2) cl
  1230. | [] ->
  1231. check_expr prev p
  1232. in
  1233. (match cases with (e,_,_) :: cl -> loop e cl | [] -> assert false);
  1234. ctx.on_error <- old_error;
  1235. in
  1236. let had_catch_all = ref false in
  1237. List.iter (fun out ->
  1238. if out.o_catch_all && not !had_catch_all then
  1239. had_catch_all := true
  1240. else if out.o_num_paths = 0 then begin
  1241. unused out.o_pos;
  1242. if mctx.toplevel_or then begin match evals with
  1243. | [{etype = t}] when (match follow t with TAbstract({a_path=[],"Int"},[]) -> true | _ -> false) ->
  1244. display_error ctx "Note: Int | Int is an or-pattern now" p;
  1245. | _ -> ()
  1246. end;
  1247. end
  1248. ) (List.rev mctx.outcomes);
  1249. in
  1250. let dt = try
  1251. (* compile decision tree *)
  1252. compile mctx stl pl true
  1253. with Not_exhaustive(pat,st) ->
  1254. let rec s_st_r top pre st v = match st.st_def with
  1255. | SVar v1 ->
  1256. if not pre then v else begin try
  1257. let e = match List.assoc v1 !var_inits with Some e -> e | None -> assert false in
  1258. (Type.s_expr_pretty "" (Type.s_type (print_context())) e) ^ v
  1259. with Not_found ->
  1260. v1.v_name ^ v
  1261. end
  1262. | STuple(st,i,a) ->
  1263. let r = a - i - 1 in
  1264. Printf.sprintf "[%s]" (st_args i r (s_st_r top false st v))
  1265. | SArray(st,i) ->
  1266. s_st_r false true st (Printf.sprintf "[%i]%s" i (if top then " = " ^ v else v))
  1267. | SField({st_def = SVar v1},cf) when v1.v_name.[0] = '`' ->
  1268. cf.cf_name ^ (if top then " = " ^ v else v)
  1269. | SField(st,cf) ->
  1270. s_st_r false true st (Printf.sprintf ".%s%s" cf.cf_name (if top then " = " ^ v else v))
  1271. | SEnum(st,ef,i) ->
  1272. let len = match follow ef.ef_type with TFun(args,_) -> List.length args | _ -> 0 in
  1273. s_st_r false false st (Printf.sprintf "%s(%s)" ef.ef_name (st_args i (len - 1 - i) v))
  1274. in
  1275. let pat = match follow st.st_type with
  1276. | TAbstract({a_impl = Some cl} as a,_) when Meta.has Meta.Enum a.a_meta ->
  1277. let rec s_pat pat = match pat.p_def with
  1278. | PCon ({c_def = CConst c},[]) when c <> TNull ->
  1279. let cf = List.find (fun cf ->
  1280. match cf.cf_expr with
  1281. | Some ({eexpr = TConst c2 | TCast({eexpr = TConst c2},None)}) -> c = c2
  1282. | _ -> false
  1283. ) cl.cl_ordered_statics in
  1284. cf.cf_name
  1285. | PVar (v,_) -> v.v_name
  1286. | PCon (c,[]) -> s_con c
  1287. | PCon (c,pl) -> s_con c ^ "(" ^ (String.concat "," (List.map s_pat pl)) ^ ")"
  1288. | POr (pat1,pat2) -> s_pat pat1 ^ " | " ^ s_pat pat2
  1289. | PAny -> "_"
  1290. | PBind((v,_),pat) -> v.v_name ^ "=" ^ s_pat pat
  1291. | PTuple pl -> "(" ^ (String.concat " " (Array.to_list (Array.map s_pat pl))) ^ ")"
  1292. in
  1293. s_pat pat
  1294. | _ ->
  1295. s_pat pat
  1296. in
  1297. let msg = "Unmatched patterns: " ^ (s_st_r true false st pat) in
  1298. if !extractor_depth > 0 then begin
  1299. display_error ctx msg st.st_pos;
  1300. error "Note: Patterns with extractors may require a default pattern" st.st_pos;
  1301. end else
  1302. error msg st.st_pos
  1303. in
  1304. save();
  1305. (* check for unused patterns *)
  1306. if !extractor_depth = 0 then check_unused();
  1307. if mctx.has_extractor then decr extractor_depth;
  1308. (* determine type of switch statement *)
  1309. let t = if not need_val then
  1310. mk_mono()
  1311. else match with_type with
  1312. | WithType t | WithTypeResume t -> t
  1313. | _ -> try Typer.unify_min_raise ctx (List.rev_map (fun (_,out) -> get_expr mctx out.o_id) (List.rev pl)) with Error (Unify l,p) -> error (error_msg (Unify l)) p
  1314. in
  1315. (* unify with expected type if necessary *)
  1316. begin match tmono with
  1317. | None -> ()
  1318. | Some (WithType t2) -> unify ctx t2 t p
  1319. | Some (WithTypeResume t2) -> (try unify_raise ctx t2 t p with Error (Unify l,p) -> raise (Typer.WithTypeError (l,p)))
  1320. | _ -> assert false
  1321. end;
  1322. (* count usage *)
  1323. let usage = Array.make (DynArray.length mctx.dt_lut) 0 in
  1324. (* we always want to keep the first part *)
  1325. let first = (match dt with Goto i -> i | _ -> Hashtbl.find mctx.dt_cache dt) in
  1326. Array.set usage first 2;
  1327. let rec loop dt = match dt with
  1328. | Goto i -> Array.set usage i ((Array.get usage i) + 1)
  1329. | Switch(st,cl) -> List.iter (fun (_,dt) -> loop dt) cl
  1330. | Bind(bl,dt) -> loop dt
  1331. | Expr e -> ()
  1332. | Guard(e,dt1,dt2) ->
  1333. loop dt1;
  1334. match dt2 with None -> () | Some dt -> (loop dt)
  1335. in
  1336. DynArray.iter loop mctx.dt_lut;
  1337. (* filter parts that will be inlined and keep a map to them*)
  1338. let map = Array.make (DynArray.length mctx.dt_lut) 0 in
  1339. let lut = DynArray.create() in
  1340. let rec loop i c =
  1341. if c < DynArray.length mctx.dt_lut then begin
  1342. let i' = if usage.(c) > 1 then begin
  1343. DynArray.add lut (DynArray.get mctx.dt_lut c);
  1344. i + 1
  1345. end else i in
  1346. Array.set map c i;
  1347. loop i' (c + 1)
  1348. end
  1349. in
  1350. loop 0 0;
  1351. (* reindex *)
  1352. let rec loop dt = match dt with
  1353. | Goto i -> if usage.(i) > 1 then DTGoto (map.(i)) else loop (DynArray.get mctx.dt_lut i)
  1354. | Switch(st,cl) -> convert_switch mctx st cl loop
  1355. | Bind(bl,dt) -> DTBind(List.map (fun (v,st) -> v,convert_st ctx st) bl,loop dt)
  1356. | Expr id -> DTExpr (get_expr mctx id)
  1357. | Guard(id,dt1,dt2) -> DTGuard((match get_guard mctx id with Some e -> e | None -> assert false),loop dt1, match dt2 with None -> None | Some dt -> Some (loop dt))
  1358. in
  1359. let lut = DynArray.map loop lut in
  1360. {
  1361. dt_first = map.(first);
  1362. dt_dt_lookup = DynArray.to_array lut;
  1363. dt_type = t;
  1364. dt_var_init = List.rev !var_inits;
  1365. dt_is_complex = !is_complex;
  1366. }
  1367. ;;
  1368. match_expr_ref := match_expr;
  1369. get_pattern_locals_ref := get_pattern_locals