texprConverter.ml 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. open Globals
  2. open Ast
  3. open Type
  4. open Typecore
  5. open Common
  6. open Error
  7. open MatcherGlobals
  8. open DecisionTree
  9. open Constructor
  10. open Case
  11. open Texpr.Builder
  12. type match_kind =
  13. | SKValue
  14. | SKEnum
  15. | SKLength
  16. let constructor_to_texpr ctx con =
  17. let open Typecore in
  18. let open Constructor in
  19. let p = pos con in
  20. match fst con with
  21. | ConEnum(en,ef) -> mk (TConst (TInt (Int32.of_int ef.ef_index))) ctx.t.tint p
  22. | ConConst ct -> make_const_texpr ctx.com.basic ct p
  23. | ConArray i -> make_int ctx.com.basic i p
  24. | ConTypeExpr mt -> TyperBase.type_module_type ctx mt p
  25. | ConStatic(c,cf) -> make_static_field c cf p
  26. | ConFields _ -> raise_typing_error "Something went wrong" p
  27. let s_subject v_lookup s e =
  28. let rec loop top s e = match e.eexpr with
  29. | TField(_,FEnum(en,ef)) ->
  30. s
  31. | TField(e1,fa) ->
  32. if top then loop false s e1
  33. else loop false (Printf.sprintf "{ %s: %s }" (field_name fa) s) e1
  34. | TEnumParameter(e1,ef,i) ->
  35. let arity = match follow ef.ef_type with TFun(args,_) -> List.length args | _ -> die "" __LOC__ in
  36. let l = make_offset_list i (arity - i - 1) s "_" in
  37. loop false (Printf.sprintf "%s(%s)" ef.ef_name (String.concat ", " l)) e1
  38. | TLocal v ->
  39. begin try
  40. loop top s (IntMap.find v.v_id v_lookup)
  41. with Not_found ->
  42. s
  43. end
  44. | _ ->
  45. s
  46. in
  47. loop true s e
  48. let s_match_kind = function
  49. | SKValue -> "value"
  50. | SKEnum -> "enum"
  51. | SKLength -> "length"
  52. let unify_constructor ctx params t con =
  53. match fst con with
  54. | ConEnum(en,ef) ->
  55. let t_ef = match follow ef.ef_type with TFun(_,t) -> t | _ -> ef.ef_type in
  56. let t_ef = apply_params ctx.type_params params (monomorphs en.e_params (monomorphs ef.ef_params t_ef)) in
  57. let monos = List.map (fun t -> match follow t with
  58. | TInst({cl_kind = KTypeParameter _},_) | TMono _ -> mk_mono()
  59. | _ -> t
  60. ) params in
  61. let rec duplicate_monos t = match follow t with
  62. | TMono _ -> mk_mono()
  63. | _ -> Type.map duplicate_monos t
  64. in
  65. let t_e = apply_params ctx.type_params monos (duplicate_monos t) in
  66. begin try
  67. Type.unify t_ef t_e;
  68. Some(con,monos)
  69. with Unify_error _ ->
  70. None
  71. end
  72. | _ ->
  73. Some(con,params)
  74. let rec extract_ctor e = match e.eexpr with
  75. | TConst ct -> Some (ConConst ct)
  76. | TField(_,FEnum(en,ef)) -> Some (ConEnum(en,ef))
  77. | TCast(e1,None) -> extract_ctor e1
  78. | _ -> None
  79. let all_ctors ctx e cases =
  80. let infer_type() = match cases with
  81. | [] -> e,e.etype,false
  82. | sc :: _ ->
  83. let fail() =
  84. (* error "Could not determine switch kind, make sure the type is known" e.epos; *)
  85. t_dynamic
  86. in
  87. let t = match fst sc.sc_con with
  88. | ConEnum(en,_) -> TEnum(en,extract_param_types en.e_params)
  89. | ConArray _ -> ctx.t.tarray t_dynamic
  90. | ConConst ct ->
  91. begin match ct with
  92. | TString _ -> ctx.t.tstring
  93. | TInt _ -> ctx.t.tint
  94. | TFloat _ -> ctx.t.tfloat
  95. | TBool _ -> ctx.t.tbool
  96. | _ -> fail()
  97. end
  98. | ConStatic({cl_kind = KAbstractImpl a},_) -> (TAbstract(a,extract_param_types a.a_params))
  99. | ConTypeExpr mt -> ExprToPattern.get_general_module_type ctx mt e.epos
  100. | ConFields _ | ConStatic _ -> fail()
  101. in
  102. e,t,true
  103. in
  104. let e,t,inferred = match follow e.etype with
  105. | TDynamic _ | TMono _ ->
  106. infer_type()
  107. | _ ->
  108. e,e.etype,false
  109. in
  110. let h = Compile.ConTable.create 0 in
  111. let add constructor =
  112. Compile.ConTable.replace h constructor true
  113. in
  114. let rec loop deep t = match follow t with
  115. | TAbstract({a_path = [],"Bool"},_) ->
  116. if not deep then begin
  117. add (ConConst(TBool true),null_pos);
  118. add (ConConst(TBool false),null_pos);
  119. end;
  120. SKValue,RunTimeFinite
  121. | TAbstract({a_impl = Some c} as a,pl) when a.a_enum ->
  122. if not deep then List.iter (fun cf ->
  123. ignore(follow cf.cf_type);
  124. if has_class_field_flag cf CfImpl && has_class_field_flag cf CfEnum then match cf.cf_expr with
  125. | Some e ->
  126. begin match extract_ctor e with
  127. | Some (ConConst TNull) -> ()
  128. | Some ctor -> add (ctor,null_pos)
  129. | None -> add (ConStatic(c,cf),null_pos)
  130. end;
  131. | _ -> add (ConStatic(c,cf),null_pos)
  132. ) c.cl_ordered_statics;
  133. let real_kind,_ = loop true (Abstract.get_underlying_type a pl) in
  134. real_kind,CompileTimeFinite
  135. | TAbstract(a,pl) when not (Meta.has Meta.CoreType a.a_meta) ->
  136. loop deep (Abstract.get_underlying_type a pl)
  137. | TInst({cl_path=[],"String"},_)
  138. | TInst({cl_kind = KTypeParameter _ },_) ->
  139. SKValue,Infinite
  140. | TInst({cl_path=[],"Array"},_) ->
  141. SKLength,Infinite
  142. | TEnum(en,pl) ->
  143. if not deep then
  144. PMap.iter (fun _ ef -> add (ConEnum(en,ef),null_pos)) en.e_constrs;
  145. SKEnum,RunTimeFinite
  146. | TAnon _ ->
  147. SKValue,Infinite
  148. | TInst(_,_) ->
  149. SKValue,Infinite
  150. | _ ->
  151. SKValue,Infinite
  152. in
  153. let kind,finiteness = loop false t in
  154. let compatible_kind con = match fst con with
  155. | ConEnum _ -> kind = SKEnum
  156. | ConArray _ -> kind = SKLength
  157. | _ -> kind = SKValue
  158. in
  159. List.iter (fun sc ->
  160. if not (compatible_kind sc.sc_con) then raise_typing_error "Incompatible pattern" sc.sc_dt.dt_pos;
  161. if sc.sc_unguarded then Compile.ConTable.remove h sc.sc_con
  162. ) cases;
  163. let unmatched = Compile.ConTable.fold (fun con _ acc -> con :: acc) h [] in
  164. e,unmatched,kind,finiteness
  165. let report_not_exhaustive v_lookup e_subject unmatched =
  166. let sl = match follow e_subject.etype with
  167. | TAbstract({a_impl = Some c} as a,tl) when a.a_enum ->
  168. List.map (fun (con,_) -> match fst con with
  169. | ConConst _ | ConEnum _ ->
  170. let cf = List.find (fun cf ->
  171. match cf.cf_expr with
  172. | Some e ->
  173. begin match extract_ctor e with
  174. | Some ctor -> Constructor.equal (ctor,null_pos) con
  175. | None -> false
  176. end
  177. | _ -> false
  178. ) c.cl_ordered_statics in
  179. cf.cf_name
  180. | _ ->
  181. Constructor.to_string con
  182. ) unmatched
  183. | _ ->
  184. List.map (fun (con,_) -> Constructor.to_string con) unmatched
  185. in
  186. let s = match unmatched with
  187. | [] -> "_"
  188. | _ -> String.concat " | " (List.sort Stdlib.compare sl)
  189. in
  190. raise_typing_error (Printf.sprintf "Unmatched patterns: %s" (s_subject v_lookup s e_subject)) e_subject.epos
  191. type dt_recursion =
  192. | Toplevel
  193. | AfterSwitch
  194. | Deep
  195. let to_texpr ctx t_switch with_type dt =
  196. let v_lookup = ref IntMap.empty in
  197. let com = ctx.com in
  198. let p = dt.dt_pos in
  199. let mk_index_call e =
  200. mk (TEnumIndex e) com.basic.tint e.epos
  201. in
  202. let rec loop dt_rec params dt = match dt.dt_texpr with
  203. | Some e ->
  204. Some e
  205. | None ->
  206. let e = match dt.dt_t with
  207. | Leaf case ->
  208. begin match case.case_expr with
  209. | Some e -> Some e
  210. | None -> Some (mk (TBlock []) ctx.t.tvoid case.case_pos)
  211. end
  212. | Switch(e_subject,[{sc_con = (ConFields _,_)} as sc],_) -> (* TODO: Can we improve this by making it more general? *)
  213. begin match loop dt_rec params sc.sc_dt with
  214. | None ->
  215. None
  216. | Some e ->
  217. Some (concat e_subject e)
  218. end
  219. | Switch(e_subject,cases,default) ->
  220. let dt_rec',toplevel = match dt_rec with
  221. | Toplevel -> AfterSwitch,true
  222. | AfterSwitch | Deep -> Deep,false
  223. in
  224. let e_subject,unmatched,kind,finiteness = all_ctors ctx e_subject cases in
  225. let unmatched = ExtList.List.filter_map (unify_constructor ctx params e_subject.etype) unmatched in
  226. let loop params dt = match loop dt_rec' params dt with
  227. | None ->
  228. begin match with_type,finiteness with
  229. | WithType.NoValue,Infinite when toplevel -> None
  230. | _,CompileTimeFinite when unmatched = [] -> None
  231. | _ when ignore_error ctx.com -> None
  232. | _ -> report_not_exhaustive !v_lookup e_subject unmatched
  233. end
  234. | Some e ->
  235. Some e
  236. in
  237. let cases = ExtList.List.filter_map (fun sc -> match unify_constructor ctx params e_subject.etype sc.sc_con with
  238. | Some(_,params) -> Some (sc.sc_con,sc.sc_dt,params)
  239. | None -> None
  240. ) cases in
  241. let group cases =
  242. let h = Compile.DtTable.create 0 in
  243. List.iter (fun (con,dt,params) ->
  244. let l,_,_ = try Compile.DtTable.find h dt.dt_t with Not_found -> [],dt,params in
  245. Compile.DtTable.replace h dt.dt_t (con :: l,dt,params)
  246. ) cases;
  247. Compile.DtTable.fold (fun _ (cons,dt,params) acc -> (cons,dt,params) :: acc) h []
  248. in
  249. let cases = group cases in
  250. let cases = List.sort (fun (cons1,_,_) (cons2,_,_) -> match cons1,cons2 with
  251. | (con1 :: _),con2 :: _ -> Constructor.compare con1 con2
  252. | _ -> -1
  253. ) cases in
  254. let e_default = match unmatched,finiteness with
  255. | [],RunTimeFinite ->
  256. None
  257. | _ ->
  258. loop params default
  259. in
  260. let cases = ExtList.List.filter_map (fun (cons,dt,params) ->
  261. let eo = loop params dt in
  262. begin match eo with
  263. | None -> None
  264. | Some e -> Some {case_patterns = List.map (constructor_to_texpr ctx) (List.sort Constructor.compare cons);case_expr = e}
  265. end
  266. ) cases in
  267. let is_nullable_subject = is_explicit_null e_subject.etype in
  268. let e_subject = match kind with
  269. | SKValue -> e_subject
  270. | SKEnum -> mk_index_call e_subject
  271. | SKLength -> ExprToPattern.type_field_access ctx e_subject "length"
  272. in
  273. let e = match cases,e_default,with_type with
  274. | [case],None,_ when (match finiteness with RunTimeFinite -> true | _ -> false) && not is_nullable_subject ->
  275. {case.case_expr with etype = t_switch}
  276. | [{case_patterns = [e1];case_expr = e2}],Some _,_
  277. | [{case_patterns = [e1];case_expr = e2}],None,NoValue ->
  278. let e_op = mk (TBinop(OpEq,e_subject,e1)) ctx.t.tbool e_subject.epos in
  279. begin match e2.eexpr with
  280. | TIf(e_op2,e3,e_default2) when (match e_default,e_default2 with Some(e1),Some(e2) when e1 == e2 -> true | _ -> false) ->
  281. let eand = binop OpBoolAnd e_op e_op2 ctx.t.tbool (punion e_op.epos e_op2.epos) in
  282. mk (TIf(eand,e3,e_default)) t_switch dt.dt_pos
  283. | _ ->
  284. mk (TIf(e_op,e2,e_default)) t_switch dt.dt_pos
  285. end
  286. | [{case_patterns = [{eexpr = TConst (TBool true)}];case_expr = e2};{case_patterns = [{eexpr = TConst (TBool false)}];case_expr = e1}],None,_
  287. | [{case_patterns = [{eexpr = TConst (TBool false)}];case_expr = e2};{case_patterns = [{eexpr = TConst (TBool true)}];case_expr = e1}],None,_ ->
  288. mk (TIf(e_subject,e1,Some e2)) t_switch dt.dt_pos
  289. | _ ->
  290. let is_exhaustive = e_default <> None || match finiteness with
  291. | RunTimeFinite | CompileTimeFinite when e_default = None ->
  292. true
  293. | _ ->
  294. false
  295. in
  296. let switch = mk_switch e_subject cases e_default is_exhaustive in
  297. mk (TSwitch switch) t_switch dt.dt_pos
  298. in
  299. Some e
  300. | Guard(e,dt1,dt2) ->
  301. (* Normal guards are considered toplevel if we're in the toplevel switch. *)
  302. let toplevel = match dt_rec with
  303. | Toplevel | AfterSwitch -> true
  304. | Deep -> false
  305. in
  306. let e_then = loop dt_rec params dt1 in
  307. begin match e_then with
  308. | None ->
  309. None
  310. | Some e_then ->
  311. let e_else = loop dt_rec params dt2 in
  312. begin match e_else with
  313. | Some e_else ->
  314. Some (mk (TIf(e,e_then,Some e_else)) t_switch (punion e_then.epos e_else.epos))
  315. | None ->
  316. if with_type = NoValue && toplevel then
  317. Some (mk (TIf(e,e_then,None)) ctx.t.tvoid (punion e.epos e_then.epos))
  318. else
  319. None
  320. end
  321. end
  322. | GuardNull(e,dt1,dt2) ->
  323. let toplevel = match dt_rec with
  324. | Toplevel -> true
  325. | Deep | AfterSwitch -> false
  326. in
  327. let e_null = make_null e.etype e.epos in
  328. let f_op e = mk (TBinop(OpEq,e,e_null)) ctx.t.tbool e.epos in
  329. let rec loop2 acc dt = match dt.dt_t with
  330. | GuardNull(e,dt1,dt3) when DecisionTree.equal_dt dt2 dt3 ->
  331. loop2 ((f_op e) :: acc) dt1
  332. | Guard(e,dt1,dt3) when DecisionTree.equal_dt dt2 dt3 ->
  333. loop2 (e :: acc) dt1
  334. | _ ->
  335. List.rev acc,dt
  336. in
  337. let conds,dt1 = loop2 [] dt1 in
  338. let e_cond = List.fold_left (fun e1 e2 -> binop OpBoolAnd e1 e2 ctx.t.tbool (punion e1.epos e2.epos)) (f_op e) conds in
  339. let e_then = loop dt_rec params dt1 in
  340. begin match e_then with
  341. | None ->
  342. if toplevel then
  343. loop dt_rec params dt2
  344. else if ignore_error ctx.com then
  345. Some (mk (TConst TNull) (mk_mono()) dt2.dt_pos)
  346. else
  347. report_not_exhaustive !v_lookup e [(ConConst TNull,dt.dt_pos),dt.dt_pos]
  348. | Some e_then ->
  349. let e_else = loop dt_rec params dt2 in
  350. begin match e_else with
  351. | None ->
  352. if toplevel then
  353. Some (mk (TIf(e_cond,e_then,None)) t_switch e_then.epos)
  354. else
  355. report_not_exhaustive !v_lookup e []
  356. | Some e_else ->
  357. Some (mk (TIf(e_cond,e_then,Some e_else)) t_switch (punion e_then.epos e_else.epos))
  358. end
  359. end
  360. | Bind(bl,dt) ->
  361. let el = ExtList.List.filter_map (fun bind ->
  362. begin match bind.Bind.b_status with
  363. | BindUsed ->
  364. v_lookup := IntMap.add bind.b_var.v_id bind.b_expr !v_lookup;
  365. Some (mk (TVar(bind.b_var,Some bind.b_expr)) com.basic.tvoid p)
  366. | BindDeferred ->
  367. Some (mk (TVar(bind.b_var,None)) com.basic.tvoid p)
  368. | BindUnused ->
  369. None
  370. end
  371. ) bl in
  372. let e = loop dt_rec params dt in
  373. Option.map (fun e -> mk (TBlock (el @ [e])) e.etype dt.dt_pos) e;
  374. | Fail ->
  375. None
  376. in
  377. dt.dt_texpr <- e;
  378. e
  379. in
  380. let params = extract_param_types ctx.type_params in
  381. let e = loop Toplevel params dt in
  382. match e with
  383. | None ->
  384. raise_typing_error "Unmatched patterns: _" p;
  385. | Some e ->
  386. Texpr.duplicate_tvars e_identity e