abstractCast.ml 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. open Globals
  2. open Common
  3. open Ast
  4. open Type
  5. open Typecore
  6. open Error
  7. open CallUnification
  8. let cast_stack = new_rec_stack()
  9. let rec make_static_call ctx c cf a pl args t p =
  10. if cf.cf_kind = Method MethMacro then begin
  11. match args with
  12. | [e] ->
  13. let e,f = push_this ctx e in
  14. ctx.with_type_stack <- (WithType.with_type t) :: ctx.with_type_stack;
  15. let e = match ctx.g.do_macro ctx MExpr c.cl_path cf.cf_name [e] p with
  16. | Some e -> type_expr ctx e (WithType.with_type t)
  17. | None -> type_expr ctx (EConst (Ident "null"),p) WithType.value
  18. in
  19. ctx.with_type_stack <- List.tl ctx.with_type_stack;
  20. let e = try cast_or_unify_raise ctx t e p with Error(Unify _,_) -> raise Not_found in
  21. f();
  22. e
  23. | _ -> die "" __LOC__
  24. end else
  25. Typecore.make_static_call ctx c cf (apply_params a.a_params pl) args t p
  26. and do_check_cast ctx uctx tleft eright p =
  27. let recurse cf f =
  28. (*
  29. Without this special check for macro @:from methods we will always get "Recursive implicit cast" error
  30. unlike non-macro @:from methods, which generate unification errors if no other @:from methods are involved.
  31. *)
  32. if cf.cf_kind = Method MethMacro then begin
  33. match cast_stack.rec_stack with
  34. | previous_from :: _ when previous_from == cf ->
  35. (try
  36. Type.unify_custom uctx eright.etype tleft;
  37. with Unify_error l ->
  38. raise (Error (Unify l, eright.epos)))
  39. | _ -> ()
  40. end;
  41. if cf == ctx.curfield || rec_stack_memq cf cast_stack then typing_error "Recursive implicit cast" p;
  42. rec_stack_loop cast_stack cf f ()
  43. in
  44. let make (a,tl,(tcf,cf)) =
  45. if (Meta.has Meta.MultiType cf.cf_meta) then
  46. mk_cast eright tleft p
  47. else match a.a_impl with
  48. | Some c -> recurse cf (fun () ->
  49. let ret = make_static_call ctx c cf a tl [eright] tleft p in
  50. { ret with eexpr = TMeta( (Meta.ImplicitCast,[],ret.epos), ret) }
  51. )
  52. | None -> die "" __LOC__
  53. in
  54. if type_iseq_custom uctx tleft eright.etype then
  55. eright
  56. else begin
  57. let rec loop stack tleft tright =
  58. if List.exists (fun (tleft',tright') -> fast_eq tleft tleft' && fast_eq tright tright') stack then
  59. raise Not_found
  60. else begin
  61. let stack = (tleft,tright) :: stack in
  62. match follow tleft,follow tright with
  63. | TAbstract(a1,tl1),TAbstract(a2,tl2) ->
  64. make (Abstract.find_to_from uctx eright.etype tleft a2 tl2 a1 tl1)
  65. | TAbstract(a,tl),_ ->
  66. begin try make (a,tl,Abstract.find_from uctx eright.etype a tl)
  67. with Not_found ->
  68. let rec loop2 tcl = match tcl with
  69. | tc :: tcl ->
  70. if not (type_iseq_custom uctx tc tleft) then loop stack (apply_params a.a_params tl tc) tright
  71. else loop2 tcl
  72. | [] -> raise Not_found
  73. in
  74. loop2 a.a_from
  75. end
  76. | _,TAbstract(a,tl) ->
  77. begin try make (a,tl,Abstract.find_to uctx tleft a tl)
  78. with Not_found ->
  79. let rec loop2 tcl = match tcl with
  80. | tc :: tcl ->
  81. if not (type_iseq_custom uctx tc tright) then loop stack tleft (apply_params a.a_params tl tc)
  82. else loop2 tcl
  83. | [] -> raise Not_found
  84. in
  85. loop2 a.a_to
  86. end
  87. | _ ->
  88. raise Not_found
  89. end
  90. in
  91. loop [] tleft eright.etype
  92. end
  93. and cast_or_unify_raise ctx ?(uctx=None) tleft eright p =
  94. let uctx = match uctx with
  95. | None -> default_unification_context
  96. | Some uctx -> uctx
  97. in
  98. try
  99. do_check_cast ctx uctx tleft eright p
  100. with Not_found ->
  101. unify_raise_custom uctx eright.etype tleft p;
  102. eright
  103. and cast_or_unify ctx tleft eright p =
  104. try
  105. cast_or_unify_raise ctx tleft eright p
  106. with Error (Unify l,p) ->
  107. raise_or_display ctx l p;
  108. eright
  109. let prepare_array_access_field ctx a pl cf p =
  110. let monos = List.map (fun _ -> spawn_monomorph ctx p) cf.cf_params in
  111. let map t = apply_params a.a_params pl (apply_params cf.cf_params monos t) in
  112. let check_constraints () =
  113. List.iter2 (fun m tp -> match follow tp.ttp_type with
  114. | TInst ({ cl_kind = KTypeParameter constr },_) when constr <> [] ->
  115. List.iter (fun tc -> match follow m with TMono _ -> raise (Unify_error []) | _ -> Type.unify m (map tc) ) constr
  116. | _ -> ()
  117. ) monos cf.cf_params;
  118. in
  119. let get_ta() =
  120. if has_class_field_flag cf CfImpl then apply_params a.a_params pl a.a_this
  121. else TAbstract(a,pl)
  122. in
  123. map,check_constraints,get_ta
  124. let find_array_read_access_raise ctx a pl e1 p =
  125. let rec loop cfl =
  126. match cfl with
  127. | [] -> raise Not_found
  128. | cf :: cfl ->
  129. let map,check_constraints,get_ta = prepare_array_access_field ctx a pl cf p in
  130. match follow (map cf.cf_type) with
  131. | TFun((_,_,tab) :: (_,_,ta1) :: args,r) as tf when is_empty_or_pos_infos args ->
  132. begin try
  133. Type.unify tab (get_ta());
  134. let e1 = cast_or_unify_raise ctx ta1 e1 p in
  135. check_constraints();
  136. cf,tf,r,e1
  137. with Unify_error _ | Error (Unify _,_) ->
  138. loop cfl
  139. end
  140. | _ -> loop cfl
  141. in
  142. loop a.a_array_read
  143. let find_array_read_access ctx a tl e1 p =
  144. try
  145. find_array_read_access_raise ctx a tl e1 p
  146. with Not_found ->
  147. let s_type = s_type (print_context()) in
  148. typing_error (Printf.sprintf "No @:arrayAccess function for %s accepts argument of %s" (s_type (TAbstract(a,tl))) (s_type e1.etype)) p
  149. module ArrayWrite = struct
  150. let get_list_from_key ctx a pl e1 p =
  151. let rec loop acc cfl =
  152. match cfl with
  153. | [] ->
  154. List.rev acc
  155. | cf :: cfl ->
  156. let map,check_constraints,get_ta = prepare_array_access_field ctx a pl cf p in
  157. match follow (map cf.cf_type) with
  158. | TFun((_,_,tab) :: (_,_,ta1) :: (_,_,ta2) :: args,r) as tf when is_empty_or_pos_infos args ->
  159. begin try
  160. Type.unify tab (get_ta());
  161. let e1 = cast_or_unify_raise ctx ta1 e1 p in
  162. let f e2 =
  163. let e2 = cast_or_unify_raise ctx ta2 e2 p in
  164. check_constraints();
  165. cf,tf,r,e1,e2
  166. in
  167. loop ((f,ta2) :: acc) cfl
  168. with Unify_error _ | Error (Unify _,_) ->
  169. loop acc cfl
  170. end
  171. | _ -> loop acc cfl
  172. in
  173. loop [] a.a_array_write
  174. let filter_by_value_raise candidates e2 =
  175. let rec loop candidates = match candidates with
  176. | [] ->
  177. raise Not_found
  178. | (f,_) :: candidates ->
  179. try
  180. f e2
  181. with Unify_error _ | Error (Unify _,_) ->
  182. loop candidates
  183. in
  184. loop candidates
  185. let catch_write_exception a tl t1 t2 p f =
  186. try
  187. f ()
  188. with Not_found ->
  189. let s_type = s_type (print_context()) in
  190. typing_error (Printf.sprintf "No @:arrayAccess function for %s accepts arguments of %s and %s" (s_type (TAbstract(a,tl))) (s_type t1) (s_type t2)) p
  191. let filter_by_value a tl t1 e2 p candidates =
  192. catch_write_exception a tl t1 e2.etype p (fun () -> filter_by_value_raise candidates e2)
  193. let find_array_write_access_raise ctx a tl e1 e2 p =
  194. let candidates = get_list_from_key ctx a tl e1 p in
  195. filter_by_value_raise candidates e2
  196. let find_array_write_access ctx a tl e1 e2 p =
  197. catch_write_exception a tl e1.etype e2.etype p (fun () -> find_array_write_access_raise ctx a tl e1 e2 p)
  198. end
  199. let find_multitype_specialization com a pl p =
  200. let uctx = default_unification_context in
  201. let m = mk_mono() in
  202. let tl,definitive_types = Abstract.find_multitype_params a pl in
  203. if com.platform = Globals.Js && a.a_path = (["haxe";"ds"],"Map") then begin match tl with
  204. | t1 :: _ ->
  205. let stack = ref [] in
  206. let rec loop t =
  207. if List.exists (fun t2 -> fast_eq t t2) !stack then
  208. t
  209. else begin
  210. stack := t :: !stack;
  211. match follow t with
  212. | TAbstract ({ a_path = [],"Class" },_) ->
  213. typing_error (Printf.sprintf "Cannot use %s as key type to Map because Class<T> is not comparable on JavaScript" (s_type (print_context()) t1)) p;
  214. | TEnum(en,tl) ->
  215. PMap.iter (fun _ ef -> ignore(loop ef.ef_type)) en.e_constrs;
  216. Type.map loop t
  217. | t ->
  218. Type.map loop t
  219. end
  220. in
  221. ignore(loop t1)
  222. | _ -> die "" __LOC__
  223. end;
  224. let _,cf =
  225. try
  226. let t = Abstract.find_to uctx m a tl in
  227. if List.exists (fun t -> has_mono t) definitive_types then begin
  228. let at = apply_params a.a_params pl a.a_this in
  229. let st = s_type (print_context()) at in
  230. typing_error ("Type parameters of multi type abstracts must be known (for " ^ st ^ ")") p
  231. end;
  232. t
  233. with Not_found ->
  234. let at = apply_params a.a_params pl a.a_this in
  235. let st = s_type (print_context()) at in
  236. if has_mono at then
  237. typing_error ("Type parameters of multi type abstracts must be known (for " ^ st ^ ")") p
  238. else
  239. typing_error ("Abstract " ^ (s_type_path a.a_path) ^ " has no @:to function that accepts " ^ st) p;
  240. in
  241. cf, follow m
  242. let handle_abstract_casts ctx e =
  243. let rec loop ctx e = match e.eexpr with
  244. | TNew({cl_kind = KAbstractImpl a} as c,pl,el) ->
  245. if not (Meta.has Meta.MultiType a.a_meta) then begin
  246. (* This must have been a @:generic expansion with a { new } constraint (issue #4364). In this case
  247. let's construct the underlying type. *)
  248. match Abstract.get_underlying_type a pl with
  249. | TInst(c,tl) as t -> {e with eexpr = TNew(c,tl,el); etype = t}
  250. | _ -> typing_error ("Cannot construct " ^ (s_type (print_context()) (TAbstract(a,pl)))) e.epos
  251. end else begin
  252. (* a TNew of an abstract implementation is only generated if it is a multi type abstract *)
  253. let cf,m = find_multitype_specialization ctx.com a pl e.epos in
  254. let e = make_static_call ctx c cf a pl ((mk (TConst TNull) (TAbstract(a,pl)) e.epos) :: el) m e.epos in
  255. {e with etype = m}
  256. end
  257. | TCall({eexpr = TField(_,FStatic({cl_path=[],"Std"},{cf_name = "string"}))},[e1]) when (match follow e1.etype with TAbstract({a_impl = Some _},_) -> true | _ -> false) ->
  258. begin match follow e1.etype with
  259. | TAbstract({a_impl = Some c} as a,tl) ->
  260. begin try
  261. let cf = PMap.find "toString" c.cl_statics in
  262. let call() = make_static_call ctx c cf a tl [e1] ctx.t.tstring e.epos in
  263. if not ctx.allow_transform then
  264. { e1 with etype = ctx.t.tstring; epos = e.epos }
  265. else if not (is_nullable e1.etype) then
  266. call()
  267. else begin
  268. let p = e.epos in
  269. let chk_null = mk (TBinop (Ast.OpEq, e1, mk (TConst TNull) e1.etype p)) ctx.com.basic.tbool p in
  270. mk (TIf (chk_null, mk (TConst (TString "null")) ctx.com.basic.tstring p, Some (call()))) ctx.com.basic.tstring p
  271. end
  272. with Not_found ->
  273. e
  274. end
  275. | _ ->
  276. die "" __LOC__
  277. end
  278. | TCall(e1, el) ->
  279. begin try
  280. let rec find_abstract e t = match follow t,e.eexpr with
  281. | TAbstract(a,pl),_ when Meta.has Meta.MultiType a.a_meta -> a,pl,e
  282. | _,TCast(e1,None) -> find_abstract e1 e1.etype
  283. | _,TLocal {v_extra = Some({v_expr = Some e'})} ->
  284. begin match follow e'.etype with
  285. | TAbstract(a,pl) when Meta.has Meta.MultiType a.a_meta -> a,pl,mk (TCast(e,None)) e'.etype e.epos
  286. | _ -> raise Not_found
  287. end
  288. | _ -> raise Not_found
  289. in
  290. let rec find_field e1 =
  291. match e1.eexpr with
  292. | TCast(e2,None) ->
  293. {e1 with eexpr = TCast(find_field e2,None)}
  294. | TField(e2,fa) ->
  295. let a,pl,e2 = find_abstract e2 e2.etype in
  296. let m = Abstract.get_underlying_type a pl in
  297. let fname = field_name fa in
  298. let el = List.map (loop ctx) el in
  299. begin try
  300. let fa = quick_field m fname in
  301. let get_fun_type t = match follow t with
  302. | TFun(args,tr) as tf -> tf,args,tr
  303. | _ -> raise Not_found
  304. in
  305. let tf,args,tr = match fa with
  306. | FStatic(_,cf) -> get_fun_type cf.cf_type
  307. | FInstance(c,tl,cf) -> get_fun_type (apply_params c.cl_params tl cf.cf_type)
  308. | FAnon cf -> get_fun_type cf.cf_type
  309. | _ -> raise Not_found
  310. in
  311. let maybe_cast e t p =
  312. if type_iseq e.etype t then e
  313. else mk (TCast(e,None)) t p
  314. in
  315. let ef = mk (TField({e2 with etype = m},fa)) tf e2.epos in
  316. let el =
  317. if has_meta Meta.MultiType a.a_meta then
  318. let rec add_casts orig_args args el =
  319. match orig_args, args, el with
  320. | _, [], _ | _, _, [] -> el
  321. | [], (_,_,t) :: args, e :: el ->
  322. maybe_cast e t e.epos :: add_casts orig_args args el
  323. | (_,_,orig_t) :: orig_args, (_,_,t) :: args, e :: el ->
  324. let t =
  325. match follow t with
  326. | TMono _ -> (match follow orig_t with TDynamic _ -> orig_t | _ -> t)
  327. | _ -> t
  328. in
  329. maybe_cast e t e.epos :: add_casts orig_args args el
  330. in
  331. match follow e1.etype with
  332. | TFun (orig_args,_) -> add_casts orig_args args el
  333. | _ -> el
  334. else
  335. el
  336. in
  337. let ecall = make_call ctx ef el tr e.epos in
  338. maybe_cast ecall e.etype e.epos
  339. with Not_found ->
  340. (* quick_field raises Not_found if m is an abstract, we have to replicate the 'using' call here *)
  341. match follow m with
  342. | TAbstract({a_impl = Some c} as a,pl) ->
  343. let cf = PMap.find fname c.cl_statics in
  344. make_static_call ctx c cf a pl (e2 :: el) e.etype e.epos
  345. | _ -> raise Not_found
  346. end
  347. | _ ->
  348. raise Not_found
  349. in
  350. find_field e1
  351. with Not_found ->
  352. Type.map_expr (loop ctx) e
  353. end
  354. | _ ->
  355. Type.map_expr (loop ctx) e
  356. in
  357. loop ctx e
  358. ;;
  359. Typecore.cast_or_unify_raise_ref := cast_or_unify_raise