123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043 |
- (*
- The Haxe Compiler
- Copyright (C) 2005-2015 Haxe Foundation
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *)
- open Ast
- open Type
- open Common
- open Typecore
- (* -------------------------------------------------------------------------- *)
- (* TOOLS *)
- let field e name t p =
- mk (TField (e,try quick_field e.etype name with Not_found -> assert false)) t p
- let fcall e name el ret p =
- let ft = tfun (List.map (fun e -> e.etype) el) ret in
- mk (TCall (field e name ft p,el)) ret p
- let mk_parent e =
- mk (TParenthesis e) e.etype e.epos
- let string com str p =
- mk (TConst (TString str)) com.basic.tstring p
- let binop op a b t p =
- mk (TBinop (op,a,b)) t p
- let index com e index t p =
- mk (TArray (e,mk (TConst (TInt (Int32.of_int index))) com.basic.tint p)) t p
- let maybe_cast e t =
- try
- type_eq EqDoNotFollowNull e.etype t;
- e
- with
- Unify_error _ -> mk (TCast(e,None)) t e.epos
- let type_constant com c p =
- let t = com.basic in
- match c with
- | Int s ->
- if String.length s > 10 && String.sub s 0 2 = "0x" then error "Invalid hexadecimal integer" p;
- (try mk (TConst (TInt (Int32.of_string s))) t.tint p
- with _ -> mk (TConst (TFloat s)) t.tfloat p)
- | Float f -> mk (TConst (TFloat f)) t.tfloat p
- | String s -> mk (TConst (TString s)) t.tstring p
- | Ident "true" -> mk (TConst (TBool true)) t.tbool p
- | Ident "false" -> mk (TConst (TBool false)) t.tbool p
- | Ident "null" -> mk (TConst TNull) (t.tnull (mk_mono())) p
- | Ident t -> error ("Invalid constant : " ^ t) p
- | Regexp _ -> error "Invalid constant" p
- let rec type_constant_value com (e,p) =
- match e with
- | EConst c ->
- type_constant com c p
- | EParenthesis e ->
- type_constant_value com e
- | EObjectDecl el ->
- mk (TObjectDecl (List.map (fun (n,e) -> n, type_constant_value com e) el)) (TAnon { a_fields = PMap.empty; a_status = ref Closed }) p
- | EArrayDecl el ->
- mk (TArrayDecl (List.map (type_constant_value com) el)) (com.basic.tarray t_dynamic) p
- | _ ->
- error "Constant value expected" p
- let rec has_properties c =
- List.exists (fun f ->
- match f.cf_kind with
- | Var { v_read = AccCall } -> true
- | Var { v_write = AccCall } -> true
- | _ when Meta.has Meta.Accessor f.cf_meta -> true
- | _ -> false
- ) c.cl_ordered_fields || (match c.cl_super with Some (c,_) -> has_properties c | _ -> false)
- let get_properties fields =
- List.fold_left (fun acc f ->
- if Meta.has Meta.Accessor f.cf_meta then
- (f.cf_name, f.cf_name) :: acc
- else
- let acc = (match f.cf_kind with
- | Var { v_read = AccCall } -> ("get_" ^ f.cf_name , "get_" ^ f.cf_name) :: acc
- | _ -> acc) in
- match f.cf_kind with
- | Var { v_write = AccCall } -> ("set_" ^ f.cf_name , "set_" ^ f.cf_name) :: acc
- | _ -> acc
- ) [] fields
- let add_property_field com c =
- let p = c.cl_pos in
- let props = get_properties (c.cl_ordered_statics @ c.cl_ordered_fields) in
- match props with
- | [] -> ()
- | _ ->
- let fields,values = List.fold_left (fun (fields,values) (n,v) ->
- let cf = mk_field n com.basic.tstring p in
- PMap.add n cf fields,(n, string com v p) :: values
- ) (PMap.empty,[]) props in
- let t = mk_anon fields in
- let e = mk (TObjectDecl values) t p in
- let cf = mk_field "__properties__" t p in
- cf.cf_expr <- Some e;
- c.cl_statics <- PMap.add cf.cf_name cf c.cl_statics;
- c.cl_ordered_statics <- cf :: c.cl_ordered_statics
- let is_removable_field ctx f =
- Meta.has Meta.Extern f.cf_meta || Meta.has Meta.Generic f.cf_meta
- || (match f.cf_kind with
- | Var {v_read = AccRequire (s,_)} -> true
- | Method MethMacro -> not ctx.in_macro
- | _ -> false)
- let escape_res_name name allow_dirs =
- ExtString.String.replace_chars (fun chr ->
- if (chr >= 'a' && chr <= 'z') || (chr >= 'A' && chr <= 'Z') || (chr >= '0' && chr <= '9') || chr = '_' || chr = '.' then
- Char.escaped chr
- else if chr = '/' && allow_dirs then
- "/"
- else
- "-x" ^ (string_of_int (Char.code chr))) name
- (* -------------------------------------------------------------------------- *)
- (* REMOTING PROXYS *)
- let extend_remoting ctx c t p async prot =
- if c.cl_super <> None then error "Cannot extend several classes" p;
- (* remove forbidden packages *)
- let rules = ctx.com.package_rules in
- ctx.com.package_rules <- PMap.foldi (fun key r acc -> match r with Forbidden -> acc | _ -> PMap.add key r acc) rules PMap.empty;
- (* parse module *)
- let path = (t.tpackage,t.tname) in
- let new_name = (if async then "Async_" else "Remoting_") ^ t.tname in
- (* check if the proxy already exists *)
- let t = (try
- Typeload.load_type_def ctx p { tpackage = fst path; tname = new_name; tparams = []; tsub = None }
- with
- Error (Module_not_found _,p2) when p == p2 ->
- (* build it *)
- Common.log ctx.com ("Building proxy for " ^ s_type_path path);
- let file, decls = (try
- Typeload.parse_module ctx path p
- with
- | Not_found -> ctx.com.package_rules <- rules; error ("Could not load proxy module " ^ s_type_path path ^ (if fst path = [] then " (try using absolute path)" else "")) p
- | e -> ctx.com.package_rules <- rules; raise e) in
- ctx.com.package_rules <- rules;
- let base_fields = [
- { cff_name = "__cnx"; cff_pos = p; cff_doc = None; cff_meta = []; cff_access = []; cff_kind = FVar (Some (CTPath { tpackage = ["haxe";"remoting"]; tname = if async then "AsyncConnection" else "Connection"; tparams = []; tsub = None }),None) };
- { cff_name = "new"; cff_pos = p; cff_doc = None; cff_meta = []; cff_access = [APublic]; cff_kind = FFun { f_args = ["c",false,None,None]; f_type = None; f_expr = Some (EBinop (OpAssign,(EConst (Ident "__cnx"),p),(EConst (Ident "c"),p)),p); f_params = [] } };
- ] in
- let tvoid = CTPath { tpackage = []; tname = "Void"; tparams = []; tsub = None } in
- let build_field is_public acc f =
- if f.cff_name = "new" then
- acc
- else match f.cff_kind with
- | FFun fd when (is_public || List.mem APublic f.cff_access) && not (List.mem AStatic f.cff_access) ->
- if List.exists (fun (_,_,t,_) -> t = None) fd.f_args then error ("Field " ^ f.cff_name ^ " type is not complete and cannot be used by RemotingProxy") p;
- let eargs = [EArrayDecl (List.map (fun (a,_,_,_) -> (EConst (Ident a),p)) fd.f_args),p] in
- let ftype = (match fd.f_type with Some (CTPath { tpackage = []; tname = "Void" }) -> None | _ -> fd.f_type) in
- let fargs, eargs = if async then match ftype with
- | Some tret -> fd.f_args @ ["__callb",true,Some (CTFunction ([tret],tvoid)),None], eargs @ [EConst (Ident "__callb"),p]
- | _ -> fd.f_args, eargs @ [EConst (Ident "null"),p]
- else
- fd.f_args, eargs
- in
- let id = (EConst (String f.cff_name), p) in
- let id = if prot then id else ECall ((EConst (Ident "__unprotect__"),p),[id]),p in
- let expr = ECall (
- (EField (
- (ECall ((EField ((EConst (Ident "__cnx"),p),"resolve"),p),[id]),p),
- "call")
- ,p),eargs),p
- in
- let expr = if async || ftype = None then expr else (EReturn (Some expr),p) in
- let fd = {
- f_params = fd.f_params;
- f_args = fargs;
- f_type = if async then None else ftype;
- f_expr = Some (EBlock [expr],p);
- } in
- { cff_name = f.cff_name; cff_pos = p; cff_doc = None; cff_meta = []; cff_access = [APublic]; cff_kind = FFun fd } :: acc
- | _ -> acc
- in
- let decls = List.map (fun d ->
- match d with
- | EClass c, p when c.d_name = t.tname ->
- let is_public = List.mem HExtern c.d_flags || List.mem HInterface c.d_flags in
- let fields = List.rev (List.fold_left (build_field is_public) base_fields c.d_data) in
- (EClass { c with d_flags = []; d_name = new_name; d_data = fields },p)
- | _ -> d
- ) decls in
- let m = Typeload.type_module ctx (t.tpackage,new_name) file decls p in
- add_dependency ctx.m.curmod m;
- try
- List.find (fun tdecl -> snd (t_path tdecl) = new_name) m.m_types
- with Not_found ->
- error ("Module " ^ s_type_path path ^ " does not define type " ^ t.tname) p
- ) in
- match t with
- | TClassDecl c2 when c2.cl_params = [] -> ignore(c2.cl_build()); c.cl_super <- Some (c2,[]);
- | _ -> error "Remoting proxy must be a class without parameters" p
- (* -------------------------------------------------------------------------- *)
- (* HAXE.RTTI.GENERIC *)
- exception Generic_Exception of string * Ast.pos
- type generic_context = {
- ctx : typer;
- subst : (t * t) list;
- name : string;
- p : pos;
- mutable mg : module_def option;
- }
- let make_generic ctx ps pt p =
- let rec loop l1 l2 =
- match l1, l2 with
- | [] , [] -> []
- | (x,TLazy f) :: l1, _ -> loop ((x,(!f)()) :: l1) l2
- | (_,t1) :: l1 , t2 :: l2 -> (t1,t2) :: loop l1 l2
- | _ -> assert false
- in
- let name =
- String.concat "_" (List.map2 (fun (s,_) t ->
- let s_type_path_underscore (p,s) = match p with [] -> s | _ -> String.concat "_" p ^ "_" ^ s in
- let rec loop top t = match follow t with
- | TInst(c,tl) -> (s_type_path_underscore c.cl_path) ^ (loop_tl tl)
- | TEnum(en,tl) -> (s_type_path_underscore en.e_path) ^ (loop_tl tl)
- | TAbstract(a,tl) -> (s_type_path_underscore a.a_path) ^ (loop_tl tl)
- | _ when not top -> "_" (* allow unknown/incompatible types as type parameters to retain old behavior *)
- | TMono _ -> raise (Generic_Exception (("Could not determine type for parameter " ^ s), p))
- | TDynamic _ -> "Dynamic"
- | t -> raise (Generic_Exception (("Type parameter must be a class or enum instance (found " ^ (s_type (print_context()) t) ^ ")"), p))
- and loop_tl tl = match tl with
- | [] -> ""
- | tl -> "_" ^ String.concat "_" (List.map (loop false) tl)
- in
- loop true t
- ) ps pt)
- in
- {
- ctx = ctx;
- subst = loop ps pt;
- name = name;
- p = p;
- mg = None;
- }
- let rec generic_substitute_type gctx t =
- match t with
- | TInst ({ cl_kind = KGeneric } as c2,tl2) ->
- (* maybe loop, or generate cascading generics *)
- let _, _, f = gctx.ctx.g.do_build_instance gctx.ctx (TClassDecl c2) gctx.p in
- let t = f (List.map (generic_substitute_type gctx) tl2) in
- (match follow t,gctx.mg with TInst(c,_), Some m -> add_dependency m c.cl_module | _ -> ());
- t
- | _ ->
- try
- generic_substitute_type gctx (List.assq t gctx.subst)
- with Not_found ->
- Type.map (generic_substitute_type gctx) t
- let generic_substitute_expr gctx e =
- let vars = Hashtbl.create 0 in
- let build_var v =
- try
- Hashtbl.find vars v.v_id
- with Not_found ->
- let v2 = alloc_var v.v_name (generic_substitute_type gctx v.v_type) in
- v2.v_meta <- v.v_meta;
- Hashtbl.add vars v.v_id v2;
- v2
- in
- let rec build_expr e =
- match e.eexpr with
- | TField(e1, FInstance({cl_kind = KGeneric} as c,tl,cf)) ->
- let _, _, f = gctx.ctx.g.do_build_instance gctx.ctx (TClassDecl c) gctx.p in
- let t = f (List.map (generic_substitute_type gctx) tl) in
- build_expr {e with eexpr = TField(e1,quick_field t cf.cf_name)}
- | TTypeExpr (TClassDecl ({cl_kind = KTypeParameter _;} as c)) when Meta.has Meta.Const c.cl_meta ->
- let rec loop subst = match subst with
- | (t1,t2) :: subst ->
- begin match follow t1 with
- | TInst(c2,_) when c == c2 -> t2
- | _ -> loop subst
- end
- | [] -> raise Not_found
- in
- begin try
- let t = loop gctx.subst in
- begin match follow t with
- | TInst({cl_kind = KExpr e},_) -> type_expr gctx.ctx e Value
- | _ -> error "Only Const type parameters can be used as value" e.epos
- end
- with Not_found ->
- e
- end
- | _ ->
- map_expr_type build_expr (generic_substitute_type gctx) build_var e
- in
- build_expr e
- let has_ctor_constraint c = match c.cl_kind with
- | KTypeParameter tl ->
- List.exists (fun t -> match follow t with
- | TAnon a when PMap.mem "new" a.a_fields -> true
- | _ -> false
- ) tl;
- | _ -> false
- let get_short_name =
- let i = ref (-1) in
- (fun () ->
- incr i;
- Printf.sprintf "Hx___short___hx_type_%i" !i
- )
- let rec build_generic ctx c p tl =
- let pack = fst c.cl_path in
- let recurse = ref false in
- let rec check_recursive t =
- match follow t with
- | TInst (c2,tl) ->
- (match c2.cl_kind with
- | KTypeParameter tl ->
- if not (Typeload.is_generic_parameter ctx c2) && has_ctor_constraint c2 then
- error "Type parameters with a constructor cannot be used non-generically" p;
- recurse := true
- | _ -> ());
- List.iter check_recursive tl;
- | _ ->
- ()
- in
- List.iter check_recursive tl;
- if !recurse then begin
- TInst (c,tl) (* build a normal instance *)
- end else begin
- let gctx = make_generic ctx c.cl_params tl p in
- let name = (snd c.cl_path) ^ "_" ^ gctx.name in
- try
- Typeload.load_instance ctx { tpackage = pack; tname = name; tparams = []; tsub = None } p false
- with Error(Module_not_found path,_) when path = (pack,name) ->
- let m = (try Hashtbl.find ctx.g.modules (Hashtbl.find ctx.g.types_module c.cl_path) with Not_found -> assert false) in
- let ctx = { ctx with m = { ctx.m with module_types = m.m_types @ ctx.m.module_types } } in
- ignore(c.cl_build()); (* make sure the super class is already setup *)
- let mg = {
- m_id = alloc_mid();
- m_path = (pack,name);
- m_types = [];
- m_extra = module_extra (s_type_path (pack,name)) m.m_extra.m_sign 0. MFake;
- } in
- gctx.mg <- Some mg;
- let cg = mk_class mg (pack,name) c.cl_pos in
- mg.m_types <- [TClassDecl cg];
- Hashtbl.add ctx.g.modules mg.m_path mg;
- add_dependency mg m;
- add_dependency ctx.m.curmod mg;
- (* ensure that type parameters are set in dependencies *)
- let dep_stack = ref [] in
- let rec loop t =
- if not (List.memq t !dep_stack) then begin
- dep_stack := t :: !dep_stack;
- match t with
- | TInst (c,tl) -> add_dep c.cl_module tl
- | TEnum (e,tl) -> add_dep e.e_module tl
- | TType (t,tl) -> add_dep t.t_module tl
- | TAbstract (a,tl) -> add_dep a.a_module tl
- | TMono r ->
- (match !r with
- | None -> ()
- | Some t -> loop t)
- | TLazy f ->
- loop ((!f)());
- | TDynamic t2 ->
- if t == t2 then () else loop t2
- | TAnon a ->
- PMap.iter (fun _ f -> loop f.cf_type) a.a_fields
- | TFun (args,ret) ->
- List.iter (fun (_,_,t) -> loop t) args;
- loop ret
- end
- and add_dep m tl =
- add_dependency mg m;
- List.iter loop tl
- in
- List.iter loop tl;
- let build_field cf_old =
- let cf_new = {cf_old with cf_pos = cf_old.cf_pos} in (* copy *)
- let f () =
- let t = generic_substitute_type gctx cf_old.cf_type in
- ignore (follow t);
- begin try (match cf_old.cf_expr with
- | None ->
- begin match cf_old.cf_kind with
- | Method _ when not c.cl_interface && not c.cl_extern ->
- display_error ctx (Printf.sprintf "Field %s has no expression (possible typing order issue)" cf_new.cf_name) cf_new.cf_pos;
- display_error ctx (Printf.sprintf "While building %s" (s_type_path cg.cl_path)) p;
- | _ ->
- ()
- end
- | Some e ->
- cf_new.cf_expr <- Some (generic_substitute_expr gctx e)
- ) with Unify_error l ->
- error (error_msg (Unify l)) cf_new.cf_pos
- end;
- t
- in
- let r = exc_protect ctx (fun r ->
- let t = mk_mono() in
- r := (fun() -> t);
- unify_raise ctx (f()) t p;
- t
- ) "build_generic" in
- delay ctx PForce (fun() -> ignore ((!r)()));
- cf_new.cf_type <- TLazy r;
- cf_new
- in
- if c.cl_init <> None || c.cl_dynamic <> None then error "This class can't be generic" p;
- List.iter (fun cf -> match cf.cf_kind with
- | Method MethMacro when not ctx.in_macro -> ()
- | _ -> error "A generic class can't have static fields" cf.cf_pos
- ) c.cl_ordered_statics;
- cg.cl_super <- (match c.cl_super with
- | None -> None
- | Some (cs,pl) ->
- let find_class subst =
- let rec loop subst = match subst with
- | (TInst(c,[]),t) :: subst when c == cs -> t
- | _ :: subst -> loop subst
- | [] -> raise Not_found
- in
- try
- if pl <> [] then raise Not_found;
- let t = loop subst in
- (* extended type parameter: concrete type must have a constructor, but generic base class must not have one *)
- begin match follow t,c.cl_constructor with
- | TInst(cs,_),None ->
- ignore(cs.cl_build());
- begin match cs.cl_constructor with
- | None -> error ("Cannot use " ^ (s_type_path cs.cl_path) ^ " as type parameter because it is extended and has no constructor") p
- | _ -> ()
- end;
- | _,Some cf -> error "Generics extending type parameters cannot have constructors" cf.cf_pos
- | _ -> ()
- end;
- t
- with Not_found ->
- apply_params c.cl_params tl (TInst(cs,pl))
- in
- let ts = follow (find_class gctx.subst) in
- let cs,pl = Typeload.check_extends ctx c ts p in
- match cs.cl_kind with
- | KGeneric ->
- (match build_generic ctx cs p pl with
- | TInst (cs,pl) -> Some (cs,pl)
- | _ -> assert false)
- | _ -> Some(cs,pl)
- );
- Typeload.add_constructor ctx cg false p;
- cg.cl_kind <- KGenericInstance (c,tl);
- cg.cl_meta <- (Meta.NoDoc,[],p) :: cg.cl_meta;
- cg.cl_interface <- c.cl_interface;
- cg.cl_constructor <- (match cg.cl_constructor, c.cl_constructor, c.cl_super with
- | _, Some cf, _ -> Some (build_field cf)
- | Some ctor, _, _ -> Some ctor
- | None, None, None -> None
- | _ -> error "Please define a constructor for this class in order to use it as generic" c.cl_pos
- );
- cg.cl_implements <- List.map (fun (i,tl) ->
- (match follow (generic_substitute_type gctx (TInst (i, List.map (generic_substitute_type gctx) tl))) with
- | TInst (i,tl) -> i, tl
- | _ -> assert false)
- ) c.cl_implements;
- cg.cl_ordered_fields <- List.map (fun f ->
- let f = build_field f in
- cg.cl_fields <- PMap.add f.cf_name f cg.cl_fields;
- f
- ) c.cl_ordered_fields;
- (* In rare cases the class name can become too long, so let's shorten it (issue #3090). *)
- if String.length (snd cg.cl_path) > 254 then begin
- let n = get_short_name () in
- cg.cl_meta <- (Meta.Native,[EConst(String (n)),p],p) :: cg.cl_meta;
- end;
- TInst (cg,[])
- end
- (* -------------------------------------------------------------------------- *)
- (* HAXE.XML.PROXY *)
- let extend_xml_proxy ctx c t file p =
- let t = Typeload.load_complex_type ctx p t in
- let file = (try Common.find_file ctx.com file with Not_found -> file) in
- add_dependency c.cl_module (create_fake_module ctx file);
- let used = ref PMap.empty in
- let print_results() =
- PMap.iter (fun id used ->
- if not used then ctx.com.warning (id ^ " is not used") p;
- ) (!used)
- in
- let check_used = Common.defined ctx.com Define.CheckXmlProxy in
- if check_used then ctx.g.hook_generate <- print_results :: ctx.g.hook_generate;
- try
- let rec loop = function
- | Xml.Element (_,attrs,childs) ->
- (try
- let id = List.assoc "id" attrs in
- if PMap.mem id c.cl_fields then error ("Duplicate id " ^ id) p;
- let t = if not check_used then t else begin
- used := PMap.add id false (!used);
- let ft() = used := PMap.add id true (!used); t in
- TLazy (ref ft)
- end in
- let f = {
- cf_name = id;
- cf_type = t;
- cf_public = true;
- cf_pos = p;
- cf_doc = None;
- cf_meta = no_meta;
- cf_kind = Var { v_read = AccResolve; v_write = AccNo };
- cf_params = [];
- cf_expr = None;
- cf_overloads = [];
- } in
- c.cl_fields <- PMap.add id f c.cl_fields;
- with
- Not_found -> ());
- List.iter loop childs;
- | Xml.PCData _ -> ()
- in
- loop (Xml.parse_file file)
- with
- | Xml.Error e -> error ("XML error " ^ Xml.error e) p
- | Xml.File_not_found f -> error ("XML File not found : " ^ f) p
- (* -------------------------------------------------------------------------- *)
- (* BUILD META DATA OBJECT *)
- let build_metadata com t =
- let api = com.basic in
- let p, meta, fields, statics = (match t with
- | TClassDecl c ->
- let fields = List.map (fun f -> f.cf_name,f.cf_meta) (c.cl_ordered_fields @ (match c.cl_constructor with None -> [] | Some f -> [{ f with cf_name = "_" }])) in
- let statics = List.map (fun f -> f.cf_name,f.cf_meta) c.cl_ordered_statics in
- (c.cl_pos, ["",c.cl_meta],fields,statics)
- | TEnumDecl e ->
- (e.e_pos, ["",e.e_meta],List.map (fun n -> n, (PMap.find n e.e_constrs).ef_meta) e.e_names, [])
- | TTypeDecl t ->
- (t.t_pos, ["",t.t_meta],(match follow t.t_type with TAnon a -> PMap.fold (fun f acc -> (f.cf_name,f.cf_meta) :: acc) a.a_fields [] | _ -> []),[])
- | TAbstractDecl a ->
- (a.a_pos, ["",a.a_meta],[],[])
- ) in
- let filter l =
- let l = List.map (fun (n,ml) -> n, ExtList.List.filter_map (fun (m,el,p) -> match m with Meta.Custom s when String.length s > 0 && s.[0] <> ':' -> Some (s,el,p) | _ -> None) ml) l in
- List.filter (fun (_,ml) -> ml <> []) l
- in
- let meta, fields, statics = filter meta, filter fields, filter statics in
- let make_meta_field ml =
- let h = Hashtbl.create 0 in
- mk (TObjectDecl (List.map (fun (f,el,p) ->
- if Hashtbl.mem h f then error ("Duplicate metadata '" ^ f ^ "'") p;
- Hashtbl.add h f ();
- f, mk (match el with [] -> TConst TNull | _ -> TArrayDecl (List.map (type_constant_value com) el)) (api.tarray t_dynamic) p
- ) ml)) t_dynamic p
- in
- let make_meta l =
- mk (TObjectDecl (List.map (fun (f,ml) -> f,make_meta_field ml) l)) t_dynamic p
- in
- if meta = [] && fields = [] && statics = [] then
- None
- else
- let meta_obj = [] in
- let meta_obj = (if fields = [] then meta_obj else ("fields",make_meta fields) :: meta_obj) in
- let meta_obj = (if statics = [] then meta_obj else ("statics",make_meta statics) :: meta_obj) in
- let meta_obj = (try ("obj", make_meta_field (List.assoc "" meta)) :: meta_obj with Not_found -> meta_obj) in
- Some (mk (TObjectDecl meta_obj) t_dynamic p)
- (* -------------------------------------------------------------------------- *)
- (* MACRO TYPE *)
- let get_macro_path ctx e args p =
- let rec loop e =
- match fst e with
- | EField (e,f) -> f :: loop e
- | EConst (Ident i) -> [i]
- | _ -> error "Invalid macro call" p
- in
- let path = match e with
- | (EConst(Ident i)),_ ->
- let path = try
- if not (PMap.mem i ctx.curclass.cl_statics) then raise Not_found;
- ctx.curclass.cl_path
- with Not_found -> try
- (t_infos (fst (PMap.find i ctx.m.module_globals))).mt_path
- with Not_found ->
- error "Invalid macro call" p
- in
- i :: (snd path) :: (fst path)
- | _ ->
- loop e
- in
- (match path with
- | meth :: cl :: path -> (List.rev path,cl), meth, args
- | _ -> error "Invalid macro call" p)
- let build_macro_type ctx pl p =
- let path, field, args = (match pl with
- | [TInst ({ cl_kind = KExpr (ECall (e,args),_) },_)]
- | [TInst ({ cl_kind = KExpr (EArrayDecl [ECall (e,args),_],_) },_)] ->
- get_macro_path ctx e args p
- | _ ->
- error "MacroType requires a single expression call parameter" p
- ) in
- let old = ctx.ret in
- let t = (match ctx.g.do_macro ctx MMacroType path field args p with
- | None -> mk_mono()
- | Some _ -> ctx.ret
- ) in
- ctx.ret <- old;
- t
- let build_macro_build ctx c pl cfl p =
- let path, field, args = match Meta.get Meta.GenericBuild c.cl_meta with
- | _,[ECall(e,args),_],_ -> get_macro_path ctx e args p
- | _ -> error "genericBuild requires a single expression call parameter" p
- in
- let old = ctx.ret,ctx.g.get_build_infos in
- ctx.g.get_build_infos <- (fun() -> Some (TClassDecl c, pl, cfl));
- let t = (match ctx.g.do_macro ctx MMacroType path field args p with
- | None -> mk_mono()
- | Some _ -> ctx.ret
- ) in
- ctx.ret <- fst old;
- ctx.g.get_build_infos <- snd old;
- t
- (* -------------------------------------------------------------------------- *)
- (* API EVENTS *)
- let build_instance ctx mtype p =
- match mtype with
- | TClassDecl c ->
- if ctx.pass > PBuildClass then ignore(c.cl_build());
- let build f s =
- let r = exc_protect ctx (fun r ->
- let t = mk_mono() in
- r := (fun() -> t);
- unify_raise ctx (f()) t p;
- t
- ) s in
- delay ctx PForce (fun() -> ignore ((!r)()));
- TLazy r
- in
- let ft = (fun pl ->
- match c.cl_kind with
- | KGeneric ->
- build (fun () -> build_generic ctx c p pl) "build_generic"
- | KMacroType ->
- build (fun () -> build_macro_type ctx pl p) "macro_type"
- | KGenericBuild cfl ->
- build (fun () -> build_macro_build ctx c pl cfl p) "generic_build"
- | _ ->
- TInst (c,pl)
- ) in
- c.cl_params , c.cl_path , ft
- | TEnumDecl e ->
- e.e_params , e.e_path , (fun t -> TEnum (e,t))
- | TTypeDecl t ->
- t.t_params , t.t_path , (fun tl -> TType(t,tl))
- | TAbstractDecl a ->
- a.a_params, a.a_path, (fun tl -> TAbstract(a,tl))
- let on_inherit ctx c p h =
- match h with
- | HExtends { tpackage = ["haxe";"remoting"]; tname = "Proxy"; tparams = [TPType(CTPath t)] } ->
- extend_remoting ctx c t p false true;
- false
- | HExtends { tpackage = ["haxe";"remoting"]; tname = "AsyncProxy"; tparams = [TPType(CTPath t)] } ->
- extend_remoting ctx c t p true true;
- false
- | HExtends { tpackage = ["haxe";"xml"]; tname = "Proxy"; tparams = [TPExpr(EConst (String file),p);TPType t] } ->
- extend_xml_proxy ctx c t file p;
- true
- | _ ->
- true
- let push_this ctx e = match e.eexpr with
- | TConst ((TInt _ | TFloat _ | TString _ | TBool _) as ct) ->
- (EConst (tconst_to_const ct),e.epos),fun () -> ()
- | _ ->
- ctx.this_stack <- e :: ctx.this_stack;
- let er = EMeta((Meta.This,[],e.epos), (EConst(Ident "this"),e.epos)),e.epos in
- er,fun () -> ctx.this_stack <- List.tl ctx.this_stack
- (* -------------------------------------------------------------------------- *)
- (* ABSTRACT CASTS *)
- module AbstractCast = struct
- let cast_stack = ref []
- let 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 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 Value
- | None -> type_expr ctx (EConst (Ident "null"),p) Value
- in
- ctx.with_type_stack <- List.tl ctx.with_type_stack;
- f();
- e
- | _ -> assert false
- end else
- make_static_call ctx c cf (apply_params a.a_params pl) args t p
- let do_check_cast ctx tleft eright p =
- let recurse cf f =
- if cf == ctx.curfield || List.mem cf !cast_stack then error "Recursive implicit cast" p;
- cast_stack := cf :: !cast_stack;
- let r = f() in
- cast_stack := List.tl !cast_stack;
- r
- in
- let find a tl f =
- let tcf,cf = f() in
- 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 -> assert false
- in
- if type_iseq tleft eright.etype then
- eright
- else begin
- let rec loop tleft tright = match follow tleft,follow tright with
- | TAbstract(a1,tl1),TAbstract(a2,tl2) ->
- begin try find a2 tl2 (fun () -> Abstract.find_to a2 tl2 tleft)
- with Not_found -> try find a1 tl1 (fun () -> Abstract.find_from a1 tl1 eright.etype tleft)
- with Not_found -> raise Not_found
- end
- | TAbstract(a,tl),_ ->
- begin try find a tl (fun () -> Abstract.find_from a tl eright.etype tleft)
- with Not_found ->
- let rec loop2 tcl = match tcl with
- | tc :: tcl ->
- if not (type_iseq tc tleft) then loop (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 find a tl (fun () -> Abstract.find_to a tl tleft)
- with Not_found ->
- let rec loop2 tcl = match tcl with
- | tc :: tcl ->
- if not (type_iseq tc tright) then loop tleft (apply_params a.a_params tl tc)
- else loop2 tcl
- | [] -> raise Not_found
- in
- loop2 a.a_to
- end
- | _ ->
- raise Not_found
- in
- loop tleft eright.etype
- end
- let cast_or_unify_raise ctx tleft eright p =
- try
- (* can't do that anymore because this might miss macro calls (#4315) *)
- (* if ctx.com.display <> DMNone then raise Not_found; *)
- do_check_cast ctx tleft eright p
- with Not_found ->
- unify_raise ctx eright.etype tleft p;
- eright
- let cast_or_unify ctx tleft eright p =
- try
- cast_or_unify_raise ctx tleft eright p
- with Error (Unify _ as err,_) ->
- if not ctx.untyped then display_error ctx (error_msg err) 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 _ -> mk_mono()) 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
- match follow (map cf.cf_type) with
- | TFun([(_,_,tab);(_,_,ta1);(_,_,ta2)],r) as tf when is_set ->
- begin try
- Type.unify tab 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 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 -> match e2o with
- | None ->
- error (Printf.sprintf "No @:arrayAccess function accepts argument of %s" (s_type (print_context()) e1.etype)) p
- | Some e2 ->
- error (Printf.sprintf "No @:arrayAccess function accepts arguments of %s and %s" (s_type (print_context()) e1.etype) (s_type (print_context()) e2.etype)) p
- let find_multitype_specialization com a pl p =
- let m = mk_mono() in
- let tl = match Meta.get Meta.MultiType a.a_meta with
- | _,[],_ -> pl
- | _,el,_ ->
- let relevant = Hashtbl.create 0 in
- List.iter (fun e -> match fst e with
- | EConst(Ident s) -> Hashtbl.replace relevant s true
- | _ -> error "Type parameter expected" (pos e)
- ) el;
- let tl = List.map2 (fun (n,_) t -> if Hashtbl.mem relevant n || not (has_mono t) then t else t_dynamic) a.a_params pl in
- if com.platform = Js && a.a_path = ([],"Map") then begin match tl with
- | t1 :: _ ->
- let rec loop stack t =
- if List.exists (fun t2 -> fast_eq t t2) stack then
- t
- else begin
- let stack = t :: stack in
- 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" (s_type (print_context()) t1)) p;
- | TEnum(en,tl) ->
- PMap.iter (fun _ ef -> ignore(loop stack ef.ef_type)) en.e_constrs;
- Type.map (loop stack) t
- | t ->
- Type.map (loop stack) t
- end
- in
- ignore(loop [] t1)
- | _ -> assert false
- end;
- tl
- in
- let _,cf =
- try
- Abstract.find_to a tl m
- 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) ->
- (* 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}
- | 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
- | _ ->
- assert false
- end
- | TCall(e1, el) ->
- begin try
- let rec find_abstract e = match follow e.etype,e.eexpr with
- | TAbstract(a,pl),_ when Meta.has Meta.MultiType a.a_meta -> a,pl,e
- | _,TCast(e1,None) -> find_abstract e1
- | _ -> 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 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(_,tr) as tf -> tf,tr
- | _ -> raise Not_found
- in
- let tf,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 ef = mk (TField({e2 with etype = m},fa)) tf e2.epos in
- let ecall = make_call ctx ef el tr e.epos in
- if not (type_iseq ecall.etype e.etype) then
- mk (TCast(ecall,None)) e.etype e.epos
- else
- ecall
- 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
- end
- module PatternMatchConversion = struct
- type cctx = {
- ctx : typer;
- mutable eval_stack : ((tvar * pos) * texpr) list list;
- dt_lookup : dt array;
- }
- let is_declared cctx v =
- let rec loop sl = match sl with
- | stack :: sl ->
- List.exists (fun ((v2,_),_) -> v == v2) stack || loop sl
- | [] ->
- false
- in
- loop cctx.eval_stack
- let group_cases cases =
- let dt_eq dt1 dt2 = match dt1,dt2 with
- | DTGoto i1, DTGoto i2 when i1 = i2 -> true
- (* TODO equal bindings *)
- | _ -> false
- in
- match List.rev cases with
- | [] -> []
- | [con,dt] -> [[con],dt]
- | (con,dt) :: cases ->
- let tmp,ldt,cases = List.fold_left (fun (tmp,ldt,acc) (con,dt) ->
- if dt_eq dt ldt then
- (con :: tmp,dt,acc)
- else
- ([con],dt,(tmp,ldt) :: acc)
- ) ([con],dt,[]) cases in
- match tmp with
- | [] -> cases
- | tmp -> ((tmp,ldt) :: cases)
- let replace_locals e =
- let v_known = ref IntMap.empty in
- let copy v =
- let v' = alloc_var v.v_name v.v_type in
- v_known := IntMap.add v.v_id v' !v_known;
- v'
- in
- let rec loop e = match e.eexpr with
- | TVar(v,e1) ->
- let v' = copy v in
- let e1 = match e1 with None -> None | Some e -> Some (loop e) in
- {e with eexpr = TVar(v',e1)}
- | TFor(v,e1,e2) ->
- let v' = copy v in
- let e1 = loop e1 in
- let e2 = loop e2 in
- {e with eexpr = TFor(v',e1,e2)}
- | TTry(e1,catches) ->
- let e1 = loop e1 in
- let catches = List.map (fun (v,e) ->
- let v' = copy v in
- let e = loop e in
- v',e
- ) catches in
- {e with eexpr = TTry(e1,catches)}
- | TLocal v ->
- let v' = try IntMap.find v.v_id !v_known with Not_found -> v in
- {e with eexpr = TLocal v'}
- | _ ->
- Type.map_expr loop e
- in
- loop e
- let rec convert_dt cctx dt =
- match dt with
- | DTBind (bl,dt) ->
- cctx.eval_stack <- bl :: cctx.eval_stack;
- let e = convert_dt cctx dt in
- cctx.eval_stack <- List.tl cctx.eval_stack;
- let vl,el = List.fold_left (fun (vl,el) ((v,p),e) ->
- if is_declared cctx v then
- vl, (mk (TBinop(OpAssign,mk (TLocal v) v.v_type p,e)) e.etype e.epos) :: el
- else
- ((v,p,Some e) :: vl), el
- ) ([],[e]) bl in
- let el_v = List.map (fun (v,p,eo) -> mk (TVar (v,eo)) cctx.ctx.t.tvoid p) vl in
- mk (TBlock (el_v @ el)) e.etype e.epos
- | DTGoto i ->
- convert_dt cctx (cctx.dt_lookup.(i))
- | DTExpr e ->
- e
- | DTGuard(e,dt1,dt2) ->
- let ethen = convert_dt cctx dt1 in
- mk (TIf(e,ethen,match dt2 with None -> None | Some dt -> Some (convert_dt cctx dt))) ethen.etype (punion e.epos ethen.epos)
- | DTSwitch({eexpr = TMeta((Meta.Exhaustive,_,_),_)},[_,dt],None) ->
- convert_dt cctx dt
- | DTSwitch(e_st,cl,dto) ->
- let def = match dto with None -> None | Some dt -> Some (convert_dt cctx dt) in
- let cases = group_cases cl in
- let cases = List.map (fun (cl,dt) ->
- let e = convert_dt cctx dt in
- (* The macro interpreter does not care about unique locals and
- we don't run the analyzer on the output, so let's save some
- time here (issue #3937) *)
- let e = if cctx.ctx.in_macro then e else replace_locals e in
- cl,e
- ) cases in
- mk (TSwitch(e_st,cases,def)) (mk_mono()) e_st.epos
- let to_typed_ast ctx dt p =
- let first = dt.dt_dt_lookup.(dt.dt_first) in
- let cctx = {
- ctx = ctx;
- dt_lookup = dt.dt_dt_lookup;
- eval_stack = [];
- } in
- let e = convert_dt cctx first in
- let e = { e with epos = p; etype = dt.dt_type} in
- if dt.dt_var_init = [] then
- e
- else begin
- let el_v = List.map (fun (v,eo) -> mk (TVar (v,eo)) cctx.ctx.t.tvoid p) dt.dt_var_init in
- mk (TBlock (el_v @ [e])) dt.dt_type e.epos
- end
- end
- (* -------------------------------------------------------------------------- *)
- (* USAGE *)
- let detect_usage com =
- let usage = ref [] in
- List.iter (fun t -> match t with
- | TClassDecl c ->
- let check_constructor c p =
- try
- let _,cf = get_constructor (fun cf -> cf.cf_type) c in
- if Meta.has Meta.Usage cf.cf_meta then
- usage := p :: !usage;
- with Not_found ->
- ()
- in
- let rec expr e = match e.eexpr with
- | TField(_,FEnum(_,ef)) when Meta.has Meta.Usage ef.ef_meta ->
- let p = {e.epos with pmin = e.epos.pmax - (String.length ef.ef_name)} in
- usage := p :: !usage;
- Type.iter expr e
- | TField(_,(FAnon cf | FInstance (_,_,cf) | FStatic (_,cf) | FClosure (_,cf))) when Meta.has Meta.Usage cf.cf_meta ->
- let p = {e.epos with pmin = e.epos.pmax - (String.length cf.cf_name)} in
- usage := p :: !usage;
- Type.iter expr e
- | TLocal v when Meta.has Meta.Usage v.v_meta ->
- usage := e.epos :: !usage
- | TVar (v,_) when com.display = DMPosition && Meta.has Meta.Usage v.v_meta ->
- raise (Typecore.DisplayPosition [e.epos])
- | TFunction tf when com.display = DMPosition && List.exists (fun (v,_) -> Meta.has Meta.Usage v.v_meta) tf.tf_args ->
- raise (Typecore.DisplayPosition [e.epos])
- | TTypeExpr mt when (Meta.has Meta.Usage (t_infos mt).mt_meta) ->
- usage := e.epos :: !usage
- | TNew (c,_,_) ->
- check_constructor c e.epos;
- Type.iter expr e;
- | TCall({eexpr = TConst TSuper},_) ->
- begin match c.cl_super with
- | Some (c,_) ->
- check_constructor c e.epos
- | _ ->
- ()
- end
- | _ -> Type.iter expr e
- in
- let field cf = ignore(follow cf.cf_type); match cf.cf_expr with None -> () | Some e -> expr e in
- (match c.cl_constructor with None -> () | Some cf -> field cf);
- (match c.cl_init with None -> () | Some e -> expr e);
- List.iter field c.cl_ordered_statics;
- List.iter field c.cl_ordered_fields;
- | _ -> ()
- ) com.types;
- let usage = List.sort (fun p1 p2 ->
- let c = compare p1.pfile p2.pfile in
- if c <> 0 then c else compare p1.pmin p2.pmin
- ) !usage in
- raise (Typecore.DisplayPosition usage)
- let update_cache_dependencies com =
- let rec check_t m t = match t with
- | TInst(c,tl) ->
- add_dependency m c.cl_module;
- List.iter (check_t m) tl;
- | TEnum(en,tl) ->
- add_dependency m en.e_module;
- List.iter (check_t m) tl;
- | TType(t,tl) ->
- add_dependency m t.t_module;
- List.iter (check_t m) tl;
- | TAbstract(a,tl) ->
- add_dependency m a.a_module;
- List.iter (check_t m) tl;
- | TFun(targs,tret) ->
- List.iter (fun (_,_,t) -> check_t m t) targs;
- check_t m tret;
- | TAnon an ->
- PMap.iter (fun _ cf -> check_field m cf) an.a_fields
- | TMono r ->
- (match !r with
- | Some t -> check_t m t
- | _ -> ())
- | TLazy f ->
- check_t m (!f())
- | TDynamic t ->
- if t == t_dynamic then
- ()
- else
- check_t m t
- and check_field m cf =
- check_t m cf.cf_type
- in
- List.iter (fun t -> match t with
- | TClassDecl c ->
- List.iter (check_field c.cl_module) c.cl_ordered_statics;
- List.iter (check_field c.cl_module) c.cl_ordered_fields;
- (match c.cl_constructor with None -> () | Some cf -> check_field c.cl_module cf);
- | _ ->
- ()
- ) com.types
- (* -------------------------------------------------------------------------- *)
- (* STACK MANAGEMENT EMULATION *)
- type stack_context = {
- stack_var : string;
- stack_exc_var : string;
- stack_pos_var : string;
- stack_pos : pos;
- stack_expr : texpr;
- stack_pop : texpr;
- stack_save_pos : texpr;
- stack_restore : texpr list;
- stack_push : tclass -> string -> texpr;
- stack_return : texpr -> texpr;
- }
- let stack_context_init com stack_var exc_var pos_var tmp_var use_add p =
- let t = com.basic in
- let st = t.tarray t.tstring in
- let stack_var = alloc_var stack_var st in
- let exc_var = alloc_var exc_var st in
- let pos_var = alloc_var pos_var t.tint in
- let stack_e = mk (TLocal stack_var) st p in
- let exc_e = mk (TLocal exc_var) st p in
- let stack_pop = fcall stack_e "pop" [] t.tstring p in
- let stack_push c m =
- fcall stack_e "push" [
- if use_add then
- binop OpAdd (string com (s_type_path c.cl_path ^ "::") p) (string com m p) t.tstring p
- else
- string com (s_type_path c.cl_path ^ "::" ^ m) p
- ] t.tvoid p
- in
- let stack_return e =
- let tmp = alloc_var tmp_var e.etype in
- mk (TBlock [
- mk (TVar (tmp, Some e)) t.tvoid e.epos;
- stack_pop;
- mk (TReturn (Some (mk (TLocal tmp) e.etype e.epos))) e.etype e.epos
- ]) e.etype e.epos
- in
- {
- stack_var = stack_var.v_name;
- stack_exc_var = exc_var.v_name;
- stack_pos_var = pos_var.v_name;
- stack_pos = p;
- stack_expr = stack_e;
- stack_pop = stack_pop;
- stack_save_pos = mk (TVar (pos_var, Some (field stack_e "length" t.tint p))) t.tvoid p;
- stack_push = stack_push;
- stack_return = stack_return;
- stack_restore = [
- binop OpAssign exc_e (mk (TArrayDecl []) st p) st p;
- mk (TWhile (
- mk_parent (binop OpGte (field stack_e "length" t.tint p) (mk (TLocal pos_var) t.tint p) t.tbool p),
- fcall exc_e "unshift" [fcall stack_e "pop" [] t.tstring p] t.tvoid p,
- NormalWhile
- )) t.tvoid p;
- fcall stack_e "push" [index com exc_e 0 t.tstring p] t.tvoid p
- ];
- }
- let stack_init com use_add =
- stack_context_init com "$s" "$e" "$spos" "$tmp" use_add null_pos
- let rec stack_block_loop ctx e =
- match e.eexpr with
- | TFunction _ ->
- e
- | TReturn None | TReturn (Some { eexpr = TConst _ }) | TReturn (Some { eexpr = TLocal _ }) ->
- mk (TBlock [
- ctx.stack_pop;
- e;
- ]) e.etype e.epos
- | TReturn (Some e) ->
- ctx.stack_return (stack_block_loop ctx e)
- | TTry (v,cases) ->
- let v = stack_block_loop ctx v in
- let cases = List.map (fun (v,e) ->
- let e = stack_block_loop ctx e in
- let e = (match (mk_block e).eexpr with
- | TBlock l -> mk (TBlock (ctx.stack_restore @ l)) e.etype e.epos
- | _ -> assert false
- ) in
- v , e
- ) cases in
- mk (TTry (v,cases)) e.etype e.epos
- | _ ->
- map_expr (stack_block_loop ctx) e
- let stack_block ctx c m e =
- match (mk_block e).eexpr with
- | TBlock l ->
- mk (TBlock (
- ctx.stack_push c m ::
- ctx.stack_save_pos ::
- List.map (stack_block_loop ctx) l
- @ [ctx.stack_pop]
- )) e.etype e.epos
- | _ ->
- assert false
- (* -------------------------------------------------------------------------- *)
- (* FIX OVERRIDES *)
- (*
- on some platforms which doesn't support type parameters, we must have the
- exact same type for overriden/implemented function as the original one
- *)
- let rec find_field com c f =
- try
- (match c.cl_super with
- | None ->
- raise Not_found
- | Some ( {cl_path = (["cpp"],"FastIterator")}, _ ) ->
- raise Not_found (* This is a strongly typed 'extern' and the usual rules don't apply *)
- | Some (c,_) ->
- find_field com c f)
- with Not_found -> try
- if com.platform = Cpp then (* Cpp uses delegation for interfaces *)
- raise Not_found;
- let rec loop = function
- | [] ->
- raise Not_found
- | (c,_) :: l ->
- try
- find_field com c f
- with
- Not_found -> loop l
- in
- loop c.cl_implements
- with Not_found ->
- let f = PMap.find f.cf_name c.cl_fields in
- (match f.cf_kind with Var { v_read = AccRequire _ } -> raise Not_found | _ -> ());
- f
- let fix_override com c f fd =
- let f2 = (try Some (find_field com c f) with Not_found -> None) in
- match f2,fd with
- | Some (f2), Some(fd) ->
- let targs, tret = (match follow f2.cf_type with TFun (args,ret) -> args, ret | _ -> assert false) in
- let changed_args = ref [] in
- let prefix = "_tmp_" in
- let nargs = List.map2 (fun ((v,ct) as cur) (_,_,t2) ->
- try
- type_eq EqStrict (monomorphs c.cl_params (monomorphs f.cf_params v.v_type)) t2;
- (* Flash generates type parameters with a single constraint as that constraint type, so we
- have to detect this case and change the variable (issue #2712). *)
- begin match follow v.v_type with
- | TInst({cl_kind = KTypeParameter [tc]} as cp,_) when com.platform = Flash ->
- if List.mem_assoc (snd cp.cl_path) c.cl_params then raise (Unify_error [])
- | _ ->
- ()
- end;
- cur
- with Unify_error _ ->
- let v2 = alloc_var (prefix ^ v.v_name) t2 in
- changed_args := (v,v2) :: !changed_args;
- v2,ct
- ) fd.tf_args targs in
- let fd2 = {
- tf_args = nargs;
- tf_type = tret;
- tf_expr = (match List.rev !changed_args with
- | [] -> fd.tf_expr
- | args ->
- let e = fd.tf_expr in
- let el = (match e.eexpr with TBlock el -> el | _ -> [e]) in
- let p = (match el with [] -> e.epos | e :: _ -> e.epos) in
- let el_v = List.map (fun (v,v2) ->
- mk (TVar (v,Some (mk (TCast (mk (TLocal v2) v2.v_type p,None)) v.v_type p))) com.basic.tvoid p
- ) args in
- { e with eexpr = TBlock (el_v @ el) }
- );
- } in
- (* as3 does not allow wider visibility, so the base method has to be made public *)
- if Common.defined com Define.As3 && f.cf_public then f2.cf_public <- true;
- let targs = List.map (fun(v,c) -> (v.v_name, Option.is_some c, v.v_type)) nargs in
- let fde = (match f.cf_expr with None -> assert false | Some e -> e) in
- f.cf_expr <- Some { fde with eexpr = TFunction fd2 };
- f.cf_type <- TFun(targs,tret);
- | Some(f2), None when c.cl_interface ->
- let targs, tret = (match follow f2.cf_type with TFun (args,ret) -> args, ret | _ -> assert false) in
- f.cf_type <- TFun(targs,tret)
- | _ ->
- ()
- let fix_overrides com t =
- match t with
- | TClassDecl c ->
- (* overrides can be removed from interfaces *)
- if c.cl_interface then
- c.cl_ordered_fields <- List.filter (fun f ->
- try
- if find_field com c f == f then raise Not_found;
- c.cl_fields <- PMap.remove f.cf_name c.cl_fields;
- false;
- with Not_found ->
- true
- ) c.cl_ordered_fields;
- List.iter (fun f ->
- match f.cf_expr, f.cf_kind with
- | Some { eexpr = TFunction fd }, Method (MethNormal | MethInline) ->
- fix_override com c f (Some fd)
- | None, Method (MethNormal | MethInline) when c.cl_interface ->
- fix_override com c f None
- | _ ->
- ()
- ) c.cl_ordered_fields
- | _ ->
- ()
- (*
- PHP does not allow abstract classes extending other abstract classes to override any fields, so these duplicates
- must be removed from the child interface
- *)
- let fix_abstract_inheritance com t =
- match t with
- | TClassDecl c when c.cl_interface ->
- c.cl_ordered_fields <- List.filter (fun f ->
- let b = try (find_field com c f) == f
- with Not_found -> false in
- if not b then c.cl_fields <- PMap.remove f.cf_name c.cl_fields;
- b;
- ) c.cl_ordered_fields
- | _ -> ()
- (* -------------------------------------------------------------------------- *)
- (* MISC FEATURES *)
- let rec is_volatile t =
- match t with
- | TMono r ->
- (match !r with
- | Some t -> is_volatile t
- | _ -> false)
- | TLazy f ->
- is_volatile (!f())
- | TType (t,tl) ->
- (match t.t_path with
- | _ -> is_volatile (apply_params t.t_params tl t.t_type))
- | _ ->
- false
- let set_default ctx a c p =
- let t = a.v_type in
- let ve = mk (TLocal a) t p in
- let cond = TBinop (OpEq,ve,mk (TConst TNull) t p) in
- mk (TIf (mk_parent (mk cond ctx.basic.tbool p), mk (TBinop (OpAssign,ve,mk (TConst c) t p)) t p,None)) ctx.basic.tvoid p
- let bytes_serialize data =
- let b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" in
- let tbl = Array.init (String.length b64) (fun i -> String.get b64 i) in
- Base64.str_encode ~tbl data
- (*
- Tells if the constructor might be called without any issue whatever its parameters
- *)
- let rec constructor_side_effects e =
- match e.eexpr with
- | TBinop (op,_,_) when op <> OpAssign ->
- true
- | TField (_,FEnum _) ->
- false
- | TUnop _ | TArray _ | TField _ | TEnumParameter _ | TCall _ | TNew _ | TFor _ | TWhile _ | TSwitch _ | TReturn _ | TThrow _ ->
- true
- | TBinop _ | TTry _ | TIf _ | TBlock _ | TVar _
- | TFunction _ | TArrayDecl _ | TObjectDecl _
- | TParenthesis _ | TTypeExpr _ | TLocal _ | TMeta _
- | TConst _ | TContinue | TBreak | TCast _ ->
- try
- Type.iter (fun e -> if constructor_side_effects e then raise Exit) e;
- false;
- with Exit ->
- true
- let make_valid_filename s =
- let r = Str.regexp "[^A-Za-z0-9_\\-\\.,]" in
- Str.global_substitute r (fun s -> "_") s
- (*
- Make a dump of the full typed AST of all types
- *)
- let rec create_dumpfile acc = function
- | [] -> assert false
- | d :: [] ->
- let d = make_valid_filename d in
- let ch = open_out (String.concat "/" (List.rev (d :: acc)) ^ ".dump") in
- let buf = Buffer.create 0 in
- buf, (fun () ->
- output_string ch (Buffer.contents buf);
- close_out ch)
- | d :: l ->
- let dir = String.concat "/" (List.rev (d :: acc)) in
- if not (Sys.file_exists dir) then Unix.mkdir dir 0o755;
- create_dumpfile (d :: acc) l
- let dump_types com =
- let s_type = s_type (Type.print_context()) in
- let params = function [] -> "" | l -> Printf.sprintf "<%s>" (String.concat "," (List.map (fun (n,t) -> n ^ " : " ^ s_type t) l)) in
- let s_expr = match Common.defined_value_safe com Define.Dump with
- | "pretty" -> Type.s_expr_pretty "\t"
- | "legacy" -> Type.s_expr
- | _ -> Type.s_expr_ast (not (Common.defined com Define.DumpIgnoreVarIds)) "\t"
- in
- List.iter (fun mt ->
- let path = Type.t_path mt in
- let buf,close = create_dumpfile [] ("dump" :: (Common.platform_name com.platform) :: fst path @ [snd path]) in
- let print fmt = Printf.kprintf (fun s -> Buffer.add_string buf s) fmt in
- (match mt with
- | Type.TClassDecl c ->
- let rec print_field stat f =
- print "\t%s%s%s%s" (if stat then "static " else "") (if f.cf_public then "public " else "") f.cf_name (params f.cf_params);
- print "(%s) : %s" (s_kind f.cf_kind) (s_type f.cf_type);
- (match f.cf_expr with
- | None -> ()
- | Some e -> print "\n\n\t = %s" (s_expr s_type e));
- print "\n\n";
- List.iter (fun f -> print_field stat f) f.cf_overloads
- in
- print "%s%s%s %s%s" (if c.cl_private then "private " else "") (if c.cl_extern then "extern " else "") (if c.cl_interface then "interface" else "class") (s_type_path path) (params c.cl_params);
- (match c.cl_super with None -> () | Some (c,pl) -> print " extends %s" (s_type (TInst (c,pl))));
- List.iter (fun (c,pl) -> print " implements %s" (s_type (TInst (c,pl)))) c.cl_implements;
- (match c.cl_dynamic with None -> () | Some t -> print " implements Dynamic<%s>" (s_type t));
- (match c.cl_array_access with None -> () | Some t -> print " implements ArrayAccess<%s>" (s_type t));
- print "{\n";
- (match c.cl_constructor with
- | None -> ()
- | Some f -> print_field false f);
- List.iter (print_field false) c.cl_ordered_fields;
- List.iter (print_field true) c.cl_ordered_statics;
- (match c.cl_init with
- | None -> ()
- | Some e ->
- print "\n\n\t__init__ = ";
- print "%s" (s_expr s_type e);
- print "}\n");
- print "}";
- | Type.TEnumDecl e ->
- print "%s%senum %s%s {\n" (if e.e_private then "private " else "") (if e.e_extern then "extern " else "") (s_type_path path) (params e.e_params);
- List.iter (fun n ->
- let f = PMap.find n e.e_constrs in
- print "\t%s : %s;\n" f.ef_name (s_type f.ef_type);
- ) e.e_names;
- print "}"
- | Type.TTypeDecl t ->
- print "%stype %s%s = %s" (if t.t_private then "private " else "") (s_type_path path) (params t.t_params) (s_type t.t_type);
- | Type.TAbstractDecl a ->
- print "%sabstract %s%s {}" (if a.a_private then "private " else "") (s_type_path path) (params a.a_params);
- );
- close();
- ) com.types
- let dump_dependencies com =
- let buf,close = create_dumpfile [] ["dump";Common.platform_name com.platform;".dependencies"] in
- let print fmt = Printf.kprintf (fun s -> Buffer.add_string buf s) fmt in
- let dep = Hashtbl.create 0 in
- List.iter (fun m ->
- print "%s:\n" m.m_extra.m_file;
- PMap.iter (fun _ m2 ->
- print "\t%s\n" (m2.m_extra.m_file);
- let l = try Hashtbl.find dep m2.m_extra.m_file with Not_found -> [] in
- Hashtbl.replace dep m2.m_extra.m_file (m :: l)
- ) m.m_extra.m_deps;
- ) com.Common.modules;
- close();
- let buf,close = create_dumpfile [] ["dump";Common.platform_name com.platform;".dependants"] in
- let print fmt = Printf.kprintf (fun s -> Buffer.add_string buf s) fmt in
- Hashtbl.iter (fun n ml ->
- print "%s:\n" n;
- List.iter (fun m ->
- print "\t%s\n" (m.m_extra.m_file);
- ) ml;
- ) dep;
- close()
- (*
- Build a default safe-cast expression :
- { var $t = <e>; if( Std.is($t,<t>) ) $t else throw "Class cast error"; }
- *)
- let default_cast ?(vtmp="$t") com e texpr t p =
- let api = com.basic in
- let mk_texpr = function
- | TClassDecl c -> TAnon { a_fields = PMap.empty; a_status = ref (Statics c) }
- | TEnumDecl e -> TAnon { a_fields = PMap.empty; a_status = ref (EnumStatics e) }
- | TAbstractDecl a -> TAnon { a_fields = PMap.empty; a_status = ref (AbstractStatics a) }
- | TTypeDecl _ -> assert false
- in
- let vtmp = alloc_var vtmp e.etype in
- let var = mk (TVar (vtmp,Some e)) api.tvoid p in
- let vexpr = mk (TLocal vtmp) e.etype p in
- let texpr = mk (TTypeExpr texpr) (mk_texpr texpr) p in
- let std = (try List.find (fun t -> t_path t = ([],"Std")) com.types with Not_found -> assert false) in
- let fis = (try
- let c = (match std with TClassDecl c -> c | _ -> assert false) in
- FStatic (c, PMap.find "is" c.cl_statics)
- with Not_found ->
- assert false
- ) in
- let std = mk (TTypeExpr std) (mk_texpr std) p in
- let is = mk (TField (std,fis)) (tfun [t_dynamic;t_dynamic] api.tbool) p in
- let is = mk (TCall (is,[vexpr;texpr])) api.tbool p in
- let exc = mk (TThrow (mk (TConst (TString "Class cast error")) api.tstring p)) t p in
- let check = mk (TIf (mk_parent is,mk (TCast (vexpr,None)) t p,Some exc)) t p in
- mk (TBlock [var;check;vexpr]) t p
- (** Overload resolution **)
- module Overloads =
- struct
- let rec simplify_t t = match t with
- | TAbstract(a,_) when Meta.has Meta.CoreType a.a_meta ->
- t
- | TInst _ | TEnum _ ->
- t
- | TAbstract(a,tl) -> simplify_t (Abstract.get_underlying_type a tl)
- | TType(({ t_path = [],"Null" } as t), [t2]) -> (match simplify_t t2 with
- | (TAbstract(a,_) as t2) when Meta.has Meta.CoreType a.a_meta ->
- TType(t, [simplify_t t2])
- | (TEnum _ as t2) ->
- TType(t, [simplify_t t2])
- | t2 -> t2)
- | TType(t, tl) ->
- simplify_t (apply_params t.t_params tl t.t_type)
- | TMono r -> (match !r with
- | Some t -> simplify_t t
- | None -> t_dynamic)
- | TAnon _ -> t_dynamic
- | TDynamic _ -> t
- | TLazy f -> simplify_t (!f())
- | TFun _ -> t
- (* rate type parameters *)
- let rate_tp tlfun tlarg =
- let acc = ref 0 in
- List.iter2 (fun f a -> if not (type_iseq f a) then incr acc) tlfun tlarg;
- !acc
- (**
- The rate function returns an ( int * int ) type.
- The smaller the int, the best rated the caller argument is in comparison with the callee.
- The first int refers to how many "conversions" would be necessary to convert from the callee to the caller type, and
- the second refers to the type parameters.
- **)
- let rec rate_conv cacc tfun targ =
- match simplify_t tfun, simplify_t targ with
- | TInst({ cl_interface = true } as cf, tlf), TInst(ca, tla) ->
- (* breadth-first *)
- let stack = ref [0,ca,tla] in
- let cur = ref (0, ca,tla) in
- let rec loop () =
- match !stack with
- | [] -> (let acc, ca, tla = !cur in match ca.cl_super with
- | None -> raise Not_found
- | Some (sup,tls) ->
- cur := (acc+1,sup,List.map (apply_params ca.cl_params tla) tls);
- stack := [!cur];
- loop())
- | (acc,ca,tla) :: _ when ca == cf ->
- acc,tla
- | (acc,ca,tla) :: s ->
- stack := s @ List.map (fun (c,tl) -> (acc+1,c,List.map (apply_params ca.cl_params tla) tl)) ca.cl_implements;
- loop()
- in
- let acc, tla = loop() in
- (cacc + acc, rate_tp tlf tla)
- | TInst(cf,tlf), TInst(ca,tla) ->
- let rec loop acc ca tla =
- if cf == ca then
- acc, tla
- else match ca.cl_super with
- | None -> raise Not_found
- | Some(sup,stl) ->
- loop (acc+1) sup (List.map (apply_params ca.cl_params tla) stl)
- in
- let acc, tla = loop 0 ca tla in
- (cacc + acc, rate_tp tlf tla)
- | TEnum(ef,tlf), TEnum(ea, tla) ->
- if ef != ea then raise Not_found;
- (cacc, rate_tp tlf tla)
- | TDynamic _, TDynamic _ ->
- (cacc, 0)
- | TDynamic _, _ ->
- (max_int, 0) (* a function with dynamic will always be worst of all *)
- | TAbstract(a, _), TDynamic _ when Meta.has Meta.CoreType a.a_meta ->
- (cacc + 2, 0) (* a dynamic to a basic type will have an "unboxing" penalty *)
- | _, TDynamic _ ->
- (cacc + 1, 0)
- | TAbstract(af,tlf), TAbstract(aa,tla) ->
- (if af == aa then
- (cacc, rate_tp tlf tla)
- else
- let ret = ref None in
- if List.exists (fun t -> try
- ret := Some (rate_conv (cacc+1) (apply_params af.a_params tlf t) targ);
- true
- with | Not_found ->
- false
- ) af.a_from then
- Option.get !ret
- else
- if List.exists (fun t -> try
- ret := Some (rate_conv (cacc+1) tfun (apply_params aa.a_params tla t));
- true
- with | Not_found ->
- false
- ) aa.a_to then
- Option.get !ret
- else
- raise Not_found)
- | TType({ t_path = [], "Null" }, [tf]), TType({ t_path = [], "Null" }, [ta]) ->
- rate_conv (cacc+0) tf ta
- | TType({ t_path = [], "Null" }, [tf]), ta ->
- rate_conv (cacc+1) tf ta
- | tf, TType({ t_path = [], "Null" }, [ta]) ->
- rate_conv (cacc+1) tf ta
- | TFun _, TFun _ -> (* unify will make sure they are compatible *)
- cacc,0
- | tfun,targ ->
- raise Not_found
- let is_best arg1 arg2 =
- (List.for_all2 (fun v1 v2 ->
- v1 <= v2)
- arg1 arg2) && (List.exists2 (fun v1 v2 ->
- v1 < v2)
- arg1 arg2)
- let rec rm_duplicates acc ret = match ret with
- | [] -> acc
- | ( el, t, _ ) :: ret when List.exists (fun (_,t2,_) -> type_iseq t t2) acc ->
- rm_duplicates acc ret
- | r :: ret ->
- rm_duplicates (r :: acc) ret
- let s_options rated =
- String.concat ",\n" (List.map (fun ((elist,t,_),rate) ->
- "( " ^ (String.concat "," (List.map (fun(e,_) -> s_expr (s_type (print_context())) e) elist)) ^ " ) => " ^
- "( " ^ (String.concat "," (List.map (fun (i,i2) -> string_of_int i ^ ":" ^ string_of_int i2) rate)) ^ " ) => " ^ (s_type (print_context()) t)
- ) rated)
- let count_optionals elist =
- List.fold_left (fun acc (_,is_optional) -> if is_optional then acc + 1 else acc) 0 elist
- let rec fewer_optionals acc compatible = match acc, compatible with
- | _, [] -> acc
- | [], c :: comp -> fewer_optionals [c] comp
- | (elist_acc, _, _) :: _, ((elist, _, _) as cur) :: comp ->
- let acc_opt = count_optionals elist_acc in
- let comp_opt = count_optionals elist in
- if acc_opt = comp_opt then
- fewer_optionals (cur :: acc) comp
- else if acc_opt < comp_opt then
- fewer_optionals acc comp
- else
- fewer_optionals [cur] comp
- let reduce_compatible compatible = match fewer_optionals [] (rm_duplicates [] compatible) with
- | [] -> []
- | [v] -> [v]
- | compatible ->
- (* convert compatible into ( rate * compatible_type ) list *)
- let rec mk_rate acc elist args = match elist, args with
- | [], [] -> acc
- | (_,true) :: elist, _ :: args -> mk_rate acc elist args
- | (e,false) :: elist, (n,o,t) :: args ->
- (* if the argument is an implicit cast, we need to start with a penalty *)
- (* The penalty should be higher than any other implicit cast - other than Dynamic *)
- (* since Dynamic has a penalty of max_int, we'll impose max_int - 1 to it *)
- (match e.eexpr with
- | TMeta( (Meta.ImplicitCast,_,_), _) ->
- mk_rate ((max_int - 1, 0) :: acc) elist args
- | _ ->
- mk_rate (rate_conv 0 t e.etype :: acc) elist args)
- | _ -> assert false
- in
- let rated = ref [] in
- List.iter (function
- | (elist,TFun(args,ret),d) -> (try
- rated := ( (elist,TFun(args,ret),d), mk_rate [] elist args ) :: !rated
- with | Not_found -> ())
- | _ -> assert false
- ) compatible;
- let rec loop best rem = match best, rem with
- | _, [] -> best
- | [], r1 :: rem -> loop [r1] rem
- | (bover, bargs) :: b1, (rover, rargs) :: rem ->
- if is_best bargs rargs then
- loop best rem
- else if is_best rargs bargs then
- loop (loop b1 [rover,rargs]) rem
- else (* equally specific *)
- loop ( (rover,rargs) :: best ) rem
- in
- let r = loop [] !rated in
- List.map fst r
- end;;
- module UnificationCallback = struct
- let tf_stack = ref []
- let check_call_params f el tl =
- let rec loop acc el tl = match el,tl with
- | e :: el, (n,_,t) :: tl ->
- loop ((f e t) :: acc) el tl
- | [], [] ->
- acc
- | [],_ ->
- acc
- | e :: el, [] ->
- loop (e :: acc) el []
- in
- List.rev (loop [] el tl)
- let check_call f el t = match follow t with
- | TFun(args,_) ->
- check_call_params f el args
- | _ ->
- List.map (fun e -> f e t_dynamic) el
- let rec run ff e =
- let f e t =
- if not (type_iseq e.etype t) then
- ff e t
- else
- e
- in
- let check e = match e.eexpr with
- | TBinop((OpAssign | OpAssignOp _),e1,e2) ->
- assert false; (* this trigger #4347, to be fixed before enabling
- let e2 = f e2 e1.etype in
- {e with eexpr = TBinop(op,e1,e2)} *)
- | TVar(v,Some ev) ->
- let eo = Some (f ev v.v_type) in
- { e with eexpr = TVar(v,eo) }
- | TCall(e1,el) ->
- let el = check_call f el e1.etype in
- {e with eexpr = TCall(e1,el)}
- | TNew(c,tl,el) ->
- begin try
- let tcf,_ = get_constructor (fun cf -> apply_params c.cl_params tl cf.cf_type) c in
- let el = check_call f el tcf in
- {e with eexpr = TNew(c,tl,el)}
- with Not_found ->
- e
- end
- | TArrayDecl el ->
- begin match follow e.etype with
- | TInst({cl_path=[],"Array"},[t]) -> {e with eexpr = TArrayDecl(List.map (fun e -> f e t) el)}
- | _ -> e
- end
- | TObjectDecl fl ->
- begin match follow e.etype with
- | TAnon an ->
- let fl = List.map (fun (n,e) ->
- let e = try
- let t = (PMap.find n an.a_fields).cf_type in
- f e t
- with Not_found ->
- e
- in
- n,e
- ) fl in
- { e with eexpr = TObjectDecl fl }
- | _ -> e
- end
- | TReturn (Some e1) ->
- begin match !tf_stack with
- | tf :: _ -> { e with eexpr = TReturn (Some (f e1 tf.tf_type))}
- | _ -> e
- end
- | _ ->
- e
- in
- match e.eexpr with
- | TFunction tf ->
- tf_stack := tf :: !tf_stack;
- let etf = {e with eexpr = TFunction({tf with tf_expr = run f tf.tf_expr})} in
- tf_stack := List.tl !tf_stack;
- etf
- | _ ->
- check (Type.map_expr (run ff) e)
- end;;
- module DeprecationCheck = struct
- let curclass = ref null_class
- let warned_positions = Hashtbl.create 0
- let print_deprecation_message com meta s p_usage =
- let s = match meta with
- | _,[EConst(String s),_],_ -> s
- | _ -> Printf.sprintf "Usage of this %s is deprecated" s
- in
- if not (Hashtbl.mem warned_positions p_usage) then begin
- Hashtbl.replace warned_positions p_usage true;
- com.warning s p_usage;
- end
- let check_meta com meta s p_usage =
- try
- print_deprecation_message com (Meta.get Meta.Deprecated meta) s p_usage;
- with Not_found ->
- ()
- let check_cf com cf p = check_meta com cf.cf_meta "field" p
- let check_class com c p = if c != !curclass then check_meta com c.cl_meta "class" p
- let check_enum com en p = check_meta com en.e_meta "enum" p
- let check_ef com ef p = check_meta com ef.ef_meta "enum field" p
- let check_typedef com t p = check_meta com t.t_meta "typedef" p
- let check_module_type com mt p = match mt with
- | TClassDecl c -> check_class com c p
- | TEnumDecl en -> check_enum com en p
- | _ -> ()
- let run com =
- let rec expr e = match e.eexpr with
- | TField(e1,fa) ->
- expr e1;
- begin match fa with
- | FStatic(c,cf) | FInstance(c,_,cf) ->
- check_class com c e.epos;
- check_cf com cf e.epos
- | FAnon cf ->
- check_cf com cf e.epos
- | FClosure(co,cf) ->
- (match co with None -> () | Some (c,_) -> check_class com c e.epos);
- check_cf com cf e.epos
- | FEnum(en,ef) ->
- check_enum com en e.epos;
- check_ef com ef e.epos;
- | _ ->
- ()
- end
- | TNew(c,_,el) ->
- List.iter expr el;
- check_class com c e.epos;
- (match c.cl_constructor with None -> () | Some cf -> check_cf com cf e.epos)
- | TTypeExpr(mt) | TCast(_,Some mt) ->
- check_module_type com mt e.epos
- | TMeta((Meta.Deprecated,_,_) as meta,e1) ->
- print_deprecation_message com meta "field" e1.epos;
- expr e1;
- | _ ->
- Type.iter expr e
- in
- List.iter (fun t -> match t with
- | TClassDecl c ->
- curclass := c;
- let field cf = match cf.cf_expr with None -> () | Some e -> expr e in
- (match c.cl_constructor with None -> () | Some cf -> field cf);
- (match c.cl_init with None -> () | Some e -> expr e);
- List.iter field c.cl_ordered_statics;
- List.iter field c.cl_ordered_fields;
- | _ ->
- ()
- ) com.types
- end
- let interpolate_code com code tl f_string f_expr p =
- let exprs = Array.of_list tl in
- let i = ref 0 in
- let err msg =
- let pos = { p with pmin = p.pmin + !i } in
- com.error msg pos
- in
- let regex = Str.regexp "[{}]" in
- let rec loop m = match m with
- | [] ->
- ()
- | Str.Text txt :: tl ->
- i := !i + String.length txt;
- f_string txt;
- loop tl
- | Str.Delim a :: Str.Delim b :: tl when a = b ->
- i := !i + 2;
- f_string a;
- loop tl
- | Str.Delim "{" :: Str.Text n :: Str.Delim "}" :: tl ->
- (try
- let expr = Array.get exprs (int_of_string n) in
- f_expr expr;
- i := !i + 2 + String.length n;
- loop tl
- with
- | Failure "int_of_string" ->
- err ("Index expected. Got " ^ n)
- | Invalid_argument _ ->
- err ("Out-of-bounds special parameter: " ^ n))
- | Str.Delim x :: _ ->
- err ("Unexpected " ^ x)
- in
- loop (Str.full_split regex code)
- let map_source_header com f =
- match Common.defined_value_safe com Define.SourceHeader with
- | "" -> ()
- | s -> f s
- (* Collection of functions that return expressions *)
- module ExprBuilder = struct
- let make_static_this c p =
- let ta = TAnon { a_fields = c.cl_statics; a_status = ref (Statics c) } in
- mk (TTypeExpr (TClassDecl c)) ta p
- let make_int com i p =
- mk (TConst (TInt (Int32.of_int i))) com.basic.tint p
- let make_float com f p =
- mk (TConst (TFloat f)) com.basic.tfloat p
- let make_null t p =
- mk (TConst TNull) t p
- let make_local v p =
- mk (TLocal v) v.v_type p
- let make_const_texpr com ct p = match ct with
- | TString s -> mk (TConst (TString s)) com.basic.tstring p
- | TInt i -> mk (TConst (TInt i)) com.basic.tint p
- | TFloat f -> mk (TConst (TFloat f)) com.basic.tfloat p
- | TBool b -> mk (TConst (TBool b)) com.basic.tbool p
- | TNull -> mk (TConst TNull) (com.basic.tnull (mk_mono())) p
- | _ -> error "Unsupported constant" p
- end
- (* Static extensions for classes *)
- module ExtClass = struct
- let add_cl_init c e = match c.cl_init with
- | None -> c.cl_init <- Some e
- | Some e' -> c.cl_init <- Some (concat e' e)
- let add_static_init c cf e p =
- let ethis = ExprBuilder.make_static_this c p in
- let ef1 = mk (TField(ethis,FStatic(c,cf))) cf.cf_type p in
- let e_assign = mk (TBinop(OpAssign,ef1,e)) e.etype p in
- add_cl_init c e_assign
- end
|