123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318 |
- open Globals
- open Common
- open Ast
- open Type
- open Typecore
- open Error
- open CallUnification
- let cast_stack = new_rec_stack()
- let rec make_static_call ctx c cf a pl args t p =
- if cf.cf_kind = Method MethMacro then begin
- match args with
- | [e] ->
- let e,f = push_this ctx e in
- ctx.with_type_stack <- (WithType.with_type t) :: ctx.with_type_stack;
- let e = match ctx.g.do_macro ctx MExpr c.cl_path cf.cf_name [e] p with
- | Some e -> type_expr ctx e (WithType.with_type t)
- | None -> type_expr ctx (EConst (Ident "null"),p) WithType.value
- in
- ctx.with_type_stack <- List.tl ctx.with_type_stack;
- let e = try cast_or_unify_raise ctx t e p with Error(Unify _,_) -> raise Not_found in
- f();
- e
- | _ -> die "" __LOC__
- end else
- Typecore.make_static_call ctx c cf (apply_params a.a_params pl) args t p
- and do_check_cast ctx uctx tleft eright p =
- let recurse cf f =
- (*
- Without this special check for macro @:from methods we will always get "Recursive implicit cast" error
- unlike non-macro @:from methods, which generate unification errors if no other @:from methods are involved.
- *)
- if cf.cf_kind = Method MethMacro then begin
- match cast_stack.rec_stack with
- | previous_from :: _ when previous_from == cf ->
- raise (Error (Unify [cannot_unify eright.etype tleft], eright.epos));
- | _ -> ()
- end;
- if cf == ctx.curfield || rec_stack_memq cf cast_stack then error "Recursive implicit cast" p;
- rec_stack_loop cast_stack cf f ()
- in
- let make (a,tl,(tcf,cf)) =
- if (Meta.has Meta.MultiType a.a_meta) then
- mk_cast eright tleft p
- else match a.a_impl with
- | Some c -> recurse cf (fun () ->
- let ret = make_static_call ctx c cf a tl [eright] tleft p in
- { ret with eexpr = TMeta( (Meta.ImplicitCast,[],ret.epos), ret) }
- )
- | None -> die "" __LOC__
- in
- if type_iseq_custom uctx tleft eright.etype then
- eright
- else begin
- let rec loop stack tleft tright =
- if List.exists (fun (tleft',tright') -> fast_eq tleft tleft' && fast_eq tright tright') stack then
- raise Not_found
- else begin
- let stack = (tleft,tright) :: stack in
- match follow tleft,follow tright with
- | TAbstract(a1,tl1),TAbstract(a2,tl2) ->
- make (Abstract.find_to_from uctx eright.etype tleft a2 tl2 a1 tl1)
- | TAbstract(a,tl),_ ->
- begin try make (a,tl,Abstract.find_from uctx eright.etype a tl)
- with Not_found ->
- let rec loop2 tcl = match tcl with
- | tc :: tcl ->
- if not (type_iseq_custom uctx tc tleft) then loop stack (apply_params a.a_params tl tc) tright
- else loop2 tcl
- | [] -> raise Not_found
- in
- loop2 a.a_from
- end
- | _,TAbstract(a,tl) ->
- begin try make (a,tl,Abstract.find_to uctx tleft a tl)
- with Not_found ->
- let rec loop2 tcl = match tcl with
- | tc :: tcl ->
- if not (type_iseq_custom uctx tc tright) then loop stack tleft (apply_params a.a_params tl tc)
- else loop2 tcl
- | [] -> raise Not_found
- in
- loop2 a.a_to
- end
- | _ ->
- raise Not_found
- end
- in
- loop [] tleft eright.etype
- end
- and cast_or_unify_raise ctx ?(uctx=None) tleft eright p =
- let uctx = match uctx with
- | None -> default_unification_context
- | Some uctx -> uctx
- in
- try
- do_check_cast ctx uctx tleft eright p
- with Not_found ->
- unify_raise_custom uctx ctx eright.etype tleft p;
- eright
- and cast_or_unify ctx tleft eright p =
- try
- cast_or_unify_raise ctx tleft eright p
- with Error (Unify l,p) ->
- raise_or_display ctx l p;
- eright
- let find_array_access_raise ctx a pl e1 e2o p =
- let is_set = e2o <> None in
- let ta = apply_params a.a_params pl a.a_this in
- let rec loop cfl =
- match cfl with
- | [] -> raise Not_found
- | cf :: cfl ->
- let monos = List.map (fun _ -> spawn_monomorph ctx p) cf.cf_params in
- let map t = apply_params a.a_params pl (apply_params cf.cf_params monos t) in
- let check_constraints () =
- List.iter2 (fun m (name,t) -> match follow t with
- | TInst ({ cl_kind = KTypeParameter constr },_) when constr <> [] ->
- List.iter (fun tc -> match follow m with TMono _ -> raise (Unify_error []) | _ -> Type.unify m (map tc) ) constr
- | _ -> ()
- ) monos cf.cf_params;
- in
- let get_ta() =
- if has_class_field_flag cf CfImpl then ta
- else TAbstract(a,pl)
- in
- match follow (map cf.cf_type) with
- | TFun([(_,_,tab);(_,_,ta1);(_,_,ta2)],r,_) as tf when is_set ->
- begin try
- Type.unify tab (get_ta());
- let e1 = cast_or_unify_raise ctx ta1 e1 p in
- let e2o = match e2o with None -> None | Some e2 -> Some (cast_or_unify_raise ctx ta2 e2 p) in
- check_constraints();
- cf,tf,r,e1,e2o
- with Unify_error _ | Error (Unify _,_) ->
- loop cfl
- end
- | TFun([(_,_,tab);(_,_,ta1)],r,_) as tf when not is_set ->
- begin try
- Type.unify tab (get_ta());
- let e1 = cast_or_unify_raise ctx ta1 e1 p in
- check_constraints();
- cf,tf,r,e1,None
- with Unify_error _ | Error (Unify _,_) ->
- loop cfl
- end
- | _ -> loop cfl
- in
- loop a.a_array
- let find_array_access ctx a tl e1 e2o p =
- try find_array_access_raise ctx a tl e1 e2o p
- with Not_found ->
- let s_type = s_type (print_context()) in
- match e2o with
- | None ->
- error (Printf.sprintf "No @:arrayAccess function for %s accepts argument of %s" (s_type (TAbstract(a,tl))) (s_type e1.etype)) p
- | Some e2 ->
- 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
- let find_multitype_specialization com a pl p =
- let uctx = default_unification_context in
- let m = mk_mono() in
- let tl,definitive_types = Abstract.find_multitype_params a pl in
- if com.platform = Globals.Js && a.a_path = (["haxe";"ds"],"Map") then begin match tl with
- | t1 :: _ ->
- let stack = ref [] in
- let rec loop t =
- if List.exists (fun t2 -> fast_eq t t2) !stack then
- t
- else begin
- stack := t :: !stack;
- match follow t with
- | TAbstract ({ a_path = [],"Class" },_) ->
- 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;
- | TEnum(en,tl) ->
- PMap.iter (fun _ ef -> ignore(loop ef.ef_type)) en.e_constrs;
- Type.map loop t
- | t ->
- Type.map loop t
- end
- in
- ignore(loop t1)
- | _ -> die "" __LOC__
- end;
- let _,cf =
- try
- let t = Abstract.find_to uctx m a tl in
- if List.exists (fun t -> has_mono t) definitive_types then begin
- let at = apply_params a.a_params pl a.a_this in
- let st = s_type (print_context()) at in
- error ("Type parameters of multi type abstracts must be known (for " ^ st ^ ")") p
- end;
- t
- with Not_found ->
- let at = apply_params a.a_params pl a.a_this in
- let st = s_type (print_context()) at in
- if has_mono at then
- error ("Type parameters of multi type abstracts must be known (for " ^ st ^ ")") p
- else
- error ("Abstract " ^ (s_type_path a.a_path) ^ " has no @:to function that accepts " ^ st) p;
- in
- cf, follow m
- let handle_abstract_casts ctx e =
- let rec loop ctx e = match e.eexpr with
- | TNew({cl_kind = KAbstractImpl a} as c,pl,el) ->
- if not (Meta.has Meta.MultiType a.a_meta) then begin
- (* This must have been a @:generic expansion with a { new } constraint (issue #4364). In this case
- let's construct the underlying type. *)
- match Abstract.get_underlying_type a pl with
- | TInst(c,tl) as t -> {e with eexpr = TNew(c,tl,el); etype = t}
- | _ -> error ("Cannot construct " ^ (s_type (print_context()) (TAbstract(a,pl)))) e.epos
- end else begin
- (* a TNew of an abstract implementation is only generated if it is a multi type abstract *)
- let cf,m = find_multitype_specialization ctx.com a pl e.epos in
- let e = make_static_call ctx c cf a pl ((mk (TConst TNull) (TAbstract(a,pl)) e.epos) :: el) m e.epos in
- {e with etype = m}
- end
- | TCall({eexpr = TField(_,FStatic({cl_path=[],"Std"},{cf_name = "string"}))},[e1]) when (match follow e1.etype with TAbstract({a_impl = Some _},_) -> true | _ -> false) ->
- begin match follow e1.etype with
- | TAbstract({a_impl = Some c} as a,tl) ->
- begin try
- let cf = PMap.find "toString" c.cl_statics in
- make_static_call ctx c cf a tl [e1] ctx.t.tstring e.epos
- with Not_found ->
- e
- end
- | _ ->
- die "" __LOC__
- end
- | TCall(e1, el) ->
- begin try
- let rec find_abstract e t = match follow t,e.eexpr with
- | TAbstract(a,pl),_ when Meta.has Meta.MultiType a.a_meta -> a,pl,e
- | _,TCast(e1,None) -> find_abstract e1 e1.etype
- | _,TLocal {v_extra = Some({v_expr = Some e'})} ->
- begin match follow e'.etype with
- | TAbstract(a,pl) when Meta.has Meta.MultiType a.a_meta -> a,pl,mk (TCast(e,None)) e'.etype e.epos
- | _ -> raise Not_found
- end
- | _ -> raise Not_found
- in
- let rec find_field e1 =
- match e1.eexpr with
- | TCast(e2,None) ->
- {e1 with eexpr = TCast(find_field e2,None)}
- | TField(e2,fa) ->
- let a,pl,e2 = find_abstract e2 e2.etype in
- let m = Abstract.get_underlying_type a pl in
- let fname = field_name fa in
- let el = List.map (loop ctx) el in
- begin try
- let fa = quick_field m fname in
- let get_fun_type t = match follow t with
- | TFun(args,tr,_) as tf -> tf,args,tr
- | _ -> raise Not_found
- in
- let tf,args,tr = match fa with
- | FStatic(_,cf) -> get_fun_type cf.cf_type
- | FInstance(c,tl,cf) -> get_fun_type (apply_params c.cl_params tl cf.cf_type)
- | FAnon cf -> get_fun_type cf.cf_type
- | _ -> raise Not_found
- in
- let maybe_cast e t p =
- if type_iseq e.etype t then e
- else mk (TCast(e,None)) t p
- in
- let ef = mk (TField({e2 with etype = m},fa)) tf e2.epos in
- let el =
- if has_meta Meta.MultiType a.a_meta then
- let rec add_casts orig_args args el =
- match orig_args, args, el with
- | _, [], _ | _, _, [] -> el
- | [], (_,_,t) :: args, e :: el ->
- maybe_cast e t e.epos :: add_casts orig_args args el
- | (_,_,orig_t) :: orig_args, (_,_,t) :: args, e :: el ->
- let t =
- match follow t with
- | TMono _ -> (match follow orig_t with TDynamic _ -> orig_t | _ -> t)
- | _ -> t
- in
- maybe_cast e t e.epos :: add_casts orig_args args el
- in
- match follow e1.etype with
- | TFun (orig_args,_,_) -> add_casts orig_args args el
- | _ -> el
- else
- el
- in
- let ecall = make_call ctx ef el tr e.epos in
- maybe_cast ecall e.etype e.epos
- with Not_found ->
- (* quick_field raises Not_found if m is an abstract, we have to replicate the 'using' call here *)
- match follow m with
- | TAbstract({a_impl = Some c} as a,pl) ->
- let cf = PMap.find fname c.cl_statics in
- make_static_call ctx c cf a pl (e2 :: el) e.etype e.epos
- | _ -> raise Not_found
- end
- | _ ->
- raise Not_found
- in
- find_field e1
- with Not_found ->
- Type.map_expr (loop ctx) e
- end
- | _ ->
- Type.map_expr (loop ctx) e
- in
- loop ctx e
- ;;
- Typecore.cast_or_unify_raise_ref := cast_or_unify_raise
|