abstractCast.ml 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  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. raise (Error (Unify [cannot_unify eright.etype tleft], eright.epos));
  36. | _ -> ()
  37. end;
  38. if cf == ctx.curfield || rec_stack_memq cf cast_stack then error "Recursive implicit cast" p;
  39. rec_stack_loop cast_stack cf f ()
  40. in
  41. let make (a,tl,(tcf,cf)) =
  42. if (Meta.has Meta.MultiType a.a_meta) then
  43. mk_cast eright tleft p
  44. else match a.a_impl with
  45. | Some c -> recurse cf (fun () ->
  46. let ret = make_static_call ctx c cf a tl [eright] tleft p in
  47. { ret with eexpr = TMeta( (Meta.ImplicitCast,[],ret.epos), ret) }
  48. )
  49. | None -> die "" __LOC__
  50. in
  51. if type_iseq_custom uctx tleft eright.etype then
  52. eright
  53. else begin
  54. let rec loop stack tleft tright =
  55. if List.exists (fun (tleft',tright') -> fast_eq tleft tleft' && fast_eq tright tright') stack then
  56. raise Not_found
  57. else begin
  58. let stack = (tleft,tright) :: stack in
  59. match follow tleft,follow tright with
  60. | TAbstract(a1,tl1),TAbstract(a2,tl2) ->
  61. make (Abstract.find_to_from uctx eright.etype tleft a2 tl2 a1 tl1)
  62. | TAbstract(a,tl),_ ->
  63. begin try make (a,tl,Abstract.find_from uctx eright.etype a tl)
  64. with Not_found ->
  65. let rec loop2 tcl = match tcl with
  66. | tc :: tcl ->
  67. if not (type_iseq_custom uctx tc tleft) then loop stack (apply_params a.a_params tl tc) tright
  68. else loop2 tcl
  69. | [] -> raise Not_found
  70. in
  71. loop2 a.a_from
  72. end
  73. | _,TAbstract(a,tl) ->
  74. begin try make (a,tl,Abstract.find_to uctx tleft a tl)
  75. with Not_found ->
  76. let rec loop2 tcl = match tcl with
  77. | tc :: tcl ->
  78. if not (type_iseq_custom uctx tc tright) then loop stack tleft (apply_params a.a_params tl tc)
  79. else loop2 tcl
  80. | [] -> raise Not_found
  81. in
  82. loop2 a.a_to
  83. end
  84. | _ ->
  85. raise Not_found
  86. end
  87. in
  88. loop [] tleft eright.etype
  89. end
  90. and cast_or_unify_raise ctx ?(uctx=None) tleft eright p =
  91. let uctx = match uctx with
  92. | None -> default_unification_context
  93. | Some uctx -> uctx
  94. in
  95. try
  96. do_check_cast ctx uctx tleft eright p
  97. with Not_found ->
  98. unify_raise_custom uctx ctx eright.etype tleft p;
  99. eright
  100. and cast_or_unify ctx tleft eright p =
  101. try
  102. cast_or_unify_raise ctx tleft eright p
  103. with Error (Unify l,p) ->
  104. raise_or_display ctx l p;
  105. eright
  106. let find_array_access_raise ctx a pl e1 e2o p =
  107. let is_set = e2o <> None in
  108. let ta = apply_params a.a_params pl a.a_this in
  109. let rec loop cfl =
  110. match cfl with
  111. | [] -> raise Not_found
  112. | cf :: cfl ->
  113. let monos = List.map (fun _ -> spawn_monomorph ctx p) cf.cf_params in
  114. let map t = apply_params a.a_params pl (apply_params cf.cf_params monos t) in
  115. let check_constraints () =
  116. List.iter2 (fun m (name,t) -> match follow t with
  117. | TInst ({ cl_kind = KTypeParameter constr },_) when constr <> [] ->
  118. List.iter (fun tc -> match follow m with TMono _ -> raise (Unify_error []) | _ -> Type.unify m (map tc) ) constr
  119. | _ -> ()
  120. ) monos cf.cf_params;
  121. in
  122. let get_ta() =
  123. if has_class_field_flag cf CfImpl then ta
  124. else TAbstract(a,pl)
  125. in
  126. match follow (map cf.cf_type) with
  127. | TFun([(_,_,tab);(_,_,ta1);(_,_,ta2)],r,_) as tf when is_set ->
  128. begin try
  129. Type.unify tab (get_ta());
  130. let e1 = cast_or_unify_raise ctx ta1 e1 p in
  131. let e2o = match e2o with None -> None | Some e2 -> Some (cast_or_unify_raise ctx ta2 e2 p) in
  132. check_constraints();
  133. cf,tf,r,e1,e2o
  134. with Unify_error _ | Error (Unify _,_) ->
  135. loop cfl
  136. end
  137. | TFun([(_,_,tab);(_,_,ta1)],r,_) as tf when not is_set ->
  138. begin try
  139. Type.unify tab (get_ta());
  140. let e1 = cast_or_unify_raise ctx ta1 e1 p in
  141. check_constraints();
  142. cf,tf,r,e1,None
  143. with Unify_error _ | Error (Unify _,_) ->
  144. loop cfl
  145. end
  146. | _ -> loop cfl
  147. in
  148. loop a.a_array
  149. let find_array_access ctx a tl e1 e2o p =
  150. try find_array_access_raise ctx a tl e1 e2o p
  151. with Not_found ->
  152. let s_type = s_type (print_context()) in
  153. match e2o with
  154. | None ->
  155. error (Printf.sprintf "No @:arrayAccess function for %s accepts argument of %s" (s_type (TAbstract(a,tl))) (s_type e1.etype)) p
  156. | Some e2 ->
  157. error (Printf.sprintf "No @:arrayAccess function for %s accepts arguments of %s and %s" (s_type (TAbstract(a,tl))) (s_type e1.etype) (s_type e2.etype)) p
  158. let find_multitype_specialization com a pl p =
  159. let uctx = default_unification_context in
  160. let m = mk_mono() in
  161. let tl,definitive_types = Abstract.find_multitype_params a pl in
  162. if com.platform = Globals.Js && a.a_path = (["haxe";"ds"],"Map") then begin match tl with
  163. | t1 :: _ ->
  164. let stack = ref [] in
  165. let rec loop t =
  166. if List.exists (fun t2 -> fast_eq t t2) !stack then
  167. t
  168. else begin
  169. stack := t :: !stack;
  170. match follow t with
  171. | TAbstract ({ a_path = [],"Class" },_) ->
  172. 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;
  173. | TEnum(en,tl) ->
  174. PMap.iter (fun _ ef -> ignore(loop ef.ef_type)) en.e_constrs;
  175. Type.map loop t
  176. | t ->
  177. Type.map loop t
  178. end
  179. in
  180. ignore(loop t1)
  181. | _ -> die "" __LOC__
  182. end;
  183. let _,cf =
  184. try
  185. let t = Abstract.find_to uctx m a tl in
  186. if List.exists (fun t -> has_mono t) definitive_types then begin
  187. let at = apply_params a.a_params pl a.a_this in
  188. let st = s_type (print_context()) at in
  189. error ("Type parameters of multi type abstracts must be known (for " ^ st ^ ")") p
  190. end;
  191. t
  192. with Not_found ->
  193. let at = apply_params a.a_params pl a.a_this in
  194. let st = s_type (print_context()) at in
  195. if has_mono at then
  196. error ("Type parameters of multi type abstracts must be known (for " ^ st ^ ")") p
  197. else
  198. error ("Abstract " ^ (s_type_path a.a_path) ^ " has no @:to function that accepts " ^ st) p;
  199. in
  200. cf, follow m
  201. let handle_abstract_casts ctx e =
  202. let rec loop ctx e = match e.eexpr with
  203. | TNew({cl_kind = KAbstractImpl a} as c,pl,el) ->
  204. if not (Meta.has Meta.MultiType a.a_meta) then begin
  205. (* This must have been a @:generic expansion with a { new } constraint (issue #4364). In this case
  206. let's construct the underlying type. *)
  207. match Abstract.get_underlying_type a pl with
  208. | TInst(c,tl) as t -> {e with eexpr = TNew(c,tl,el); etype = t}
  209. | _ -> error ("Cannot construct " ^ (s_type (print_context()) (TAbstract(a,pl)))) e.epos
  210. end else begin
  211. (* a TNew of an abstract implementation is only generated if it is a multi type abstract *)
  212. let cf,m = find_multitype_specialization ctx.com a pl e.epos in
  213. let e = make_static_call ctx c cf a pl ((mk (TConst TNull) (TAbstract(a,pl)) e.epos) :: el) m e.epos in
  214. {e with etype = m}
  215. end
  216. | TCall({eexpr = TField(_,FStatic({cl_path=[],"Std"},{cf_name = "string"}))},[e1]) when (match follow e1.etype with TAbstract({a_impl = Some _},_) -> true | _ -> false) ->
  217. begin match follow e1.etype with
  218. | TAbstract({a_impl = Some c} as a,tl) ->
  219. begin try
  220. let cf = PMap.find "toString" c.cl_statics in
  221. make_static_call ctx c cf a tl [e1] ctx.t.tstring e.epos
  222. with Not_found ->
  223. e
  224. end
  225. | _ ->
  226. die "" __LOC__
  227. end
  228. | TCall(e1, el) ->
  229. begin try
  230. let rec find_abstract e t = match follow t,e.eexpr with
  231. | TAbstract(a,pl),_ when Meta.has Meta.MultiType a.a_meta -> a,pl,e
  232. | _,TCast(e1,None) -> find_abstract e1 e1.etype
  233. | _,TLocal {v_extra = Some({v_expr = Some e'})} ->
  234. begin match follow e'.etype with
  235. | TAbstract(a,pl) when Meta.has Meta.MultiType a.a_meta -> a,pl,mk (TCast(e,None)) e'.etype e.epos
  236. | _ -> raise Not_found
  237. end
  238. | _ -> raise Not_found
  239. in
  240. let rec find_field e1 =
  241. match e1.eexpr with
  242. | TCast(e2,None) ->
  243. {e1 with eexpr = TCast(find_field e2,None)}
  244. | TField(e2,fa) ->
  245. let a,pl,e2 = find_abstract e2 e2.etype in
  246. let m = Abstract.get_underlying_type a pl in
  247. let fname = field_name fa in
  248. let el = List.map (loop ctx) el in
  249. begin try
  250. let fa = quick_field m fname in
  251. let get_fun_type t = match follow t with
  252. | TFun(args,tr,_) as tf -> tf,args,tr
  253. | _ -> raise Not_found
  254. in
  255. let tf,args,tr = match fa with
  256. | FStatic(_,cf) -> get_fun_type cf.cf_type
  257. | FInstance(c,tl,cf) -> get_fun_type (apply_params c.cl_params tl cf.cf_type)
  258. | FAnon cf -> get_fun_type cf.cf_type
  259. | _ -> raise Not_found
  260. in
  261. let maybe_cast e t p =
  262. if type_iseq e.etype t then e
  263. else mk (TCast(e,None)) t p
  264. in
  265. let ef = mk (TField({e2 with etype = m},fa)) tf e2.epos in
  266. let el =
  267. if has_meta Meta.MultiType a.a_meta then
  268. let rec add_casts orig_args args el =
  269. match orig_args, args, el with
  270. | _, [], _ | _, _, [] -> el
  271. | [], (_,_,t) :: args, e :: el ->
  272. maybe_cast e t e.epos :: add_casts orig_args args el
  273. | (_,_,orig_t) :: orig_args, (_,_,t) :: args, e :: el ->
  274. let t =
  275. match follow t with
  276. | TMono _ -> (match follow orig_t with TDynamic _ -> orig_t | _ -> t)
  277. | _ -> t
  278. in
  279. maybe_cast e t e.epos :: add_casts orig_args args el
  280. in
  281. match follow e1.etype with
  282. | TFun (orig_args,_,_) -> add_casts orig_args args el
  283. | _ -> el
  284. else
  285. el
  286. in
  287. let ecall = make_call ctx ef el tr e.epos in
  288. maybe_cast ecall e.etype e.epos
  289. with Not_found ->
  290. (* quick_field raises Not_found if m is an abstract, we have to replicate the 'using' call here *)
  291. match follow m with
  292. | TAbstract({a_impl = Some c} as a,pl) ->
  293. let cf = PMap.find fname c.cl_statics in
  294. make_static_call ctx c cf a pl (e2 :: el) e.etype e.epos
  295. | _ -> raise Not_found
  296. end
  297. | _ ->
  298. raise Not_found
  299. in
  300. find_field e1
  301. with Not_found ->
  302. Type.map_expr (loop ctx) e
  303. end
  304. | _ ->
  305. Type.map_expr (loop ctx) e
  306. in
  307. loop ctx e
  308. ;;
  309. Typecore.cast_or_unify_raise_ref := cast_or_unify_raise