Selaa lähdekoodia

Spring clean 2018 (#6974)

* [typer] organize some things

* [typer] organize even more things

* [typer] lose unify_min's context

* [typer] factor out display handling

* [typer] factor out type_expr cases

* restore "package" order
Simon Krajewski 7 vuotta sitten
vanhempi
commit
4669a2754d

+ 1 - 0
Makefile

@@ -28,6 +28,7 @@ STATICLINK?=0
 
 # Configuration
 
+# Modules in these directories should only depend on modules that are in directories to the left
 HAXE_DIRECTORIES=core syntax context codegen codegen/gencommon generators optimization filters macro macro/eval typing compiler
 EXTLIB_LIBS=extlib-leftovers extc neko javalib swflib ttflib ilib objsize pcre ziplib
 OCAML_LIBS=unix str threads dynlink

+ 3 - 3
src/compiler/main.ml

@@ -430,7 +430,7 @@ and process_args arg_spec =
 		(* official argument names *)
 		(List.map (fun (arg) -> (arg, spec, doc)) ok) @
 		(* deprecated argument names *)
-		let dep_msg arg = (Printf.sprintf "WARNING: %s is deprecated" arg) ^ (if List.length ok > 0 then (Printf.sprintf ". Use %s instead" (String.concat "/" ok)) else "") in
+		(* let dep_msg arg = (Printf.sprintf "WARNING: %s is deprecated" arg) ^ (if List.length ok > 0 then (Printf.sprintf ". Use %s instead" (String.concat "/" ok)) else "") in *)
 		(* For now, these warnings are a noop. Can replace this function to
 		enable error output: *)
 		(* let dep_fun = prerr_endline (dep_msg arg) in *)
@@ -813,7 +813,7 @@ try
 		let tctx = Typer.create com in
 		List.iter (MacroContext.call_init_macro tctx) (List.rev !config_macros);
 		List.iter (fun cpath -> ignore(tctx.Typecore.g.Typecore.do_load_module tctx cpath null_pos)) (List.rev !classes);
-		Typer.finalize tctx;
+		Finalization.finalize tctx;
 		t();
 		if not ctx.com.display.dms_display && ctx.has_error then raise Abort;
 		if ctx.com.display.dms_exit_during_typing then begin
@@ -821,7 +821,7 @@ try
 			failwith "No completion point was found";
 		end;
 		let t = Timer.timer ["filters"] in
-		let main, types, modules = Typer.generate tctx in
+		let main, types, modules = Finalization.generate tctx in
 		com.main <- main;
 		com.types <- types;
 		com.modules <- modules;

+ 1 - 1
src/compiler/server.ml

@@ -491,7 +491,7 @@ let rec wait_loop process_params verbose accept =
 				Hashtbl.clear changed_directories;
 				Common.display_default := DMNone;
 				Parser.resume_display := null_pos;
-				Typeload.return_partial_type := false;
+				return_partial_type := false;
 				measure_times := false;
 				close_times();
 				stats.s_files_parsed := 0;

+ 286 - 0
src/context/abstractCast.ml

@@ -0,0 +1,286 @@
+open Globals
+open Common
+open Ast
+open Type
+open Typecore
+open Error
+
+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) ->
+			Abstract.find_to_from find a1 tl1 a2 tl2 tleft eright.etype
+		| 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 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 _ -> 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 ->
+				let rec loop f e = match fst e with
+					| EConst(Ident s) ->
+						Hashtbl.replace relevant s f
+					| EMeta((Meta.Custom ":followWithAbstracts",_,_),e1) ->
+						loop Abstract.follow_with_abstracts e1;
+					| _ ->
+						error "Type parameter expected" (pos e)
+				in
+				loop (fun t -> t) e
+			) el;
+			let tl = List.map2 (fun (n,_) t ->
+				try
+					(Hashtbl.find relevant n) t
+				with Not_found ->
+					if not (has_mono t) then t
+					else t_dynamic
+			) a.a_params pl in
+			if com.platform = Globals.Js && a.a_path = (["haxe";"ds"],"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) ->
+			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
+				| _ ->
+					assert false
+			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(_,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(_,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

+ 1 - 1
src/context/display.ml

@@ -456,7 +456,7 @@ module Diagnostics = struct
 				()
 			| TFunction tf ->
 				loop false tf.tf_expr
-			| TCall({eexpr = TField(e1,fa)},el) when not in_value && OptimizerTexpr.PurityState.is_pure_field_access fa -> compound "call" el e.epos
+			| TCall({eexpr = TField(e1,fa)},el) when not in_value && PurityState.is_pure_field_access fa -> compound "call" el e.epos
 			| TNew _ | TCall _ | TBinop ((Ast.OpAssignOp _ | Ast.OpAssign),_,_) | TUnop ((Ast.Increment | Ast.Decrement),_,_)
 			| TReturn _ | TBreak | TContinue | TThrow _ | TCast (_,Some _)
 			| TIf _ | TTry _ | TSwitch _ | TWhile _ | TFor _ ->

+ 2 - 2
src/context/displayFields.ml

@@ -45,9 +45,9 @@ let collect ctx e_ast e with_type p =
 	let opt_type t =
 		match t with
 		| TLazy f ->
-			Typeload.return_partial_type := true;
+			return_partial_type := true;
 			let t = lazy_type f in
-			Typeload.return_partial_type := false;
+			return_partial_type := false;
 			t
 		| _ ->
 			t

+ 59 - 0
src/context/purityState.ml

@@ -0,0 +1,59 @@
+open Globals
+open Ast
+open Type
+open Error
+
+(*
+	PurityState represents whether or not something has a side-effect. Unless otherwise stated
+	by using `@:pure` (equivalent to `@:pure(true)`) or `@:pure(false)`, fields are originally
+	supposed to be "maybe pure". Once all types and fields are known, this is refined by
+	AnalyzerTexpr.Purity.
+
+	There's a special case for fields that override a parent class field or implement an
+	interface field: If the overridden/implemented field is explicitly marked as pure,
+	the type loader marks the overriding/implementing as "expected pure". If during purity
+	inference this assumption does not hold, an error is shown.
+*)
+type t =
+	| Pure
+	| Impure
+	| MaybePure
+	| ExpectPure of pos
+
+let get_purity_from_meta meta =
+	try
+		begin match Meta.get Meta.Pure meta with
+		| (_,[EConst(Ident s),p],_) ->
+			begin match s with
+			| "true" -> Pure
+			| "false" -> Impure
+			| "expect" -> ExpectPure p
+			| _ -> error ("Unsupported purity value " ^ s ^ ", expected true or false") p
+			end
+		| (_,[],_) ->
+			Pure
+		| (_,_,p) ->
+			error "Unsupported purity value" p
+		end
+	with Not_found ->
+		MaybePure
+
+let get_purity c cf = match get_purity_from_meta cf.cf_meta with
+	| Pure -> Pure
+	| Impure -> Impure
+	| ExpectPure p -> ExpectPure p
+	| _ -> get_purity_from_meta c.cl_meta
+
+let is_pure c cf = get_purity c cf = Pure
+
+let is_pure_field_access fa = match fa with
+	| FInstance(c,_,cf) | FClosure(Some(c,_),cf) | FStatic(c,cf) -> is_pure c cf
+	| FAnon cf | FClosure(None,cf) -> (get_purity_from_meta cf.cf_meta = Pure)
+	| FEnum _ -> true
+	| FDynamic _ -> false
+
+let to_string = function
+	| Pure -> "pure"
+	| Impure -> "impure"
+	| MaybePure -> "maybe"
+	| ExpectPure _ -> "expect"

+ 1 - 293
src/context/typecore.ml

@@ -133,13 +133,9 @@ exception WithTypeError of error_msg * pos
 
 let make_call_ref : (typer -> texpr -> texpr list -> t -> pos -> texpr) ref = ref (fun _ _ _ _ _ -> assert false)
 let type_expr_ref : (typer -> expr -> with_type -> texpr) ref = ref (fun _ _ _ -> assert false)
-let type_module_type_ref : (typer -> module_type -> t list option -> pos -> texpr) ref = ref (fun _ _ _ _ -> assert false)
+let type_block_ref : (typer -> expr list -> with_type -> pos -> texpr) ref = ref (fun _ _ _ _ -> assert false)
 let unify_min_ref : (typer -> texpr list -> t) ref = ref (fun _ _ -> assert false)
-let match_expr_ref : (typer -> expr -> (expr list * expr option * expr option * pos) list -> (expr option * pos) option -> with_type -> pos -> texpr) ref = ref (fun _ _ _ _ _ _ -> assert false)
 let get_pattern_locals_ref : (typer -> expr -> Type.t -> (string, tvar * pos) PMap.t) ref = ref (fun _ _ _ -> assert false)
-let get_constructor_ref : (typer -> tclass -> t list -> pos -> (t * tclass_field)) ref = ref (fun _ _ _ _ -> assert false)
-let cast_or_unify_ref : (typer -> t -> texpr -> pos -> texpr) ref = ref (fun _ _ _ _ -> assert false)
-let find_array_access_raise_ref : (typer -> tabstract -> tparams -> texpr -> texpr option -> pos -> (tclass_field * t * t * texpr * texpr option)) ref = ref (fun _ _ _ _ _ _ -> assert false)
 let analyzer_run_on_expr_ref : (Common.context -> texpr -> texpr) ref = ref (fun _ _ -> assert false)
 let merge_core_doc_ref : (typer -> tclass -> unit) ref = ref (fun _ _ -> assert false)
 
@@ -161,8 +157,6 @@ let type_expr ctx e with_type = (!type_expr_ref) ctx e with_type
 
 let unify_min ctx el = (!unify_min_ref) ctx el
 
-let match_expr ctx e cases def with_type p = !match_expr_ref ctx e cases def with_type p
-
 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
@@ -417,292 +411,6 @@ let prepare_using_field cf = match follow cf.cf_type with
 		{cf with cf_overloads = loop [] cf.cf_overloads; cf_type = TFun(args,ret)}
 	| _ -> cf
 
-(* -------------------------------------------------------------------------- *)
-(* 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) ->
-				Abstract.find_to_from find a1 tl1 a2 tl2 tleft eright.etype
-			| 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 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 _ -> 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 ->
-					let rec loop f e = match fst e with
-						| EConst(Ident s) ->
-							Hashtbl.replace relevant s f
-						| EMeta((Meta.Custom ":followWithAbstracts",_,_),e1) ->
-							loop Abstract.follow_with_abstracts e1;
-						| _ ->
-							error "Type parameter expected" (pos e)
-					in
-					loop (fun t -> t) e
-				) el;
-				let tl = List.map2 (fun (n,_) t ->
-					try
-						(Hashtbl.find relevant n) t
-					with Not_found ->
-						if not (has_mono t) then t
-						else t_dynamic
-				) a.a_params pl in
-				if com.platform = Globals.Js && a.a_path = (["haxe";"ds"],"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) ->
-				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
-					| _ ->
-						assert false
-				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(_,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(_,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
-
 (* -------------- debug functions to activate when debugging typer passes ------------------------------- *)
 (*/*
 

+ 16 - 1
src/core/error.ml

@@ -91,4 +91,19 @@ and s_call_error = function
 
 let error msg p = raise (Error (Custom msg,p))
 
-let raise_error err p = raise (Error(err,p))
+let raise_error err p = raise (Error(err,p))
+
+let error_require r p =
+	if r = "" then
+		error "This field is not available with the current compilation flags" p
+	else
+	let r = if r = "sys" then
+		"a system platform (php,neko,cpp,etc.)"
+	else try
+		if String.sub r 0 5 <> "flash" then raise Exit;
+		let _, v = ExtString.String.replace (String.sub r 5 (String.length r - 5)) "_" "." in
+		"flash version " ^ v ^ " (use -swf-version " ^ v ^ ")"
+	with _ ->
+		"'" ^ r ^ "' to be enabled"
+	in
+	error ("Accessing this field requires " ^ r) p

+ 2 - 0
src/core/globals.ml

@@ -28,6 +28,8 @@ let version_revision = (version mod 100)
 
 let macro_platform = ref Neko
 
+let return_partial_type = ref false
+
 let is_windows = Sys.os_type = "Win32" || Sys.os_type = "Cygwin"
 
 let platforms = [

+ 2 - 2
src/optimization/dce.ml

@@ -209,7 +209,7 @@ and mark_t dce p t =
 			List.iter (mark_t dce p) pl
 		| TAbstract(a,pl) when Meta.has Meta.MultiType a.a_meta ->
 			begin try
-				mark_t dce p (snd (Typecore.AbstractCast.find_multitype_specialization dce.com a pl p))
+				mark_t dce p (snd (AbstractCast.find_multitype_specialization dce.com a pl p))
 			with Error.Error _ ->
 				()
 			end
@@ -352,7 +352,7 @@ and mark_directly_used_t dce p t =
 		List.iter (mark_directly_used_t dce p) pl
 	| TAbstract(a,pl) when Meta.has Meta.MultiType a.a_meta ->
 		begin try (* this is copy-pasted from mark_t *)
-			mark_directly_used_t dce p (snd (Typecore.AbstractCast.find_multitype_specialization dce.com a pl p))
+			mark_directly_used_t dce p (snd (AbstractCast.find_multitype_specialization dce.com a pl p))
 		with Error.Error _ ->
 			()
 		end

+ 0 - 213
src/optimization/optimizer.ml

@@ -686,219 +686,6 @@ and type_inline_ctor ctx c cf tf ethis el po =
 	in
 	type_inline ctx cf tf ethis el ctx.t.tvoid None po true
 
-
-(* ---------------------------------------------------------------------- *)
-(* LOOPS *)
-
-let rec optimize_for_loop ctx (i,pi) e1 e2 p =
-	let t_void = ctx.t.tvoid in
-	let t_int = ctx.t.tint in
-	let lblock el = Some (mk (TBlock el) t_void p) in
-	let mk_field e n =
-		TField (e,try quick_field e.etype n with Not_found -> assert false)
-	in
-	let gen_int_iter pt f_get f_length =
-		let i = add_local ctx i pt pi in
-		let index = gen_local ctx t_int pi in
-		index.v_meta <- (Meta.ForLoopVariable,[],null_pos) :: index.v_meta;
-		let arr, avars = (match e1.eexpr with
-			| TLocal _ -> e1, None
-			| _ ->
-				let atmp = gen_local ctx e1.etype e1.epos in
-				mk (TLocal atmp) e1.etype e1.epos, (Some (atmp,Some e1))
-		) in
-		let iexpr = mk (TLocal index) t_int p in
-		let e2 = type_expr ctx e2 NoValue in
-		let aget = mk (TVar (i,Some (f_get arr iexpr pt p))) t_void pi in
-		let incr = mk (TUnop (Increment,Prefix,iexpr)) t_int p in
-		let block = match e2.eexpr with
-			| TBlock el -> mk (TBlock (aget :: incr :: el)) t_void e2.epos
-			| _ -> mk (TBlock [aget;incr;e2]) t_void p
-		in
-		let ivar = Some (mk (TConst (TInt 0l)) t_int p) in
-		let elength = f_length arr p in
-		let el = [mk (TWhile (
-				mk (TBinop (OpLt, iexpr, elength)) ctx.t.tbool p,
-				block,
-				NormalWhile
-			)) t_void p;
-		] in
-		let el = match avars with None -> el | Some (v,eo) -> (mk (TVar (v,eo)) t_void p) :: el in
-		let el = (mk (TVar (index,ivar)) t_void p) :: el in
-		lblock el
-	in
-	let get_next_array_element arr iexpr pt p =
-		(mk (TArray (arr,iexpr)) pt p)
-	in
-	let get_array_length arr p =
-		mk (mk_field arr "length") ctx.com.basic.tint p
-	in
-	match e1.eexpr, follow e1.etype with
-	| TNew ({ cl_path = ([],"IntIterator") },[],[i1;i2]) , _ ->
-		let max = (match i1.eexpr , i2.eexpr with
-			| TConst (TInt a), TConst (TInt b) when Int32.compare b a < 0 -> error "Range operator can't iterate backwards" p
-			| _, TConst _ -> None
-			| _ -> Some (gen_local ctx t_int e1.epos)
-		) in
-		let tmp = gen_local ctx t_int pi in
-		tmp.v_meta <- (Meta.ForLoopVariable,[],null_pos) :: tmp.v_meta;
-		let i = add_local ctx i t_int pi in
-		let rec check e =
-			match e.eexpr with
-			| TBinop (OpAssign,{ eexpr = TLocal l },_)
-			| TBinop (OpAssignOp _,{ eexpr = TLocal l },_)
-			| TUnop (Increment,_,{ eexpr = TLocal l })
-			| TUnop (Decrement,_,{ eexpr = TLocal l })  when l == i ->
-				error "Loop variable cannot be modified" e.epos
-			| _ ->
-				Type.iter check e
-		in
-		let e2 = type_expr ctx e2 NoValue in
-		check e2;
-		let etmp = mk (TLocal tmp) t_int p in
-		let incr = mk (TUnop (Increment,Postfix,etmp)) t_int p in
-		let init = mk (TVar (i,Some incr)) t_void pi in
-		let block = match e2.eexpr with
-			| TBlock el -> mk (TBlock (init :: el)) t_void e2.epos
-			| _ -> mk (TBlock [init;e2]) t_void p
-		in
-		(*
-			force locals to be of Int type (to prevent Int/UInt issues)
-		*)
-		let i2 = match follow i2.etype with
-			| TAbstract ({ a_path = ([],"Int") }, []) -> i2
-			| _ -> { i2 with eexpr = TCast(i2, None); etype = t_int }
-		in
-		(match max with
-		| None ->
-			lblock [
-				mk (TVar (tmp,Some i1)) t_void p;
-				mk (TWhile (
-					mk (TBinop (OpLt, etmp, i2)) ctx.t.tbool p,
-					block,
-					NormalWhile
-				)) t_void p;
-			]
-		| Some max ->
-			lblock [
-				mk (TVar (tmp,Some i1)) t_void p;
-				mk (TVar (max,Some i2)) t_void p;
-				mk (TWhile (
-					mk (TBinop (OpLt, etmp, mk (TLocal max) t_int p)) ctx.t.tbool p,
-					block,
-					NormalWhile
-				)) t_void p;
-			])
-	| TArrayDecl el, TInst({ cl_path = [],"Array" },[pt]) ->
-		begin try
-			let num_expr = ref 0 in
-			let rec loop e = match fst e with
-				| EContinue | EBreak ->
-					raise Exit
-				| _ ->
-					incr num_expr;
-					Ast.map_expr loop e
-			in
-			ignore(loop e2);
-			let cost = (List.length el) * !num_expr in
-			let max_cost = try
-				int_of_string (Common.defined_value ctx.com Define.LoopUnrollMaxCost)
-			with Not_found ->
-				250
-			in
-			if cost > max_cost then raise Exit;
-			let el = List.map (fun e ->
-				let v = add_local ctx i pt p in
-				let ev = mk (TVar(v, None)) ctx.t.tvoid p in
-				let typed_e2 = type_expr ctx e2 NoValue in
-				let eloc = mk (TLocal v) v.v_type p in
-				let e_assign = mk (TBinop(OpAssign,eloc,e)) e.etype e.epos in
-				concat ev (concat e_assign typed_e2)
-			) el in
-			Some (mk (TBlock el) ctx.t.tvoid p)
-		with Exit ->
-			gen_int_iter pt get_next_array_element get_array_length
-		end
-	| _ , TInst({ cl_path = [],"Array" },[pt])
-	| _ , TInst({ cl_path = ["flash"],"Vector" },[pt]) ->
-		gen_int_iter pt get_next_array_element get_array_length
-	| _ , TInst({ cl_array_access = Some pt } as c,pl) when (try match follow (PMap.find "length" c.cl_fields).cf_type with TAbstract ({ a_path = [],"Int" },[]) -> true | _ -> false with Not_found -> false) && not (PMap.mem "iterator" c.cl_fields) ->
-		gen_int_iter (apply_params c.cl_params pl pt) get_next_array_element get_array_length
-	| _, TAbstract({a_impl = Some c} as a,tl) ->
-		begin try
-			let cf_length = PMap.find "get_length" c.cl_statics in
-			let get_length e p =
-				make_static_call ctx c cf_length (apply_params a.a_params tl) [e] ctx.com.basic.tint p
-			in
-			begin match follow cf_length.cf_type with
-				| TFun(_,tr) ->
-					begin match follow tr with
-						| TAbstract({a_path = [],"Int"},_) -> ()
-						| _ -> raise Not_found
-					end
-				| _ ->
-					raise Not_found
-			end;
-			begin try
-				(* first try: do we have an @:arrayAccess getter field? *)
-				let todo = mk (TConst TNull) ctx.t.tint p in
-				let cf,_,r,_,_ = (!find_array_access_raise_ref) ctx a tl todo None p in
-				let get_next e_base e_index t p =
-					make_static_call ctx c cf (apply_params a.a_params tl) [e_base;e_index] r p
-				in
-				gen_int_iter r get_next get_length
-			with Not_found ->
-				(* second try: do we have @:arrayAccess on the abstract itself? *)
-				if not (Meta.has Meta.ArrayAccess a.a_meta) then raise Not_found;
-				(* let's allow this only for core-type abstracts *)
-				if not (Meta.has Meta.CoreType a.a_meta) then raise Not_found;
-				(* in which case we assume that a singular type parameter is the element type *)
-				let t = match tl with [t] -> t | _ -> raise Not_found in
-				gen_int_iter t get_next_array_element get_length
-		end with Not_found ->
-			None
-		end
-	| _ , TInst ({ cl_kind = KGenericInstance ({ cl_path = ["haxe";"ds"],"GenericStack" },[t]) } as c,[]) ->
-		let tcell = (try (PMap.find "head" c.cl_fields).cf_type with Not_found -> assert false) in
-		let i = add_local ctx i t p in
-		let cell = gen_local ctx tcell p in
-		let cexpr = mk (TLocal cell) tcell p in
-		let e2 = type_expr ctx e2 NoValue in
-		let evar = mk (TVar (i,Some (mk (mk_field cexpr "elt") t p))) t_void pi in
-		let enext = mk (TBinop (OpAssign,cexpr,mk (mk_field cexpr "next") tcell p)) tcell p in
-		let block = match e2.eexpr with
-			| TBlock el -> mk (TBlock (evar :: enext :: el)) t_void e2.epos
-			| _ -> mk (TBlock [evar;enext;e2]) t_void p
-		in
-		lblock [
-			mk (TVar (cell,Some (mk (mk_field e1 "head") tcell p))) t_void p;
-			mk (TWhile (
-				mk (TBinop (OpNotEq, cexpr, mk (TConst TNull) tcell p)) ctx.t.tbool p,
-				block,
-				NormalWhile
-			)) t_void p
-		]
-	| _ ->
-		None
-
-let optimize_for_loop_iterator ctx v e1 e2 p =
-	let c,tl = (match follow e1.etype with TInst (c,pl) -> c,pl | _ -> raise Exit) in
-	let _, _, fhasnext = (try raw_class_field (fun cf -> apply_params c.cl_params tl cf.cf_type) c tl "hasNext" with Not_found -> raise Exit) in
-	if fhasnext.cf_kind <> Method MethInline then raise Exit;
-	let tmp = gen_local ctx e1.etype e1.epos in
-	let eit = mk (TLocal tmp) e1.etype p in
-	let ehasnext = make_call ctx (mk (TField (eit,FInstance (c, tl, fhasnext))) (TFun([],ctx.t.tbool)) p) [] ctx.t.tbool p in
-	let enext = mk (TVar (v,Some (make_call ctx (mk (TField (eit,quick_field_dynamic eit.etype "next")) (TFun ([],v.v_type)) p) [] v.v_type p))) ctx.t.tvoid p in
-	let eblock = (match e2.eexpr with
-		| TBlock el -> { e2 with eexpr = TBlock (enext :: el) }
-		| _ -> mk (TBlock [enext;e2]) ctx.t.tvoid p
-	) in
-	mk (TBlock [
-		mk (TVar (tmp,Some e1)) ctx.t.tvoid p;
-		mk (TWhile (ehasnext,eblock,NormalWhile)) ctx.t.tvoid p
-	]) ctx.t.tvoid p
-
-
 (* ---------------------------------------------------------------------- *)
 (* SANITIZE *)
 

+ 0 - 57
src/optimization/optimizerTexpr.ml

@@ -3,63 +3,6 @@ open Type
 open Error
 open Globals
 
-(*
-	PurityState represents whether or not something has a side-effect. Unless otherwise stated
-	by using `@:pure` (equivalent to `@:pure(true)`) or `@:pure(false)`, fields are originally
-	supposed to be "maybe pure". Once all types and fields are known, this is refined by
-	AnalyzerTexpr.Purity.
-
-	There's a special case for fields that override a parent class field or implement an
-	interface field: If the overridden/implemented field is explicitly marked as pure,
-	the type loader marks the overriding/implementing as "expected pure". If during purity
-	inference this assumption does not hold, an error is shown.
-*)
-module PurityState = struct
-	type t =
-		| Pure
-		| Impure
-		| MaybePure
-		| ExpectPure of pos
-
-	let get_purity_from_meta meta =
-		try
-			begin match Meta.get Meta.Pure meta with
-			| (_,[EConst(Ident s),p],_) ->
-				begin match s with
-				| "true" -> Pure
-				| "false" -> Impure
-				| "expect" -> ExpectPure p
-				| _ -> error ("Unsupported purity value " ^ s ^ ", expected true or false") p
-				end
-			| (_,[],_) ->
-				Pure
-			| (_,_,p) ->
-				error "Unsupported purity value" p
-			end
-		with Not_found ->
-			MaybePure
-
-	let get_purity c cf = match get_purity_from_meta cf.cf_meta with
-		| Pure -> Pure
-		| Impure -> Impure
-		| ExpectPure p -> ExpectPure p
-		| _ -> get_purity_from_meta c.cl_meta
-
-	let is_pure c cf = get_purity c cf = Pure
-
-	let is_pure_field_access fa = match fa with
-		| FInstance(c,_,cf) | FClosure(Some(c,_),cf) | FStatic(c,cf) -> is_pure c cf
-		| FAnon cf | FClosure(None,cf) -> (get_purity_from_meta cf.cf_meta = Pure)
-		| FEnum _ -> true
-		| FDynamic _ -> false
-
-	let to_string = function
-		| Pure -> "pure"
-		| Impure -> "impure"
-		| MaybePure -> "maybe"
-		| ExpectPure _ -> "expect"
-end
-
 (* tells if an expression causes side effects. This does not account for potential null accesses (fields/arrays/ops) *)
 let has_side_effect e =
 	let rec loop e =

+ 708 - 0
src/typing/calls.ml

@@ -0,0 +1,708 @@
+open Globals
+open Common.DisplayMode
+open Common
+open Ast
+open Type
+open Typecore
+open TyperBase
+open Fields
+open Error
+
+let is_forced_inline c cf =
+	match c with
+	| Some { cl_extern = true } -> true
+	| Some { cl_kind = KAbstractImpl _ } -> true
+	| _ when Meta.has Meta.Extern cf.cf_meta -> true
+	| _ -> false
+
+let make_call ctx e params t p =
+	try
+		let ethis,cl,f = match e.eexpr with
+			| TField (ethis,fa) ->
+				let co,cf = match fa with
+					| FInstance(c,_,cf) | FStatic(c,cf) -> Some c,cf
+					| FAnon cf -> None,cf
+					| _ -> raise Exit
+				in
+				ethis,co,cf
+			| _ ->
+				raise Exit
+		in
+		if f.cf_kind <> Method MethInline then raise Exit;
+		let config = match cl with
+			| Some ({cl_kind = KAbstractImpl _}) when Meta.has Meta.Impl f.cf_meta ->
+				let t = if f.cf_name = "_new" then
+					t
+				else if params = [] then
+					error "Invalid abstract implementation function" f.cf_pos
+				else
+					follow (List.hd params).etype
+				in
+				begin match t with
+					| TAbstract(a,pl) ->
+						let has_params = a.a_params <> [] || f.cf_params <> [] in
+						let monos = List.map (fun _ -> mk_mono()) f.cf_params in
+						let map_type = fun t -> apply_params a.a_params pl (apply_params f.cf_params monos t) in
+						Some (has_params,map_type)
+					| _ ->
+						None
+				end
+			| _ ->
+				None
+		in
+		ignore(follow f.cf_type); (* force evaluation *)
+		let params = List.map (ctx.g.do_optimize ctx) params in
+		let force_inline = is_forced_inline cl f in
+		(match f.cf_expr_unoptimized,f.cf_expr with
+		| Some fd,_
+		| None,Some { eexpr = TFunction fd } ->
+			(match Optimizer.type_inline ctx f fd ethis params t config p force_inline with
+			| None ->
+				if force_inline then error "Inline could not be done" p;
+				raise Exit;
+			| Some e -> e)
+		| _ ->
+			(*
+				we can't inline because there is most likely a loop in the typing.
+				this can be caused by mutually recursive vars/functions, some of them
+				being inlined or not. In that case simply ignore inlining.
+			*)
+			raise Exit)
+	with Exit ->
+		mk (TCall (e,params)) t p
+
+let mk_array_get_call ctx (cf,tf,r,e1,e2o) c ebase p = match cf.cf_expr with
+	| None ->
+		if not (Meta.has Meta.NoExpr cf.cf_meta) then display_error ctx "Recursive array get method" p;
+		mk (TArray(ebase,e1)) r p
+	| Some _ ->
+		let et = type_module_type ctx (TClassDecl c) None p in
+		let ef = mk (TField(et,(FStatic(c,cf)))) tf p in
+		make_call ctx ef [ebase;e1] r p
+
+let mk_array_set_call ctx (cf,tf,r,e1,e2o) c ebase p =
+	let evalue = match e2o with None -> assert false | Some e -> e in
+	match cf.cf_expr with
+		| None ->
+			if not (Meta.has Meta.NoExpr cf.cf_meta) then display_error ctx "Recursive array set method" p;
+			let ea = mk (TArray(ebase,e1)) r p in
+			mk (TBinop(OpAssign,ea,evalue)) r p
+		| Some _ ->
+			let et = type_module_type ctx (TClassDecl c) None p in
+			let ef = mk (TField(et,(FStatic(c,cf)))) tf p in
+			make_call ctx ef [ebase;e1;evalue] r p
+
+let call_to_string ctx ?(resume=false) e =
+	(* Ignore visibility of the toString field. *)
+	ctx.meta <- (Meta.PrivateAccess,[],e.epos) :: ctx.meta;
+	let acc = type_field ~resume ctx e "toString" e.epos MCall in
+	ctx.meta <- List.tl ctx.meta;
+	!build_call_ref ctx acc [] (WithType ctx.t.tstring) e.epos
+
+let rec unify_call_args' ctx el args r callp inline force_inline =
+	let in_call_args = ctx.in_call_args in
+	ctx.in_call_args <- true;
+	let call_error err p =
+		raise (Error (Call_error err,p))
+	in
+	let arg_error ul name opt p =
+		let err = Stack (ul,Custom ("For " ^ (if opt then "optional " else "") ^ "function argument '" ^ name ^ "'")) in
+		call_error (Could_not_unify err) p
+	in
+	let mk_pos_infos t =
+		let infos = mk_infos ctx callp [] in
+		type_expr ctx infos (WithType t)
+	in
+	let rec default_value name t =
+		if is_pos_infos t then
+			mk_pos_infos t
+		else
+			null (ctx.t.tnull t) callp
+	in
+	let skipped = ref [] in
+	let invalid_skips = ref [] in
+	let skip name ul t p =
+		if not ctx.com.config.pf_can_skip_non_nullable_argument && not (is_nullable t) then
+			invalid_skips := name :: !invalid_skips;
+		skipped := (name,ul,p) :: !skipped;
+		default_value name t
+	in
+	(* let force_inline, is_extern = match cf with Some(TInst(c,_),f) -> is_forced_inline (Some c) f, c.cl_extern | _ -> false, false in *)
+	let type_against t e =
+		try
+			let e = type_expr ctx e (WithType t) in
+			AbstractCast.cast_or_unify_raise ctx t e e.epos
+		with Error(l,p) when (match l with Call_error _ | Module_not_found _ -> false | _ -> true) ->
+			raise (WithTypeError (l,p))
+	in
+	let rec loop el args = match el,args with
+		| [],[] ->
+			begin match List.rev !invalid_skips with
+				| [] -> ()
+				| name :: _ -> call_error (Cannot_skip_non_nullable name) callp;
+			end;
+			[]
+		| _,[name,false,t] when (match follow t with TAbstract({a_path = ["haxe";"extern"],"Rest"},_) -> true | _ -> false) ->
+			begin match follow t with
+				| TAbstract({a_path=(["haxe";"extern"],"Rest")},[t]) ->
+					(try List.map (fun e -> type_against t e,false) el with WithTypeError(ul,p) -> arg_error ul name false p)
+				| _ ->
+					assert false
+			end
+		| [],(_,false,_) :: _ ->
+			call_error (Not_enough_arguments args) callp
+		| [],(name,true,t) :: args ->
+			begin match loop [] args with
+				| [] when not (inline && (ctx.g.doinline || force_inline)) && not ctx.com.config.pf_pad_nulls ->
+					if is_pos_infos t then [mk_pos_infos t,true]
+					else []
+				| args ->
+					let e_def = default_value name t in
+					(e_def,true) :: args
+			end
+		| (_,p) :: _, [] ->
+			begin match List.rev !skipped with
+				| [] -> call_error Too_many_arguments p
+				| (s,ul,p) :: _ -> arg_error ul s true p
+			end
+		| e :: el,(name,opt,t) :: args ->
+			begin try
+				let e = type_against t e in
+				(e,opt) :: loop el args
+			with
+				WithTypeError (ul,p)->
+					if opt then
+						let e_def = skip name ul t p in
+						(e_def,true) :: loop (e :: el) args
+					else
+						arg_error ul name false p
+			end
+	in
+	let el = try loop el args with exc -> ctx.in_call_args <- in_call_args; raise exc; in
+	ctx.in_call_args <- in_call_args;
+	el,TFun(args,r)
+
+let unify_call_args ctx el args r p inline force_inline =
+	let el,tf = unify_call_args' ctx el args r p inline force_inline in
+	List.map fst el,tf
+
+let unify_field_call ctx fa el args ret p inline =
+	let map_cf cf0 map cf =
+		let t = map (monomorphs cf.cf_params cf.cf_type) in
+		begin match cf.cf_expr,cf.cf_kind with
+		| None,Method MethInline when not ctx.com.config.pf_overload ->
+			(* This is really awkward and shouldn't be here. We'll keep it for
+			   3.2 in order to not break code that relied on the quirky behavior
+			   in 3.1.3, but it should really be reviewed afterwards.
+			   Related issue: https://github.com/HaxeFoundation/haxe/issues/3846
+			*)
+			cf.cf_expr <- cf0.cf_expr;
+			cf.cf_kind <- cf0.cf_kind;
+		| _ ->
+			()
+		end;
+		t,cf
+	in
+	let expand_overloads map cf =
+		(TFun(args,ret),cf) :: (List.map (map_cf cf map) cf.cf_overloads)
+	in
+	let candidates,co,cf,mk_fa = match fa with
+		| FStatic(c,cf) ->
+			expand_overloads (fun t -> t) cf,Some c,cf,(fun cf -> FStatic(c,cf))
+		| FAnon cf ->
+			expand_overloads (fun t -> t) cf,None,cf,(fun cf -> FAnon cf)
+		| FInstance(c,tl,cf) ->
+			let map = apply_params c.cl_params tl in
+			let cfl = if cf.cf_name = "new" || not (Meta.has Meta.Overload cf.cf_meta && ctx.com.config.pf_overload) then
+				List.map (map_cf cf map) cf.cf_overloads
+			else
+				List.map (fun (t,cf) -> map (monomorphs cf.cf_params t),cf) (Overloads.get_overloads c cf.cf_name)
+			in
+			(TFun(args,ret),cf) :: cfl,Some c,cf,(fun cf -> FInstance(c,tl,cf))
+		| FClosure(co,cf) ->
+			let c = match co with None -> None | Some (c,_) -> Some c in
+			expand_overloads (fun t -> t) cf,c,cf,(fun cf -> match co with None -> FAnon cf | Some (c,tl) -> FInstance(c,tl,cf))
+		| _ ->
+			error "Invalid field call" p
+	in
+	let is_forced_inline = is_forced_inline co cf in
+	let is_overload = Meta.has Meta.Overload cf.cf_meta in
+	let attempt_call t cf = match follow t with
+		| TFun(args,ret) ->
+			let el,tf = unify_call_args' ctx el args ret p inline is_forced_inline in
+			let mk_call ethis p_field =
+				let ef = mk (TField(ethis,mk_fa cf)) t p_field in
+				make_call ctx ef (List.map fst el) ret p
+			in
+			el,tf,mk_call
+		| _ ->
+			assert false
+	in
+	let maybe_raise_unknown_ident cerr p =
+		let rec loop err =
+			match err with
+			| Unknown_ident _ -> error (error_msg err) p
+			| Stack (e1,e2) -> (loop e1; loop e2)
+			| _ -> ()
+		in
+		match cerr with Could_not_unify err -> loop err | _ -> ()
+	in
+	let rec loop candidates = match candidates with
+		| [] -> [],[]
+		| (t,cf) :: candidates ->
+			begin try
+				let candidate = attempt_call t cf in
+				if ctx.com.config.pf_overload && is_overload then begin
+					let candidates,failures = loop candidates in
+					candidate :: candidates,failures
+				end else
+					[candidate],[]
+			with Error ((Call_error cerr as err),p) ->
+				maybe_raise_unknown_ident cerr p;
+				let candidates,failures = loop candidates in
+				candidates,(cf,err,p) :: failures
+			end
+	in
+	let fail_fun () =
+		let tf = TFun(args,ret) in
+		[],tf,(fun ethis p_field ->
+			let e1 = mk (TField(ethis,mk_fa cf)) tf p_field in
+			mk (TCall(e1,[])) ret p)
+	in
+	match candidates with
+	| [t,cf] ->
+		begin try
+			let el,tf,mk_call = attempt_call t cf in
+			List.map fst el,tf,mk_call
+		with Error _ when ctx.com.display.dms_error_policy = EPIgnore ->
+			fail_fun();
+		end
+	| _ ->
+		let candidates,failures = loop candidates in
+		let fail () =
+			let failures = List.map (fun (cf,err,p) -> cf,error_msg err,p) failures in
+			let failures = remove_duplicates (fun (_,msg1,_) (_,msg2,_) -> msg1 <> msg2) failures in
+			begin match failures with
+			| [_,msg,p] ->
+				error msg p
+			| _ ->
+				display_error ctx "Could not find a suitable overload, reasons follow" p;
+				List.iter (fun (cf,msg,p2) ->
+					display_error ctx ("Overload resolution failed for " ^ (s_type (print_context()) cf.cf_type)) p;
+					display_error ctx msg p2;
+				) failures;
+				error "End of overload failure reasons" p
+			end
+		in
+		if is_overload && ctx.com.config.pf_overload then begin match Overloads.Resolution.reduce_compatible candidates with
+			| [] -> fail()
+			| [el,tf,mk_call] -> List.map fst el,tf,mk_call
+			| _ -> error "Ambiguous overload" p
+		end else begin match List.rev candidates with
+			| [] -> fail()
+			| (el,tf,mk_call) :: _ -> List.map fst el,tf,mk_call
+		end
+
+ let type_generic_function ctx (e,fa) el ?(using_param=None) with_type p =
+	let c,tl,cf,stat = match fa with
+		| FInstance(c,tl,cf) -> c,tl,cf,false
+		| FStatic(c,cf) -> c,[],cf,true
+		| _ -> assert false
+	in
+	if cf.cf_params = [] then error "Function has no type parameters and cannot be generic" p;
+	let monos = List.map (fun _ -> mk_mono()) cf.cf_params in
+	let map_monos t = apply_params cf.cf_params monos t in
+	let map t = if stat then map_monos t else apply_params c.cl_params tl (map_monos t) in
+	let t = map cf.cf_type in
+	let args,ret = match t,using_param with
+		| TFun((_,_,ta) :: args,ret),Some e ->
+			let ta = if not (Meta.has Meta.Impl cf.cf_meta) then ta
+			else match follow ta with TAbstract(a,tl) -> Abstract.get_underlying_type a tl | _ -> assert false
+			in
+			(* manually unify first argument *)
+			unify ctx e.etype ta p;
+			args,ret
+		| TFun(args,ret),None -> args,ret
+		| _ ->  error "Invalid field type for generic call" p
+	in
+	begin match with_type with
+		| WithType t -> unify ctx ret t p
+		| _ -> ()
+	end;
+	let el,_ = unify_call_args ctx el args ret p false false in
+	begin try
+		check_constraints ctx cf.cf_name cf.cf_params monos map false p
+	with Unify_error l ->
+		display_error ctx (error_msg (Unify l)) p
+	end;
+	let el = match using_param with None -> el | Some e -> e :: el in
+	(try
+		let gctx = Typeload.make_generic ctx cf.cf_params monos p in
+		let name = cf.cf_name ^ "_" ^ gctx.Typeload.name in
+		let unify_existing_field tcf pcf = try
+			unify_raise ctx tcf t p
+		with Error(Unify _,_) as err ->
+			display_error ctx ("Cannot create field " ^ name ^ " due to type mismatch") p;
+			display_error ctx "Conflicting field was defined here" pcf;
+			raise err
+		in
+		let cf2 = try
+			let cf2 = if stat then
+				let cf2 = PMap.find name c.cl_statics in
+				unify_existing_field cf2.cf_type cf2.cf_pos;
+				cf2
+			else
+				let cf2 = PMap.find name c.cl_fields in
+				unify_existing_field cf2.cf_type cf2.cf_pos;
+				cf2
+			in
+			cf2
+		with Not_found ->
+			let cf2 = mk_field name (map_monos cf.cf_type) cf.cf_pos cf.cf_name_pos in
+			if stat then begin
+				c.cl_statics <- PMap.add name cf2 c.cl_statics;
+				c.cl_ordered_statics <- cf2 :: c.cl_ordered_statics
+			end else begin
+				if List.memq cf c.cl_overrides then c.cl_overrides <- cf2 :: c.cl_overrides;
+				c.cl_fields <- PMap.add name cf2 c.cl_fields;
+				c.cl_ordered_fields <- cf2 :: c.cl_ordered_fields
+			end;
+			ignore(follow cf.cf_type);
+			let rec check e = match e.eexpr with
+				| TNew({cl_kind = KTypeParameter _} as c,_,_) when not (Typeload.is_generic_parameter ctx c) ->
+					display_error ctx "Only generic type parameters can be constructed" e.epos;
+					display_error ctx "While specializing this call" p;
+				| _ ->
+					Type.iter check e
+			in
+			cf2.cf_expr <- (match cf.cf_expr with
+				| None ->
+					display_error ctx "Recursive @:generic function" p; None;
+				| Some e ->
+					let e = Typeload.generic_substitute_expr gctx e in
+					check e;
+					Some e
+			);
+			cf2.cf_kind <- cf.cf_kind;
+			cf2.cf_public <- cf.cf_public;
+			let metadata = List.filter (fun (m,_,_) -> match m with
+				| Meta.Generic -> false
+				| _ -> true
+			) cf.cf_meta in
+			cf2.cf_meta <- (Meta.NoCompletion,[],p) :: (Meta.NoUsing,[],p) :: (Meta.GenericInstance,[],p) :: metadata;
+			cf2
+		in
+		let path = match c.cl_kind with
+			| KAbstractImpl(a) ->
+				a.a_path
+			| _ -> c.cl_path
+		in
+		let e = if stat then type_type ctx path p else e in
+		let fa = if stat then FStatic (c,cf2) else FInstance (c,tl,cf2) in
+		let e = mk (TField(e,fa)) cf2.cf_type p in
+		make_call ctx e el ret p
+	with Typeload.Generic_Exception (msg,p) ->
+		error msg p)
+
+let rec acc_get ctx g p =
+	match g with
+	| AKNo f -> error ("Field " ^ f ^ " cannot be accessed for reading") p
+	| AKExpr e -> e
+	| AKSet _ | AKAccess _ -> assert false
+	| AKUsing (et,c,cf,e) when ctx.in_display ->
+		(* Generate a TField node so we can easily match it for position/usage completion (issue #1968) *)
+		let ec = type_module_type ctx (TClassDecl c) None p in
+		let t = match follow et.etype with
+			| TFun (_ :: args,ret) -> TFun(args,ret)
+			| _ -> et.etype
+		in
+		mk (TField(ec,FStatic(c,cf))) t et.epos
+	| AKUsing (et,_,cf,e) ->
+		(* build a closure with first parameter applied *)
+		(match follow et.etype with
+		| TFun (_ :: args,ret) ->
+			let tcallb = TFun (args,ret) in
+			let twrap = TFun ([("_e",false,e.etype)],tcallb) in
+			(* arguments might not have names in case of variable fields of function types, so we generate one (issue #2495) *)
+			let args = List.map (fun (n,o,t) ->
+				let t = if o then ctx.t.tnull t else t in
+				o,if n = "" then gen_local ctx t e.epos else alloc_var n t e.epos (* TODO: var pos *)
+			) args in
+			let ve = alloc_var "_e" e.etype e.epos in
+			let ecall = make_call ctx et (List.map (fun v -> mk (TLocal v) v.v_type p) (ve :: List.map snd args)) ret p in
+			let ecallb = mk (TFunction {
+				tf_args = List.map (fun (o,v) -> v,if o then Some TNull else None) args;
+				tf_type = ret;
+				tf_expr = (match follow ret with | TAbstract ({a_path = [],"Void"},_) -> ecall | _ -> mk (TReturn (Some ecall)) t_dynamic p);
+			}) tcallb p in
+			let ewrap = mk (TFunction {
+				tf_args = [ve,None];
+				tf_type = tcallb;
+				tf_expr = mk (TReturn (Some ecallb)) t_dynamic p;
+			}) twrap p in
+			make_call ctx ewrap [e] tcallb p
+		| _ -> assert false)
+	| AKInline (e,f,fmode,t) ->
+		(* do not create a closure for static calls *)
+		let cmode = (match fmode with FStatic _ -> fmode | FInstance (c,tl,f) -> FClosure (Some (c,tl),f) | _ -> assert false) in
+		ignore(follow f.cf_type); (* force computing *)
+		(match f.cf_expr with
+		| None when ctx.com.display.dms_display ->
+			mk (TField (e,cmode)) t p
+		| None ->
+			error "Recursive inline is not supported" p
+		| Some { eexpr = TFunction _ } ->
+			let chk_class c = (c.cl_extern || Meta.has Meta.Extern f.cf_meta) && not (Meta.has Meta.Runtime f.cf_meta) in
+			let wrap_extern c =
+				let c2 =
+					let m = c.cl_module in
+					let mpath = (fst m.m_path @ ["_" ^ snd m.m_path],(snd m.m_path) ^ "_Impl_") in
+					try
+						let rec loop mtl = match mtl with
+							| (TClassDecl c) :: _ when c.cl_path = mpath -> c
+							| _ :: mtl -> loop mtl
+							| [] -> raise Not_found
+						in
+						loop c.cl_module.m_types
+					with Not_found ->
+						let c2 = mk_class c.cl_module mpath c.cl_pos null_pos in
+						c.cl_module.m_types <- (TClassDecl c2) :: c.cl_module.m_types;
+						c2
+				in
+				let cf = try
+					PMap.find f.cf_name c2.cl_statics
+				with Not_found ->
+					let cf = {f with cf_kind = Method MethNormal} in
+					c2.cl_statics <- PMap.add cf.cf_name cf c2.cl_statics;
+					c2.cl_ordered_statics <- cf :: c2.cl_ordered_statics;
+					cf
+				in
+				let e_t = type_module_type ctx (TClassDecl c2) None p in
+				mk (TField(e_t,FStatic(c2,cf))) t p
+			in
+			let e_def = mk (TField (e,cmode)) t p in
+			begin match follow e.etype with
+				| TInst (c,_) when chk_class c ->
+					display_error ctx "Can't create closure on an extern inline member method" p;
+					e_def
+				| TAnon a ->
+					begin match !(a.a_status) with
+						| Statics {cl_extern = false} when Meta.has Meta.Extern f.cf_meta ->
+							display_error ctx "Cannot create closure on @:extern inline method" p;
+							e_def
+						| Statics c when chk_class c -> wrap_extern c
+						| _ -> e_def
+					end
+				| _ -> e_def
+			end
+		| Some e ->
+			let rec loop e = Type.map_expr loop { e with epos = p } in
+			loop e)
+	| AKMacro _ ->
+		assert false
+
+let rec build_call ctx acc el (with_type:with_type) p =
+	match acc with
+	| AKInline (ethis,f,fmode,t) when Meta.has Meta.Generic f.cf_meta ->
+		type_generic_function ctx (ethis,fmode) el with_type p
+	| AKInline (ethis,f,fmode,t) ->
+		(match follow t with
+			| TFun (args,r) ->
+				let _,_,mk_call = unify_field_call ctx fmode el args r p true in
+				mk_call ethis p
+			| _ ->
+				error (s_type (print_context()) t ^ " cannot be called") p
+		)
+	| AKUsing (et,cl,ef,eparam) when Meta.has Meta.Generic ef.cf_meta ->
+		(match et.eexpr with
+		| TField(ec,fa) ->
+			type_generic_function ctx (ec,fa) el ~using_param:(Some eparam) with_type p
+		| _ -> assert false)
+	| AKUsing (et,cl,ef,eparam) ->
+		begin match ef.cf_kind with
+		| Method MethMacro ->
+			let ethis = type_module_type ctx (TClassDecl cl) None p in
+			let eparam,f = push_this ctx eparam in
+			let e = build_call ctx (AKMacro (ethis,ef)) (eparam :: el) with_type p in
+			f();
+			e
+		| _ ->
+			let t = follow (field_type ctx cl [] ef p) in
+			(* for abstracts we have to apply their parameters to the static function *)
+			let t,tthis = match follow eparam.etype with
+				| TAbstract(a,tl) when Meta.has Meta.Impl ef.cf_meta -> apply_params a.a_params tl t,apply_params a.a_params tl a.a_this
+				| te -> t,te
+			in
+			let params,args,r,eparam = match t with
+				| TFun ((_,_,t1) :: args,r) ->
+					unify ctx tthis t1 eparam.epos;
+					let ef = prepare_using_field ef in
+					begin match unify_call_args ctx el args r p (ef.cf_kind = Method MethInline) (is_forced_inline (Some cl) ef) with
+					| el,TFun(args,r) -> el,args,r,eparam
+					| _ -> assert false
+					end
+				| _ -> assert false
+			in
+			make_call ctx et (eparam :: params) r p
+		end
+	| AKMacro (ethis,cf) ->
+		if ctx.macro_depth > 300 then error "Stack overflow" p;
+		ctx.macro_depth <- ctx.macro_depth + 1;
+		ctx.with_type_stack <- with_type :: ctx.with_type_stack;
+		let ethis_f = ref (fun () -> ()) in
+		let f = (match ethis.eexpr with
+		| TTypeExpr (TClassDecl c) ->
+			(match ctx.g.do_macro ctx MExpr c.cl_path cf.cf_name el p with
+			| None -> (fun() -> type_expr ctx (EConst (Ident "null"),p) Value)
+			| Some (EMeta((Meta.MergeBlock,_,_),(EBlock el,_)),_) -> (fun () -> let e = (!type_block_ref) ctx el with_type p in mk (TMeta((Meta.MergeBlock,[],p), e)) e.etype e.epos)
+			| Some e -> (fun() -> type_expr ctx e with_type))
+		| _ ->
+			(* member-macro call : since we will make a static call, let's found the actual class and not its subclass *)
+			(match follow ethis.etype with
+			| TInst (c,_) ->
+				let rec loop c =
+					if PMap.mem cf.cf_name c.cl_fields then
+						let eparam,f = push_this ctx ethis in
+						ethis_f := f;
+						let e = match ctx.g.do_macro ctx MExpr c.cl_path cf.cf_name (eparam :: el) p with
+							| None -> (fun() -> type_expr ctx (EConst (Ident "null"),p) Value)
+							| Some e -> (fun() -> type_expr ctx e Value)
+						in
+						e
+					else
+						match c.cl_super with
+						| None -> assert false
+						| Some (csup,_) -> loop csup
+				in
+				loop c
+			| _ -> assert false))
+		in
+		ctx.macro_depth <- ctx.macro_depth - 1;
+		ctx.with_type_stack <- List.tl ctx.with_type_stack;
+		let old = ctx.on_error in
+		ctx.on_error <- (fun ctx msg ep ->
+			(* display additional info in the case the error is not part of our original call *)
+			if ep.pfile <> p.pfile || ep.pmax < p.pmin || ep.pmin > p.pmax then begin
+				Typeload.locate_macro_error := false;
+				old ctx msg ep;
+				Typeload.locate_macro_error := true;
+				ctx.com.error "Called from macro here" p;
+			end else
+				old ctx msg ep;
+		);
+		let e = try
+			f()
+		with Error (m,p) ->
+			ctx.on_error <- old;
+			!ethis_f();
+			raise (Fatal_error ((error_msg m),p))
+		in
+		let e = Display.Diagnostics.secure_generated_code ctx e in
+		ctx.on_error <- old;
+		!ethis_f();
+		e
+	| AKNo _ | AKSet _ | AKAccess _ ->
+		ignore(acc_get ctx acc p);
+		assert false
+	| AKExpr e ->
+		let rec loop t = match follow t with
+		| TFun (args,r) ->
+			begin match e.eexpr with
+				| TField(e1,fa) when not (match fa with FEnum _ -> true | _ -> false) ->
+					begin match fa with
+						| FInstance(_,_,cf) | FStatic(_,cf) when Meta.has Meta.Generic cf.cf_meta ->
+							type_generic_function ctx (e1,fa) el with_type p
+						| _ ->
+							let _,_,mk_call = unify_field_call ctx fa el args r p false in
+							mk_call e1 e.epos
+					end
+				| _ ->
+					let el, tfunc = unify_call_args ctx el args r p false false in
+					let r = match tfunc with TFun(_,r) -> r | _ -> assert false in
+					mk (TCall (e,el)) r p
+			end
+		| TAbstract(a,tl) when Meta.has Meta.Callable a.a_meta ->
+			loop (Abstract.get_underlying_type a tl)
+		| TMono _ ->
+			let t = mk_mono() in
+			let el = List.map (fun e -> type_expr ctx e Value) el in
+			unify ctx (tfun (List.map (fun e -> e.etype) el) t) e.etype e.epos;
+			mk (TCall (e,el)) t p
+		| t ->
+			let el = List.map (fun e -> type_expr ctx e Value) el in
+			let t = if t == t_dynamic then
+				t_dynamic
+			else if ctx.untyped then
+				mk_mono()
+			else
+				error (s_type (print_context()) e.etype ^ " cannot be called") e.epos
+			in
+			mk (TCall (e,el)) t p
+		in
+		loop e.etype
+
+let type_bind ctx (e : texpr) (args,ret) params p =
+	let vexpr v = mk (TLocal v) v.v_type p in
+	let acount = ref 0 in
+	let alloc_name n =
+		if n = "" && not ctx.is_display_file then begin
+			incr acount;
+			"a" ^ string_of_int !acount;
+		end else
+			n
+	in
+	let rec loop args params given_args missing_args ordered_args = match args, params with
+		| [], [] -> given_args,missing_args,ordered_args
+		| [], _ -> error "Too many callback arguments" p
+		| (n,o,t) :: args , [] when o ->
+			let a = if is_pos_infos t then
+					let infos = mk_infos ctx p [] in
+					ordered_args @ [type_expr ctx infos (WithType t)]
+				else if ctx.com.config.pf_pad_nulls then
+					(ordered_args @ [(mk (TConst TNull) t_dynamic p)])
+				else
+					ordered_args
+			in
+			loop args [] given_args missing_args a
+		| (n,o,t) :: _ , (EConst(Ident "_"),p) :: _ when not ctx.com.config.pf_can_skip_non_nullable_argument && o && not (is_nullable t) ->
+			error "Usage of _ is not supported for optional non-nullable arguments" p
+		| (n,o,t) :: args , ([] as params)
+		| (n,o,t) :: args , (EConst(Ident "_"),_) :: params ->
+			let v = alloc_var (alloc_name n) (if o then ctx.t.tnull t else t) p in
+			loop args params given_args (missing_args @ [v,o]) (ordered_args @ [vexpr v])
+		| (n,o,t) :: args , param :: params ->
+			let e = type_expr ctx param (WithType t) in
+			let e = AbstractCast.cast_or_unify ctx t e p in
+			let v = alloc_var (alloc_name n) t (pos param) in
+			loop args params (given_args @ [v,o,Some e]) missing_args (ordered_args @ [vexpr v])
+	in
+	let given_args,missing_args,ordered_args = loop args params [] [] [] in
+	let rec gen_loc_name n =
+		let name = if n = 0 then "f" else "f" ^ (string_of_int n) in
+		if List.exists (fun (n,_,_) -> name = n) args then gen_loc_name (n + 1) else name
+	in
+	let loc = alloc_var (gen_loc_name 0) e.etype e.epos in
+	let given_args = (loc,false,Some e) :: given_args in
+	let inner_fun_args l = List.map (fun (v,o) -> v.v_name, o, v.v_type) l in
+	let t_inner = TFun(inner_fun_args missing_args, ret) in
+	let call = make_call ctx (vexpr loc) ordered_args ret p in
+	let e_ret = match follow ret with
+		| TAbstract ({a_path = [],"Void"},_) ->
+			call
+		| TMono _ ->
+			mk (TReturn (Some call)) t_dynamic p;
+		| _ ->
+			mk (TReturn (Some call)) t_dynamic p;
+	in
+	let func = mk (TFunction {
+		tf_args = List.map (fun (v,o) -> v, if o then Some TNull else None) missing_args;
+		tf_type = ret;
+		tf_expr = e_ret;
+	}) t_inner p in
+	let outer_fun_args l = List.map (fun (v,o,_) -> v.v_name, o, v.v_type) l in
+	let func = mk (TFunction {
+		tf_args = List.map (fun (v,_,_) -> v,None) given_args;
+		tf_type = t_inner;
+		tf_expr = mk (TReturn (Some func)) t_inner p;
+	}) (TFun(outer_fun_args given_args, t_inner)) p in
+	make_call ctx func (List.map (fun (_,_,e) -> (match e with Some e -> e | None -> assert false)) given_args) t_inner p

+ 538 - 0
src/typing/fields.ml

@@ -0,0 +1,538 @@
+open Globals
+open Common
+open Ast
+open Type
+open TyperBase
+open Error
+open Typecore
+
+(*
+	temporally remove the constant flag from structures to allow larger unification
+*)
+let remove_constant_flag t callb =
+	let tmp = ref [] in
+	let rec loop t =
+		match follow t with
+		| TAnon a ->
+			if !(a.a_status) = Const then begin
+				a.a_status := Closed;
+				tmp := a :: !tmp;
+			end;
+			PMap.iter (fun _ f -> loop f.cf_type) a.a_fields;
+		|  _ ->
+			()
+	in
+	let restore() =
+		List.iter (fun a -> a.a_status := Const) (!tmp)
+	in
+	try
+		loop t;
+		let ret = callb (!tmp <> []) in
+		restore();
+		ret
+	with e ->
+		restore();
+		raise e
+
+let check_constraints ctx tname tpl tl map delayed p =
+	List.iter2 (fun m (name,t) ->
+		match follow t with
+		| TInst ({ cl_kind = KTypeParameter constr },_) when constr <> [] ->
+			let f = (fun() ->
+				List.iter (fun ct ->
+					try
+						Type.unify (map m) (map ct)
+					with Unify_error l ->
+						let l = Constraint_failure (tname ^ "." ^ name) :: l in
+						raise (Unify_error l)
+				) constr
+			) in
+			if delayed then
+				delay ctx PCheckConstraint (fun () -> try f() with Unify_error l -> display_error ctx (error_msg (Unify l)) p)
+			else
+				f()
+		| _ ->
+			()
+	) tl tpl
+
+let enum_field_type ctx en ef tl_en tl_ef p =
+	let map t = apply_params en.e_params tl_en (apply_params ef.ef_params tl_ef t) in
+	begin try
+		check_constraints ctx (s_type_path en.e_path) en.e_params tl_en map true p;
+		check_constraints ctx ef.ef_name ef.ef_params tl_ef map true p;
+	with Unify_error l ->
+		display_error ctx (error_msg (Unify l)) p
+	end;
+	map ef.ef_type
+
+let add_constraint_checks ctx ctypes pl f tl p =
+	List.iter2 (fun m (name,t) ->
+		match follow t with
+		| TInst ({ cl_kind = KTypeParameter constr },_) when constr <> [] ->
+			let constr = List.map (fun t ->
+				let t = apply_params f.cf_params tl t in
+				(* only apply params if not static : in that case no param is passed *)
+				let t = (if pl = [] then t else apply_params ctypes pl t) in
+				t
+			) constr in
+			delay ctx PCheckConstraint (fun() ->
+				List.iter (fun ct ->
+					try
+						(* if has_mono m then raise (Unify_error [Unify_custom "Could not resolve full type for constraint checks"; Unify_custom ("Type was " ^ (s_type (print_context()) m))]); *)
+						Type.unify m ct
+					with Unify_error l ->
+						display_error ctx (error_msg (Unify (Constraint_failure (f.cf_name ^ "." ^ name) :: l))) p;
+				) constr
+			);
+		| _ -> ()
+	) tl f.cf_params
+
+let field_type ctx c pl f p =
+	match f.cf_params with
+	| [] -> f.cf_type
+	| l ->
+		let monos = List.map (fun _ -> mk_mono()) l in
+		if not (Meta.has Meta.Generic f.cf_meta) then add_constraint_checks ctx c.cl_params pl f monos p;
+		apply_params l monos f.cf_type
+
+let fast_enum_field e ef p =
+	let et = mk (TTypeExpr (TEnumDecl e)) (TAnon { a_fields = PMap.empty; a_status = ref (EnumStatics e) }) p in
+	TField (et,FEnum (e,ef))
+
+let get_constructor ctx c params p =
+	match c.cl_kind with
+	| KAbstractImpl a ->
+		let f = (try PMap.find "_new" c.cl_statics with Not_found -> raise_error (No_constructor (TAbstractDecl a)) p) in
+		let ct = field_type ctx c params f p in
+		apply_params a.a_params params ct, f
+	| _ ->
+		let ct, f = (try Type.get_constructor (fun f -> field_type ctx c params f p) c with Not_found -> raise_error (No_constructor (TClassDecl c)) p) in
+		apply_params c.cl_params params ct, f
+
+let field_access ctx mode f fmode t e p =
+	let fnormal() = AKExpr (mk (TField (e,fmode)) t p) in
+	let normal() =
+		match follow e.etype with
+		| TAnon a ->
+			(match !(a.a_status) with
+			| EnumStatics en ->
+				let c = (try PMap.find f.cf_name en.e_constrs with Not_found -> assert false) in
+				let fmode = FEnum (en,c) in
+				AKExpr (mk (TField (e,fmode)) t p)
+			| _ -> fnormal())
+		| _ -> fnormal()
+	in
+	match f.cf_kind with
+	| Method m ->
+		if mode = MSet && m <> MethDynamic && not ctx.untyped then error "Cannot rebind this method : please use 'dynamic' before method declaration" p;
+		begin match ctx.curfun,e.eexpr with
+		| (FunMemberAbstract | FunMemberAbstractLocal),TTypeExpr(TClassDecl ({cl_kind = KAbstractImpl a} as c)) when c == ctx.curclass && Meta.has Meta.Impl f.cf_meta ->
+			let e = mk (TField(e,fmode)) t p in
+			let ethis = get_this ctx p in
+			let ethis = {ethis with etype = TAbstract(a,List.map snd a.a_params)} in
+			AKUsing(e,ctx.curclass,f,ethis)
+		| _ ->
+			(match m, mode with
+			| MethInline, _ -> AKInline (e,f,fmode,t)
+			| MethMacro, MGet -> display_error ctx "Macro functions must be called immediately" p; normal()
+			| MethMacro, MCall -> AKMacro (e,f)
+			| _ , MGet ->
+				let cmode = (match fmode with
+					| FInstance(_, _, cf) | FStatic(_, cf) when Meta.has Meta.Generic cf.cf_meta -> display_error ctx "Cannot create closure on generic function" p; fmode
+					| FInstance (c,tl,cf) -> FClosure (Some (c,tl),cf)
+					| FStatic _ | FEnum _ -> fmode
+					| FAnon f -> FClosure (None, f)
+					| FDynamic _ | FClosure _ -> assert false
+				) in
+				AKExpr (mk (TField (e,cmode)) t p)
+			| _ -> normal())
+		end
+	| Var v ->
+		match (match mode with MGet | MCall -> v.v_read | MSet -> v.v_write) with
+		| AccNo when not (Meta.has Meta.PrivateAccess ctx.meta) ->
+			(match follow e.etype with
+			| TInst (c,_) when is_parent c ctx.curclass || can_access ctx c { f with cf_public = false } false -> normal()
+			| TAnon a ->
+				(match !(a.a_status) with
+				| Opened when mode = MSet ->
+					f.cf_kind <- Var { v with v_write = AccNormal };
+					normal()
+				| Statics c2 when ctx.curclass == c2 || can_access ctx c2 { f with cf_public = false } true -> normal()
+				| _ -> if ctx.untyped then normal() else AKNo f.cf_name)
+			| _ ->
+				if ctx.untyped then normal() else AKNo f.cf_name)
+		| AccNormal | AccNo ->
+			(*
+				if we are reading from a read-only variable on an anonymous object, it might actually be a method, so make sure to create a closure
+			*)
+			let is_maybe_method() =
+				match v.v_write, follow t, follow e.etype with
+				| (AccNo | AccNever), TFun _, TAnon a ->
+					(match !(a.a_status) with
+					| Statics _ | EnumStatics _ -> false
+					| _ -> true)
+				| _ -> false
+			in
+			if mode = MGet && is_maybe_method() then
+				AKExpr (mk (TField (e,FClosure (None,f))) t p)
+			else
+				normal()
+		| AccCall when ctx.in_display ->
+			normal()
+		| AccCall ->
+			let m = (match mode with MSet -> "set_" | _ -> "get_") ^ f.cf_name in
+			let is_abstract_this_access () = match e.eexpr,ctx.curfun with
+				| TTypeExpr (TClassDecl ({cl_kind = KAbstractImpl _} as c)),(FunMemberAbstract | FunMemberAbstractLocal) ->
+					c == ctx.curclass
+				| _ ->
+					false
+			in
+			if m = ctx.curfield.cf_name && (match e.eexpr with TConst TThis -> true | TLocal v -> Option.map_default (fun vthis -> v == vthis) false ctx.vthis | TTypeExpr (TClassDecl c) when c == ctx.curclass -> true | _ -> false) then
+				let prefix = (match ctx.com.platform with Flash when Common.defined ctx.com Define.As3 -> "$" | _ -> "") in
+				(match e.eexpr with TLocal _ when Common.defined ctx.com Define.Haxe3Compat -> ctx.com.warning "Field set has changed here in Haxe 4: call setter explicitly to keep Haxe 3.x behaviour" p | _ -> ());
+				if not (is_physical_field f) then begin
+					display_error ctx "This field cannot be accessed because it is not a real variable" p;
+					display_error ctx "Add @:isVar here to enable it" f.cf_pos;
+				end;
+				AKExpr (mk (TField (e,if prefix = "" then fmode else FDynamic (prefix ^ f.cf_name))) t p)
+			else if is_abstract_this_access() then begin
+				let this = get_this ctx p in
+				if mode = MSet then begin
+					let c,a = match ctx.curclass with {cl_kind = KAbstractImpl a} as c -> c,a | _ -> assert false in
+					let f = PMap.find m c.cl_statics in
+					(* we don't have access to the type parameters here, right? *)
+					(* let t = apply_params a.a_params pl (field_type ctx c [] f p) in *)
+					let t = (field_type ctx c [] f p) in
+					let ef = mk (TField (e,FStatic (c,f))) t p in
+					AKUsing (ef,c,f,this)
+				end else
+					AKExpr (make_call ctx (mk (TField (e,quick_field_dynamic e.etype m)) (tfun [this.etype] t) p) [this] t p)
+			end else if mode = MSet then
+				AKSet (e,t,f)
+			else
+				AKExpr (make_call ctx (mk (TField (e,quick_field_dynamic e.etype m)) (tfun [] t) p) [] t p)
+		| AccResolve ->
+			let fstring = mk (TConst (TString f.cf_name)) ctx.t.tstring p in
+			let tresolve = tfun [ctx.t.tstring] t in
+			AKExpr (make_call ctx (mk (TField (e,FDynamic "resolve")) tresolve p) [fstring] t p)
+		| AccNever ->
+			if ctx.untyped then normal() else AKNo f.cf_name
+		| AccInline ->
+			AKInline (e,f,fmode,t)
+		| AccCtor ->
+			if ctx.curfun = FunConstructor then normal() else AKNo f.cf_name
+		| AccRequire (r,msg) ->
+			match msg with
+			| None -> error_require r p
+			| Some msg -> error msg p
+
+let class_field ctx c tl name p =
+	raw_class_field (fun f -> field_type ctx c tl f p) c tl name
+
+let rec using_field ctx mode e i p =
+	if mode = MSet then raise Not_found;
+	(* do not try to find using fields if the type is a monomorph, which could lead to side-effects *)
+	let is_dynamic = match follow e.etype with
+		| TMono _ -> raise Not_found
+		| t -> t == t_dynamic
+	in
+	let check_constant_struct = ref false in
+	let rec loop = function
+	| [] ->
+		raise Not_found
+	| (c,pc) :: l ->
+		try
+			let cf = PMap.find i c.cl_statics in
+			if Meta.has Meta.NoUsing cf.cf_meta || not (can_access ctx c cf true) || (Meta.has Meta.Impl cf.cf_meta) then raise Not_found;
+			let monos = List.map (fun _ -> mk_mono()) cf.cf_params in
+			let map = apply_params cf.cf_params monos in
+			let t = map cf.cf_type in
+			begin match follow t with
+				| TFun((_,_,(TType({t_path = ["haxe";"macro"],"ExprOf"},[t0]) | t0)) :: args,r) ->
+					if is_dynamic && follow t0 != t_dynamic then raise Not_found;
+					let e = AbstractCast.cast_or_unify_raise ctx t0 e p in
+					(* early constraints check is possible because e.etype has no monomorphs *)
+					List.iter2 (fun m (name,t) -> match follow t with
+						| TInst ({ cl_kind = KTypeParameter constr },_) when constr <> [] && not (has_mono m) ->
+							List.iter (fun tc -> Type.unify m (map tc)) constr
+						| _ -> ()
+					) monos cf.cf_params;
+					let et = type_module_type ctx (TClassDecl c) None p in
+					Display.ImportHandling.maybe_mark_import_position ctx pc;
+					AKUsing (mk (TField (et,FStatic (c,cf))) t p,c,cf,e)
+				| _ ->
+					raise Not_found
+			end
+		with Not_found ->
+			loop l
+		| Unify_error el | Error (Unify el,_) ->
+			if List.exists (function Has_extra_field _ -> true | _ -> false) el then check_constant_struct := true;
+			loop l
+	in
+	try loop ctx.m.module_using with Not_found ->
+	try
+		let acc = loop ctx.g.global_using in
+		(match acc with
+		| AKUsing (_,c,_,_) -> add_dependency ctx.m.curmod c.cl_module
+		| _ -> assert false);
+		acc
+	with Not_found ->
+	if not !check_constant_struct then raise Not_found;
+	remove_constant_flag e.etype (fun ok -> if ok then using_field ctx mode e i p else raise Not_found)
+
+(* Resolves field [i] on typed expression [e] using the given [mode]. *)
+let rec type_field ?(resume=false) ctx e i p mode =
+	let no_field() =
+		if resume then raise Not_found;
+		let t = match follow e.etype with
+			| TAnon a -> (match !(a.a_status) with
+				| Statics {cl_kind = KAbstractImpl a} -> TAbstract(a,[])
+				| _ -> e.etype)
+			| TInst({cl_kind = KAbstractImpl a},_) -> TAbstract(a,[])
+			| _ -> e.etype
+		in
+		let has_special_field a =
+			List.exists (fun (_,cf) -> cf.cf_name = i) a.a_ops
+			|| List.exists (fun (_,_,cf) -> cf.cf_name = i) a.a_unops
+			|| List.exists (fun cf -> cf.cf_name = i) a.a_array
+		in
+		if not ctx.untyped then begin
+			match t with
+			| TAbstract(a,_) when has_special_field a ->
+				(* the abstract field is not part of the field list, which is only true when it has no expression (issue #2344) *)
+				display_error ctx ("Field " ^ i ^ " cannot be called directly because it has no expression") p;
+			| _ ->
+				display_error ctx (StringError.string_error i (string_source t) (s_type (print_context()) t ^ " has no field " ^ i)) p;
+		end;
+		AKExpr (mk (TField (e,FDynamic i)) (mk_mono()) p)
+	in
+	let does_forward a stat =
+		try
+			let _,el,_ = Meta.get (if stat then Meta.ForwardStatics else Meta.Forward) a.a_meta in
+			match el with
+				| [] ->
+					true
+				| _ ->
+					List.exists (fun e -> match fst e with
+						| EConst(Ident s | String s) -> s = i
+						| _ -> error "Identifier or string expected as argument to @:forward" (pos e)
+					) el
+		with Not_found ->
+			false
+	in
+	match follow e.etype with
+	| TInst (c,params) ->
+		let rec loop_dyn c params =
+			match c.cl_dynamic with
+			| Some t ->
+				let t = apply_params c.cl_params params t in
+				if (mode = MGet || mode = MCall) && PMap.mem "resolve" c.cl_fields then begin
+					let f = PMap.find "resolve" c.cl_fields in
+					begin match f.cf_kind with
+						| Method MethMacro -> display_error ctx "The macro accessor is not allowed for field resolve" f.cf_pos
+						| _ -> ()
+					end;
+					let texpect = tfun [ctx.t.tstring] t in
+					let tfield = apply_params c.cl_params params (monomorphs f.cf_params f.cf_type) in
+					(try Type.unify tfield texpect
+					with Unify_error l ->
+						display_error ctx "Field resolve has an invalid type" f.cf_pos;
+						display_error ctx (error_msg (Unify [Cannot_unify(tfield,texpect)])) f.cf_pos);
+					AKExpr (make_call ctx (mk (TField (e,FInstance (c,params,f))) tfield p) [Texpr.type_constant ctx.com.basic (String i) p] t p)
+				end else
+					AKExpr (mk (TField (e,FDynamic i)) t p)
+			| None ->
+				match c.cl_super with
+				| None -> raise Not_found
+				| Some (c,params) -> loop_dyn c params
+		in
+		(try
+			let c2, t , f = class_field ctx c params i p in
+			if e.eexpr = TConst TSuper then (match mode,f.cf_kind with
+				| MGet,Var {v_read = AccCall }
+				| MSet,Var {v_write = AccCall }
+				| MCall,Var {v_read = AccCall } ->
+					()
+				| MCall, Var _ ->
+					display_error ctx "Cannot access superclass variable for calling: needs to be a proper method" p
+				| MCall, _ ->
+					()
+				| MGet,Var _
+				| MSet,Var _ when (match c2 with Some ({ cl_extern = true; cl_path = ("flash" :: _,_) }, _) -> true | _ -> false) ->
+					()
+				| _, Method _ ->
+					display_error ctx "Cannot create closure on super method" p
+				| _ ->
+					display_error ctx "Normal variables cannot be accessed with 'super', use 'this' instead" p);
+			if not (can_access ctx c f false) && not ctx.untyped then display_error ctx ("Cannot access private field " ^ i) p;
+			field_access ctx mode f (match c2 with None -> FAnon f | Some (c,tl) -> FInstance (c,tl,f)) (apply_params c.cl_params params t) e p
+		with Not_found -> try
+			begin match e.eexpr with
+				| TConst TSuper -> raise Not_found
+				| _ -> using_field ctx mode e i p
+			end
+		with Not_found -> try
+			loop_dyn c params
+		with Not_found -> try
+			(* if we have an abstract constraint we have to check its static fields and recurse (issue #2343) *)
+			begin match c.cl_kind with
+				| KTypeParameter tl ->
+					let rec loop tl = match tl with
+						| t :: tl ->
+							begin match follow t with
+								| TAbstract({a_impl = Some c},tl) when PMap.mem i c.cl_statics ->
+									let e = mk_cast e t p in
+									type_field ctx e i p mode;
+								| _ ->
+									loop tl
+							end
+						| [] ->
+							raise Not_found
+					in
+					loop tl
+				| _ ->
+					raise Not_found
+			end
+		with Not_found ->
+			if PMap.mem i c.cl_statics then error ("Cannot access static field " ^ i ^ " from a class instance") p;
+			no_field())
+	| TDynamic t ->
+		(try
+			using_field ctx mode e i p
+		with Not_found ->
+			AKExpr (mk (TField (e,FDynamic i)) t p))
+	| TAnon a ->
+		(try
+			let f = PMap.find i a.a_fields in
+			if Meta.has Meta.Impl f.cf_meta && not (Meta.has Meta.Enum f.cf_meta) then display_error ctx "Cannot access non-static abstract field statically" p;
+			if not f.cf_public && not ctx.untyped then begin
+				match !(a.a_status) with
+				| Closed | Extend _ -> () (* always allow anon private fields access *)
+				| Statics c when can_access ctx c f true -> ()
+				| _ -> display_error ctx ("Cannot access private field " ^ i) p
+			end;
+			let fmode, ft = (match !(a.a_status) with
+				| Statics c -> FStatic (c,f), field_type ctx c [] f p
+				| EnumStatics e -> FEnum (e,try PMap.find f.cf_name e.e_constrs with Not_found -> assert false), Type.field_type f
+				| _ ->
+					match f.cf_params with
+					| [] ->
+						FAnon f, Type.field_type f
+					| l ->
+						(* handle possible constraints *)
+						let monos = List.map (fun _ -> mk_mono()) l in
+						let t = apply_params f.cf_params monos f.cf_type in
+						add_constraint_checks ctx [] [] f monos p;
+						FAnon f, t
+			) in
+			field_access ctx mode f fmode ft e p
+		with Not_found -> try
+				match !(a.a_status) with
+				| Statics {cl_kind = KAbstractImpl a} when does_forward a true ->
+					let mt = try module_type_of_type a.a_this with Exit -> raise Not_found in
+					let et = type_module_type ctx mt None p in
+					type_field ctx et i p mode;
+				| _ ->
+					raise Not_found
+			with Not_found ->
+				if is_closed a then try
+					using_field ctx mode e i p
+				with Not_found ->
+					no_field()
+				else
+				let f = {
+					(mk_field i (mk_mono()) p null_pos) with
+					cf_kind = Var { v_read = AccNormal; v_write = (match mode with MSet -> AccNormal | MGet | MCall -> AccNo) };
+				} in
+				a.a_fields <- PMap.add i f a.a_fields;
+				field_access ctx mode f (FAnon f) (Type.field_type f) e p
+		)
+	| TMono r ->
+		let f = {
+			(mk_field i (mk_mono()) p null_pos) with
+			cf_kind = Var { v_read = AccNormal; v_write = (match mode with MSet -> AccNormal | MGet | MCall -> AccNo) };
+		} in
+		let x = ref Opened in
+		let t = TAnon { a_fields = PMap.add i f PMap.empty; a_status = x } in
+		ctx.opened <- x :: ctx.opened;
+		r := Some t;
+		field_access ctx mode f (FAnon f) (Type.field_type f) e p
+	| TAbstract (a,pl) ->
+		let static_abstract_access_through_instance = ref false in
+		(try
+			let c = (match a.a_impl with None -> raise Not_found | Some c -> c) in
+			let f = PMap.find i c.cl_statics in
+			if not (can_access ctx c f true) && not ctx.untyped then display_error ctx ("Cannot access private field " ^ i) p;
+			let field_type f =
+				if not (Meta.has Meta.Impl f.cf_meta) then begin
+					static_abstract_access_through_instance := true;
+					raise Not_found;
+				end;
+				let t = field_type ctx c [] f p in
+				apply_params a.a_params pl t
+			in
+			let et = type_module_type ctx (TClassDecl c) None p in
+			let field_expr f t = mk (TField (et,FStatic (c,f))) t p in
+			(match mode, f.cf_kind with
+			| (MGet | MCall), Var {v_read = AccCall } ->
+				(* getter call *)
+				let f = PMap.find ("get_" ^ f.cf_name) c.cl_statics in
+				let t = field_type f in
+				let r = match follow t with TFun(_,r) -> r | _ -> raise Not_found in
+				let ef = field_expr f t in
+				AKExpr(make_call ctx ef [e] r p)
+			| MSet, Var {v_write = AccCall } ->
+				let f = PMap.find ("set_" ^ f.cf_name) c.cl_statics in
+				let t = field_type f in
+				let ef = field_expr f t in
+				AKUsing (ef,c,f,e)
+			| (MGet | MCall), Var {v_read = AccNever} ->
+				AKNo f.cf_name
+			| (MGet | MCall), _ ->
+				let rec loop cfl = match cfl with
+					| [] -> error (Printf.sprintf "Field %s cannot be called on %s" f.cf_name (s_type (print_context()) e.etype)) p
+					| cf :: cfl ->
+						match follow (apply_params a.a_params pl (monomorphs cf.cf_params cf.cf_type)) with
+							| TFun((_,_,t1) :: _,_) when type_iseq t1 (Abstract.get_underlying_type a pl) ->
+								cf
+							| _ ->
+								loop cfl
+				in
+				let f = match f.cf_overloads with
+					| [] -> f
+					| cfl -> loop (f :: cfl)
+				in
+				let t = field_type f in
+				begin match follow t with
+					| TFun((_,_,t1) :: _,_) -> ()
+					| _ -> error ("Invalid call to static function " ^ i ^ " through abstract instance") p
+				end;
+				let ef = field_expr f t in
+				AKUsing (ef,c,f,e)
+			| MSet, _ ->
+				error "This operation is unsupported" p)
+		with Not_found -> try
+			if does_forward a false then
+				type_field ~resume:true ctx {e with etype = apply_params a.a_params pl a.a_this} i p mode
+			else
+				raise Not_found
+		with Not_found -> try
+			using_field ctx mode e i p
+		with Not_found -> try
+			(match ctx.curfun, e.eexpr with
+			| FunMemberAbstract, TConst (TThis) -> type_field ctx {e with etype = apply_params a.a_params pl a.a_this} i p mode;
+			| _ -> raise Not_found)
+		with Not_found -> try
+			let c,cf = match a.a_impl,a.a_resolve with
+				| Some c,Some cf -> c,cf
+				| _ -> raise Not_found
+			in
+			let et = type_module_type ctx (TClassDecl c) None p in
+			let t = apply_params a.a_params pl (field_type ctx c [] cf p) in
+			let ef = mk (TField (et,FStatic (c,cf))) t p in
+			AKExpr ((!build_call_ref) ctx (AKUsing(ef,c,cf,e)) [EConst (String i),p] NoValue p)
+		with Not_found ->
+			if !static_abstract_access_through_instance then error ("Invalid call to static function " ^ i ^ " through abstract instance") p
+			else no_field())
+	| _ ->
+		try using_field ctx mode e i p with Not_found -> no_field()

+ 166 - 0
src/typing/finalization.ml

@@ -0,0 +1,166 @@
+open Globals
+open Ast
+open Common
+open Type
+open Error
+open TyperBase
+open Typecore
+
+(* ---------------------------------------------------------------------- *)
+(* FINALIZATION *)
+
+let get_main ctx types =
+	match ctx.com.main_class with
+	| None -> None
+	| Some cl ->
+		let t = Typeload.load_type_def ctx null_pos { tpackage = fst cl; tname = snd cl; tparams = []; tsub = None } in
+		let fmode, ft, r = (match t with
+		| TEnumDecl _ | TTypeDecl _ | TAbstractDecl _ ->
+			error ("Invalid -main : " ^ s_type_path cl ^ " is not a class") null_pos
+		| TClassDecl c ->
+			try
+				let f = PMap.find "main" c.cl_statics in
+				let t = Type.field_type f in
+				(match follow t with
+				| TFun ([],r) -> FStatic (c,f), t, r
+				| _ -> error ("Invalid -main : " ^ s_type_path cl ^ " has invalid main function") c.cl_pos);
+			with
+				Not_found -> error ("Invalid -main : " ^ s_type_path cl ^ " does not have static function main") c.cl_pos
+		) in
+		let emain = type_type ctx cl null_pos in
+		let main = mk (TCall (mk (TField (emain,fmode)) ft null_pos,[])) r null_pos in
+		(* add haxe.EntryPoint.run() call *)
+		let main = (try
+			let et = List.find (fun t -> t_path t = (["haxe"],"EntryPoint")) types in
+			let ec = (match et with TClassDecl c -> c | _ -> assert false) in
+			let ef = PMap.find "run" ec.cl_statics in
+			let p = null_pos in
+			let et = mk (TTypeExpr et) (TAnon { a_fields = PMap.empty; a_status = ref (Statics ec) }) p in
+			let call = mk (TCall (mk (TField (et,FStatic (ec,ef))) ef.cf_type p,[])) ctx.t.tvoid p in
+			mk (TBlock [main;call]) ctx.t.tvoid p
+		with Not_found ->
+			main
+		) in
+		Some main
+
+let finalize ctx =
+	flush_pass ctx PFinal "final";
+	match ctx.com.callbacks.after_typing with
+		| [] ->
+			()
+		| fl ->
+			let rec loop handled_types =
+				let all_types = Hashtbl.fold (fun _ m acc -> m.m_types @ acc) ctx.g.modules [] in
+				match (List.filter (fun mt -> not (List.memq mt handled_types)) all_types) with
+				| [] ->
+					()
+				| new_types ->
+					List.iter (fun f -> f new_types) fl;
+					flush_pass ctx PFinal "final";
+					loop all_types
+			in
+			loop []
+
+type state =
+	| Generating
+	| Done
+	| NotYet
+
+let sort_types com modules =
+	let types = ref [] in
+	let states = Hashtbl.create 0 in
+	let state p = try Hashtbl.find states p with Not_found -> NotYet in
+	let statics = ref PMap.empty in
+
+	let rec loop t =
+		let p = t_path t in
+		match state p with
+		| Done -> ()
+		| Generating ->
+			com.warning ("Warning : maybe loop in static generation of " ^ s_type_path p) (t_infos t).mt_pos;
+		| NotYet ->
+			Hashtbl.add states p Generating;
+			let t = (match t with
+			| TClassDecl c ->
+				walk_class p c;
+				t
+			| TEnumDecl _ | TTypeDecl _ | TAbstractDecl _ ->
+				t
+			) in
+			Hashtbl.replace states p Done;
+			types := t :: !types
+
+	and loop_class p c =
+		if c.cl_path <> p then loop (TClassDecl c)
+
+	and loop_enum p e =
+		if e.e_path <> p then loop (TEnumDecl e)
+
+	and loop_abstract p a =
+		if a.a_path <> p then loop (TAbstractDecl a)
+
+	and walk_static_field p c cf =
+		match cf.cf_expr with
+		| None -> ()
+		| Some e ->
+			if PMap.mem (c.cl_path,cf.cf_name) (!statics) then
+				()
+			else begin
+				statics := PMap.add (c.cl_path,cf.cf_name) () (!statics);
+				walk_expr p e;
+			end
+
+	and walk_expr p e =
+		match e.eexpr with
+		| TTypeExpr t ->
+			(match t with
+			| TClassDecl c -> loop_class p c
+			| TEnumDecl e -> loop_enum p e
+			| TAbstractDecl a -> loop_abstract p a
+			| TTypeDecl _ -> assert false)
+		| TNew (c,_,_) ->
+			iter (walk_expr p) e;
+			loop_class p c;
+			let rec loop c =
+				if PMap.mem (c.cl_path,"new") (!statics) then
+					()
+				else begin
+					statics := PMap.add (c.cl_path,"new") () !statics;
+					(match c.cl_constructor with
+					| Some { cf_expr = Some e } -> walk_expr p e
+					| _ -> ());
+					match c.cl_super with
+					| None -> ()
+					| Some (csup,_) -> loop csup
+				end
+			in
+			loop c
+		| TField(e1,FStatic(c,cf)) ->
+			walk_expr p e1;
+			walk_static_field p c cf;
+		| _ ->
+			iter (walk_expr p) e
+
+	and walk_class p c =
+		(match c.cl_super with None -> () | Some (c,_) -> loop_class p c);
+		List.iter (fun (c,_) -> loop_class p c) c.cl_implements;
+		(match c.cl_init with
+		| None -> ()
+		| Some e -> walk_expr p e);
+		PMap.iter (fun _ f ->
+			match f.cf_expr with
+			| None -> ()
+			| Some e ->
+				match e.eexpr with
+				| TFunction _ -> ()
+				| _ -> walk_expr p e
+		) c.cl_statics
+
+	in
+	let sorted_modules = List.sort (fun m1 m2 -> compare m1.m_path m2.m_path) (Hashtbl.fold (fun _ m acc -> m :: acc) modules []) in
+	List.iter (fun m -> List.iter loop m.m_types) sorted_modules;
+	List.rev !types, sorted_modules
+
+let generate ctx =
+	let types,modules = sort_types ctx.com ctx.g.modules in
+	get_main ctx types,types,modules

+ 274 - 0
src/typing/forLoop.ml

@@ -0,0 +1,274 @@
+open Globals
+open Ast
+open Type
+open Common
+open Typecore
+open TyperBase
+open Fields
+open Error
+
+(* ---------------------------------------------------------------------- *)
+(* LOOPS *)
+
+let rec optimize_for_loop ctx (i,pi) e1 e2 p =
+	let t_void = ctx.t.tvoid in
+	let t_int = ctx.t.tint in
+	let lblock el = Some (mk (TBlock el) t_void p) in
+	let mk_field e n =
+		TField (e,try quick_field e.etype n with Not_found -> assert false)
+	in
+	let gen_int_iter pt f_get f_length =
+		let i = add_local ctx i pt pi in
+		let index = gen_local ctx t_int pi in
+		index.v_meta <- (Meta.ForLoopVariable,[],null_pos) :: index.v_meta;
+		let arr, avars = (match e1.eexpr with
+			| TLocal _ -> e1, None
+			| _ ->
+				let atmp = gen_local ctx e1.etype e1.epos in
+				mk (TLocal atmp) e1.etype e1.epos, (Some (atmp,Some e1))
+		) in
+		let iexpr = mk (TLocal index) t_int p in
+		let e2 = type_expr ctx e2 NoValue in
+		let aget = mk (TVar (i,Some (f_get arr iexpr pt p))) t_void pi in
+		let incr = mk (TUnop (Increment,Prefix,iexpr)) t_int p in
+		let block = match e2.eexpr with
+			| TBlock el -> mk (TBlock (aget :: incr :: el)) t_void e2.epos
+			| _ -> mk (TBlock [aget;incr;e2]) t_void p
+		in
+		let ivar = Some (mk (TConst (TInt 0l)) t_int p) in
+		let elength = f_length arr p in
+		let el = [mk (TWhile (
+				mk (TBinop (OpLt, iexpr, elength)) ctx.t.tbool p,
+				block,
+				NormalWhile
+			)) t_void p;
+		] in
+		let el = match avars with None -> el | Some (v,eo) -> (mk (TVar (v,eo)) t_void p) :: el in
+		let el = (mk (TVar (index,ivar)) t_void p) :: el in
+		lblock el
+	in
+	let get_next_array_element arr iexpr pt p =
+		(mk (TArray (arr,iexpr)) pt p)
+	in
+	let get_array_length arr p =
+		mk (mk_field arr "length") ctx.com.basic.tint p
+	in
+	match e1.eexpr, follow e1.etype with
+	| TNew ({ cl_path = ([],"IntIterator") },[],[i1;i2]) , _ ->
+		let max = (match i1.eexpr , i2.eexpr with
+			| TConst (TInt a), TConst (TInt b) when Int32.compare b a < 0 -> error "Range operator can't iterate backwards" p
+			| _, TConst _ -> None
+			| _ -> Some (gen_local ctx t_int e1.epos)
+		) in
+		let tmp = gen_local ctx t_int pi in
+		tmp.v_meta <- (Meta.ForLoopVariable,[],null_pos) :: tmp.v_meta;
+		let i = add_local ctx i t_int pi in
+		let rec check e =
+			match e.eexpr with
+			| TBinop (OpAssign,{ eexpr = TLocal l },_)
+			| TBinop (OpAssignOp _,{ eexpr = TLocal l },_)
+			| TUnop (Increment,_,{ eexpr = TLocal l })
+			| TUnop (Decrement,_,{ eexpr = TLocal l })  when l == i ->
+				error "Loop variable cannot be modified" e.epos
+			| _ ->
+				Type.iter check e
+		in
+		let e2 = type_expr ctx e2 NoValue in
+		check e2;
+		let etmp = mk (TLocal tmp) t_int p in
+		let incr = mk (TUnop (Increment,Postfix,etmp)) t_int p in
+		let init = mk (TVar (i,Some incr)) t_void pi in
+		let block = match e2.eexpr with
+			| TBlock el -> mk (TBlock (init :: el)) t_void e2.epos
+			| _ -> mk (TBlock [init;e2]) t_void p
+		in
+		(*
+			force locals to be of Int type (to prevent Int/UInt issues)
+		*)
+		let i2 = match follow i2.etype with
+			| TAbstract ({ a_path = ([],"Int") }, []) -> i2
+			| _ -> { i2 with eexpr = TCast(i2, None); etype = t_int }
+		in
+		(match max with
+		| None ->
+			lblock [
+				mk (TVar (tmp,Some i1)) t_void p;
+				mk (TWhile (
+					mk (TBinop (OpLt, etmp, i2)) ctx.t.tbool p,
+					block,
+					NormalWhile
+				)) t_void p;
+			]
+		| Some max ->
+			lblock [
+				mk (TVar (tmp,Some i1)) t_void p;
+				mk (TVar (max,Some i2)) t_void p;
+				mk (TWhile (
+					mk (TBinop (OpLt, etmp, mk (TLocal max) t_int p)) ctx.t.tbool p,
+					block,
+					NormalWhile
+				)) t_void p;
+			])
+	| TArrayDecl el, TInst({ cl_path = [],"Array" },[pt]) ->
+		begin try
+			let num_expr = ref 0 in
+			let rec loop e = match fst e with
+				| EContinue | EBreak ->
+					raise Exit
+				| _ ->
+					incr num_expr;
+					Ast.map_expr loop e
+			in
+			ignore(loop e2);
+			let cost = (List.length el) * !num_expr in
+			let max_cost = try
+				int_of_string (Common.defined_value ctx.com Define.LoopUnrollMaxCost)
+			with Not_found ->
+				250
+			in
+			if cost > max_cost then raise Exit;
+			let el = List.map (fun e ->
+				let v = add_local ctx i pt p in
+				let ev = mk (TVar(v, None)) ctx.t.tvoid p in
+				let typed_e2 = type_expr ctx e2 NoValue in
+				let eloc = mk (TLocal v) v.v_type p in
+				let e_assign = mk (TBinop(OpAssign,eloc,e)) e.etype e.epos in
+				concat ev (concat e_assign typed_e2)
+			) el in
+			Some (mk (TBlock el) ctx.t.tvoid p)
+		with Exit ->
+			gen_int_iter pt get_next_array_element get_array_length
+		end
+	| _ , TInst({ cl_path = [],"Array" },[pt])
+	| _ , TInst({ cl_path = ["flash"],"Vector" },[pt]) ->
+		gen_int_iter pt get_next_array_element get_array_length
+	| _ , TInst({ cl_array_access = Some pt } as c,pl) when (try match follow (PMap.find "length" c.cl_fields).cf_type with TAbstract ({ a_path = [],"Int" },[]) -> true | _ -> false with Not_found -> false) && not (PMap.mem "iterator" c.cl_fields) ->
+		gen_int_iter (apply_params c.cl_params pl pt) get_next_array_element get_array_length
+	| _, TAbstract({a_impl = Some c} as a,tl) ->
+		begin try
+			let cf_length = PMap.find "get_length" c.cl_statics in
+			let get_length e p =
+				make_static_call ctx c cf_length (apply_params a.a_params tl) [e] ctx.com.basic.tint p
+			in
+			begin match follow cf_length.cf_type with
+				| TFun(_,tr) ->
+					begin match follow tr with
+						| TAbstract({a_path = [],"Int"},_) -> ()
+						| _ -> raise Not_found
+					end
+				| _ ->
+					raise Not_found
+			end;
+			begin try
+				(* first try: do we have an @:arrayAccess getter field? *)
+				let todo = mk (TConst TNull) ctx.t.tint p in
+				let cf,_,r,_,_ = AbstractCast.find_array_access_raise ctx a tl todo None p in
+				let get_next e_base e_index t p =
+					make_static_call ctx c cf (apply_params a.a_params tl) [e_base;e_index] r p
+				in
+				gen_int_iter r get_next get_length
+			with Not_found ->
+				(* second try: do we have @:arrayAccess on the abstract itself? *)
+				if not (Meta.has Meta.ArrayAccess a.a_meta) then raise Not_found;
+				(* let's allow this only for core-type abstracts *)
+				if not (Meta.has Meta.CoreType a.a_meta) then raise Not_found;
+				(* in which case we assume that a singular type parameter is the element type *)
+				let t = match tl with [t] -> t | _ -> raise Not_found in
+				gen_int_iter t get_next_array_element get_length
+		end with Not_found ->
+			None
+		end
+	| _ , TInst ({ cl_kind = KGenericInstance ({ cl_path = ["haxe";"ds"],"GenericStack" },[t]) } as c,[]) ->
+		let tcell = (try (PMap.find "head" c.cl_fields).cf_type with Not_found -> assert false) in
+		let i = add_local ctx i t p in
+		let cell = gen_local ctx tcell p in
+		let cexpr = mk (TLocal cell) tcell p in
+		let e2 = type_expr ctx e2 NoValue in
+		let evar = mk (TVar (i,Some (mk (mk_field cexpr "elt") t p))) t_void pi in
+		let enext = mk (TBinop (OpAssign,cexpr,mk (mk_field cexpr "next") tcell p)) tcell p in
+		let block = match e2.eexpr with
+			| TBlock el -> mk (TBlock (evar :: enext :: el)) t_void e2.epos
+			| _ -> mk (TBlock [evar;enext;e2]) t_void p
+		in
+		lblock [
+			mk (TVar (cell,Some (mk (mk_field e1 "head") tcell p))) t_void p;
+			mk (TWhile (
+				mk (TBinop (OpNotEq, cexpr, mk (TConst TNull) tcell p)) ctx.t.tbool p,
+				block,
+				NormalWhile
+			)) t_void p
+		]
+	| _ ->
+		None
+
+let optimize_for_loop_iterator ctx v e1 e2 p =
+	let c,tl = (match follow e1.etype with TInst (c,pl) -> c,pl | _ -> raise Exit) in
+	let _, _, fhasnext = (try raw_class_field (fun cf -> apply_params c.cl_params tl cf.cf_type) c tl "hasNext" with Not_found -> raise Exit) in
+	if fhasnext.cf_kind <> Method MethInline then raise Exit;
+	let tmp = gen_local ctx e1.etype e1.epos in
+	let eit = mk (TLocal tmp) e1.etype p in
+	let ehasnext = make_call ctx (mk (TField (eit,FInstance (c, tl, fhasnext))) (TFun([],ctx.t.tbool)) p) [] ctx.t.tbool p in
+	let enext = mk (TVar (v,Some (make_call ctx (mk (TField (eit,quick_field_dynamic eit.etype "next")) (TFun ([],v.v_type)) p) [] v.v_type p))) ctx.t.tvoid p in
+	let eblock = (match e2.eexpr with
+		| TBlock el -> { e2 with eexpr = TBlock (enext :: el) }
+		| _ -> mk (TBlock [enext;e2]) ctx.t.tvoid p
+	) in
+	mk (TBlock [
+		mk (TVar (tmp,Some e1)) ctx.t.tvoid p;
+		mk (TWhile (ehasnext,eblock,NormalWhile)) ctx.t.tvoid p
+	]) ctx.t.tvoid p
+
+let type_for_loop ctx handle_display it e2 p =
+	let rec loop_ident display e1 = match e1 with
+		| EConst(Ident i),p -> i,p,display
+		| EDisplay(e1,_),_ -> loop_ident true e1
+		| _ -> error "Identifier expected" (pos e1)
+	in
+	let rec loop display e1 = match fst e1 with
+		| EBinop(OpIn,e1,e2) -> loop_ident display e1,e2
+		| EDisplay(e1,_) -> loop true e1
+		| _ -> error "For expression should be 'v in expr'" (snd it)
+	in
+	let (i, pi, display), e1 = loop false it in
+	let e1 = type_expr ctx e1 Value in
+	let old_loop = ctx.in_loop in
+	let old_locals = save_locals ctx in
+	ctx.in_loop <- true;
+	let e2 = Expr.ensure_block e2 in
+	let default() =
+		let t, pt = Typeload.t_iterator ctx in
+		let i = add_local ctx i pt pi in
+		let e1 = (match follow e1.etype with
+		| TMono _
+		| TDynamic _ ->
+			display_error ctx "You can't iterate on a Dynamic value, please specify Iterator or Iterable" e1.epos;
+			e1
+		| TLazy _ ->
+			assert false
+		| _ ->
+			(try
+				AbstractCast.cast_or_unify_raise ctx t e1 p
+			with Error (Unify _,_) ->
+				let acc = !build_call_ref ctx (type_field ctx e1 "iterator" e1.epos MCall) [] Value e1.epos in
+				try
+					unify_raise ctx acc.etype t acc.epos;
+					acc
+				with Error (Unify(l),p) ->
+					display_error ctx "Field iterator has an invalid type" acc.epos;
+					display_error ctx (error_msg (Unify l)) p;
+					mk (TConst TNull) t_dynamic p
+			)
+		) in
+		if display then ignore(handle_display ctx (EConst(Ident i.v_name),i.v_pos) (WithType i.v_type));
+		let e2 = type_expr ctx e2 NoValue in
+		(try optimize_for_loop_iterator ctx i e1 e2 p with Exit -> mk (TFor (i,e1,e2)) ctx.t.tvoid p)
+	in
+	let e = match optimize_for_loop ctx (i,pi) e1 e2 p with
+		| Some e ->
+			if display then ignore(handle_display ctx (EConst(Ident i),pi) Value);
+			e
+		| None -> default()
+	in
+	ctx.in_loop <- old_loop;
+	old_locals();
+	e

+ 2 - 4
src/typing/macroContext.ml

@@ -47,8 +47,6 @@ let macro_interp_on_reuse = ref []
 let macro_interp_reused = ref false
 
 let delayed_macro_result = ref ((fun() -> assert false) : unit -> unit -> Interp.value)
-let unify_call_args_ref = ref (fun _ _ _ _ _ _ _-> assert false)
-let unify_call_args a b c d e f g : (texpr list * t) = !unify_call_args_ref a b c d e f g
 
 let safe_decode v t p f =
 	try
@@ -672,7 +670,7 @@ let type_macro ctx mode cpath f (el:Ast.expr list) p =
 			incr index;
 			(EArray ((EArrayDecl [e],p),(EConst (Int (string_of_int (!index))),p)),p)
 		) el in
-		let elt, _ = try unify_call_args mctx constants (List.map fst eargs) t_dynamic p false false with e -> List.iter (fun f -> f()) (!todo); raise e; in
+		let elt, _ = try Calls.unify_call_args mctx constants (List.map fst eargs) t_dynamic p false false with e -> List.iter (fun f -> f()) (!todo); raise e; in
 		List.iter (fun f -> f()) (!todo);
 		List.map2 (fun (_,mct) e ->
 			let e, et = (match e.eexpr with
@@ -766,7 +764,7 @@ let type_macro ctx mode cpath f (el:Ast.expr list) p =
 
 let call_macro ctx path meth args p =
 	let mctx, (margs,_,mclass,mfield), call = load_macro ctx false path meth p in
-	let el, _ = unify_call_args mctx args margs t_dynamic p false false in
+	let el, _ = Calls.unify_call_args mctx args margs t_dynamic p false false in
 	call (List.map (fun e -> try Interp.make_const e with Exit -> error "Parameter should be a constant" e.epos) el)
 
 let call_init_macro ctx e =

+ 10 - 12
src/typing/matcher.ml

@@ -38,7 +38,7 @@ let make_offset_list left right middle other =
 	(ExtList.List.make left other) @ [middle] @ (ExtList.List.make right other)
 
 let type_field_access ctx ?(resume=false) e name =
-	Typer.acc_get ctx (Typer.type_field ~resume ctx e name e.epos Typer.MGet) e.epos
+	Calls.acc_get ctx (Fields.type_field ~resume ctx e name e.epos TyperBase.MGet) e.epos
 
 let unapply_type_parameters params monos =
 	List.iter2 (fun (_,t1) t2 -> match t2,follow t2 with TMono m1,TMono m2 when m1 == m2 -> Type.unify t1 t2 | _ -> ()) params monos
@@ -108,13 +108,13 @@ module Constructor = struct
 	let to_texpr ctx match_debug p con = match con with
 		| ConEnum(en,ef) ->
 			if Meta.has Meta.FakeEnum en.e_meta then begin
-				let e_mt = !type_module_type_ref ctx (TEnumDecl en) None p in
+				let e_mt = TyperBase.type_module_type ctx (TEnumDecl en) None p in
  				mk (TField(e_mt,FEnum(en,ef))) ef.ef_type p
  			end else if match_debug then mk (TConst (TString ef.ef_name)) ctx.t.tstring p
 			else mk (TConst (TInt (Int32.of_int ef.ef_index))) ctx.t.tint p
 		| ConConst ct -> make_const_texpr ctx.com.basic ct p
 		| ConArray i -> make_int ctx.com.basic i p
-		| ConTypeExpr mt -> Typer.type_module_type ctx mt None p
+		| ConTypeExpr mt -> TyperBase.type_module_type ctx mt None p
 		| ConStatic(c,cf) -> make_static_field c cf p
 		| ConFields _ -> error "Something went wrong" p
 
@@ -250,7 +250,7 @@ module Pattern = struct
 			| Exit | Bad_pattern _ ->
 				begin try
 					let mt = module_type_of_type t in
-					let e_mt = Typer.type_module_type ctx mt None p in
+					let e_mt = TyperBase.type_module_type ctx mt None p in
 					let e = type_field_access ctx ~resume:true e_mt s in
 					let pat = check_expr e in
 					save();
@@ -442,7 +442,7 @@ module Pattern = struct
 				let rec loop in_display e = match e with
 					| (EConst (Ident s),p) ->
 						let v = add_local s p in
-						if in_display then ignore(Typer.display_expr ctx e (mk (TLocal v) v.v_type p) (WithType t) p);
+						if in_display then ignore(TyperDisplay.display_expr ctx e (mk (TLocal v) v.v_type p) (WithType t) p);
 						let pat = make pctx false t e2 in
 						PatBind(v,pat)
 					| (EParenthesis e1,_) -> loop in_display e1
@@ -461,8 +461,8 @@ module Pattern = struct
 				PatExtractor(v,e1,pat)
 			| EDisplay(e,iscall) ->
 				let pat = loop e in
-				let _ = if iscall then Typer.handle_signature_display ctx e (WithType t)
-				else Typer.handle_display ctx e (WithType t) in
+				let _ = if iscall then TyperDisplay.handle_signature_display ctx e (WithType t)
+				else TyperDisplay.handle_display ctx e (WithType t) in
 				pat
 			| _ ->
 				fail()
@@ -535,8 +535,8 @@ module Case = struct
 		List.iter (fun (v,t) -> v.v_type <- t) old_types;
 		save();
 		if ctx.is_display_file && Display.is_display_position p then begin match eo,eo_ast with
-			| Some e,Some e_ast -> ignore(Typer.display_expr ctx e_ast e with_type p)
-			| None,None -> ignore(Typer.display_expr ctx (EBlock [],p) (mk (TBlock []) ctx.t.tvoid p) with_type p)
+			| Some e,Some e_ast -> ignore(TyperDisplay.display_expr ctx e_ast e with_type p)
+			| None,None -> ignore(TyperDisplay.display_expr ctx (EBlock [],p) (mk (TBlock []) ctx.t.tvoid p) with_type p)
 			| _ -> assert false
 		end;
 		{
@@ -1486,6 +1486,4 @@ module Match = struct
 			print_endline "TEXPR END";
 		end;
 		{e with epos = p}
-end
-;;
-Typecore.match_expr_ref := Match.match_expr
+end

+ 1 - 2
src/typing/typeload.ml

@@ -280,7 +280,6 @@ let parse_file com file p =
 let parse_hook = ref parse_file
 let type_module_hook = ref (fun _ _ _ -> None)
 let type_function_params_rec = ref (fun _ _ _ _ -> assert false)
-let return_partial_type = ref false
 
 let type_function_arg ctx t e opt p =
 	if opt then
@@ -294,7 +293,7 @@ let type_var_field ctx t e stat do_display p =
 	if stat then ctx.curfun <- FunStatic else ctx.curfun <- FunMember;
 	let e = if do_display then Display.ExprPreprocessing.process_expr ctx.com e else e in
 	let e = type_expr ctx e (WithType t) in
-	let e = (!cast_or_unify_ref) ctx t e p in
+	let e = AbstractCast.cast_or_unify ctx t e p in
 	match t with
 	| TType ({ t_path = ([],"UInt") },[]) | TAbstract ({ a_path = ([],"UInt") },[]) when stat -> { e with etype = t }
 	| _ -> e

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 86 - 1153
src/typing/typer.ml


+ 146 - 0
src/typing/typerBase.ml

@@ -0,0 +1,146 @@
+open Globals
+open Ast
+open Type
+open Typecore
+open Error
+
+type access_mode =
+	| MGet
+	| MSet
+	| MCall
+
+type access_kind =
+	| AKNo of string
+	| AKExpr of texpr
+	| AKSet of texpr * t * tclass_field
+	| AKInline of texpr * tclass_field * tfield_access * t
+	| AKMacro of texpr * tclass_field
+	| AKUsing of texpr * tclass * tclass_field * texpr
+	| AKAccess of tabstract * tparams * tclass * texpr * texpr
+
+type object_decl_kind =
+	| ODKWithStructure of tanon
+	| ODKWithClass of tclass * tparams
+	| ODKPlain
+
+let build_call_ref : (typer -> access_kind -> expr list -> with_type -> pos -> texpr) ref = ref (fun _ _ _ _ _ -> assert false)
+
+let merge_core_doc ctx c =
+	let c_core = Typeload.load_core_class ctx c in
+	if c.cl_doc = None then c.cl_doc <- c_core.cl_doc;
+	let maybe_merge cf_map cf =
+		if cf.cf_doc = None then try cf.cf_doc <- (PMap.find cf.cf_name cf_map).cf_doc with Not_found -> ()
+	in
+	List.iter (maybe_merge c_core.cl_fields) c.cl_ordered_fields;
+	List.iter (maybe_merge c_core.cl_statics) c.cl_ordered_statics;
+	match c.cl_constructor,c_core.cl_constructor with
+		| Some ({cf_doc = None} as cf),Some cf2 -> cf.cf_doc <- cf2.cf_doc
+		| _ -> ()
+
+let relative_path ctx file =
+	let slashes path = String.concat "/" (ExtString.String.nsplit path "\\") in
+	let fpath = slashes (Path.get_full_path file) in
+	let fpath_lower = String.lowercase fpath in
+	let flen = String.length fpath_lower in
+	let rec loop = function
+		| [] -> file
+		| path :: l ->
+			let spath = String.lowercase (slashes path) in
+			let slen = String.length spath in
+			if slen > 0 && slen < flen && String.sub fpath_lower 0 slen = spath then String.sub fpath slen (flen - slen) else loop l
+	in
+	loop ctx.com.Common.class_path
+
+let mk_infos ctx p params =
+	let file = if ctx.in_macro then p.pfile else if Common.defined ctx.com Define.AbsolutePath then Path.get_full_path p.pfile else relative_path ctx p.pfile in
+	(EObjectDecl (
+		(("fileName",null_pos,NoQuotes) , (EConst (String file) , p)) ::
+		(("lineNumber",null_pos,NoQuotes) , (EConst (Int (string_of_int (Lexer.get_error_line p))),p)) ::
+		(("className",null_pos,NoQuotes) , (EConst (String (s_type_path ctx.curclass.cl_path)),p)) ::
+		if ctx.curfield.cf_name = "" then
+			params
+		else
+			(("methodName",null_pos,NoQuotes), (EConst (String ctx.curfield.cf_name),p)) :: params
+	) ,p)
+
+let rec is_pos_infos = function
+	| TMono r ->
+		(match !r with
+		| Some t -> is_pos_infos t
+		| _ -> false)
+	| TLazy f ->
+		is_pos_infos (lazy_type f)
+	| TType ({ t_path = ["haxe"] , "PosInfos" },[]) ->
+		true
+	| TType (t,tl) ->
+		is_pos_infos (apply_params t.t_params tl t.t_type)
+	| TAbstract({a_path=[],"Null"},[t]) ->
+		is_pos_infos t
+	| _ ->
+		false
+
+let get_this ctx p =
+	match ctx.curfun with
+	| FunStatic ->
+		error "Cannot access this from a static function" p
+	| FunMemberClassLocal | FunMemberAbstractLocal ->
+		let v = match ctx.vthis with
+			| None ->
+				let v = if ctx.curfun = FunMemberAbstractLocal then
+					PMap.find "this" ctx.locals
+				else
+					add_local ctx "`this" ctx.tthis p
+				in
+				ctx.vthis <- Some v;
+				v
+			| Some v ->
+				ctx.locals <- PMap.add v.v_name v ctx.locals;
+				v
+		in
+		mk (TLocal v) ctx.tthis p
+	| FunMemberAbstract ->
+		let v = (try PMap.find "this" ctx.locals with Not_found -> assert false) in
+		mk (TLocal v) v.v_type p
+	| FunConstructor | FunMember ->
+		mk (TConst TThis) ctx.tthis p
+
+let rec type_module_type ctx t tparams p =
+	match t with
+	| TClassDecl {cl_kind = KGenericBuild _} ->
+		let _,_,f = Typeload.build_instance ctx t p in
+		let t = f (match tparams with None -> [] | Some tl -> tl) in
+		let mt = try
+			module_type_of_type t
+		with Exit ->
+			if follow t == t_dynamic then Typeload.load_type_def ctx p { tpackage = []; tname = "Dynamic"; tparams = []; tsub = None }
+			else error "Invalid module type" p
+		in
+		type_module_type ctx mt None p
+	| TClassDecl c ->
+		let t_tmp = class_module_type c in
+		mk (TTypeExpr (TClassDecl c)) (TType (t_tmp,[])) p
+	| TEnumDecl e ->
+		let types = (match tparams with None -> List.map (fun _ -> mk_mono()) e.e_params | Some l -> l) in
+		mk (TTypeExpr (TEnumDecl e)) (TType (e.e_type,types)) p
+	| TTypeDecl s ->
+		let t = apply_params s.t_params (List.map (fun _ -> mk_mono()) s.t_params) s.t_type in
+		if not (Common.defined ctx.com Define.NoDeprecationWarnings) then
+			Display.DeprecationCheck.check_typedef ctx.com s p;
+		(match follow t with
+		| TEnum (e,params) ->
+			type_module_type ctx (TEnumDecl e) (Some params) p
+		| TInst (c,params) ->
+			type_module_type ctx (TClassDecl c) (Some params) p
+		| TAbstract (a,params) ->
+			type_module_type ctx (TAbstractDecl a) (Some params) p
+		| _ ->
+			error (s_type_path s.t_path ^ " is not a value") p)
+	| TAbstractDecl { a_impl = Some c } ->
+		type_module_type ctx (TClassDecl c) tparams p
+	| TAbstractDecl a ->
+		if not (Meta.has Meta.RuntimeValue a.a_meta) then error (s_type_path a.a_path ^ " is not a value") p;
+		let t_tmp = abstract_module_type a [] in
+		mk (TTypeExpr (TAbstractDecl a)) (TType (t_tmp,[])) p
+
+let type_type ctx tpath p =
+	type_module_type ctx (Typeload.load_type_def ctx p { tpackage = fst tpath; tname = snd tpath; tparams = []; tsub = None }) None p

+ 216 - 0
src/typing/typerDisplay.ml

@@ -0,0 +1,216 @@
+open Globals
+open Ast
+open Common.DisplayMode
+open Common
+open Type
+open Typecore
+open TyperBase
+open Fields
+open Calls
+open Error
+
+let rec handle_display ctx e_ast with_type =
+	let old = ctx.in_display,ctx.in_call_args in
+	ctx.in_display <- true;
+	ctx.in_call_args <- false;
+	let e = match e_ast,with_type with
+	| (EConst (Ident "$type"),_),_ ->
+		let mono = mk_mono() in
+		raise (Display.DisplaySignatures ([((["expression",false,mono],mono),Some "Outputs type of argument as a warning and uses argument as value")],0))
+	| (EConst (Ident "trace"),_),_ ->
+		raise (Display.DisplaySignatures ([((["value",false,t_dynamic],ctx.com.basic.tvoid),Some "Print given arguments")],0))
+	| (EConst (Ident "_"),p),WithType t ->
+		mk (TConst TNull) t p (* This is "probably" a bind skip, let's just use the expected type *)
+	| _ -> try
+		type_expr ctx e_ast with_type
+	with Error (Unknown_ident n,_) ->
+		raise (Parser.TypePath ([n],None,false))
+	| Error (Type_not_found (path,_),_) as err ->
+		begin try
+			raise (Display.DisplayFields (DisplayFields.get_submodule_fields ctx path))
+		with Not_found ->
+			raise err
+		end
+	in
+	let p = e.epos in
+	let e = match with_type with
+		| WithType t -> (try AbstractCast.cast_or_unify_raise ctx t e e.epos with Error (Unify l,p) -> e)
+		| _ -> e
+	in
+	ctx.in_display <- fst old;
+	ctx.in_call_args <- snd old;
+	display_expr ctx e_ast e with_type p
+
+and handle_signature_display ctx e_ast with_type =
+	ctx.in_display <- true;
+	let p = pos e_ast in
+	let find_constructor_types t = match follow t with
+		| TInst (c,tl) | TAbstract({a_impl = Some c},tl) ->
+			let ct,cf = get_constructor ctx c tl p in
+			let tl = (ct,cf.cf_doc) :: List.rev_map (fun cf' -> cf'.cf_type,cf.cf_doc) cf.cf_overloads in
+			tl
+		| _ ->
+			[]
+	in
+	let tl,el,p0 = match fst e_ast with
+		| ECall(e1,el) ->
+			let e1 = try
+				type_expr ctx e1 Value
+			with Error (Unknown_ident "trace",_) ->
+				let e = expr_of_type_path (["haxe";"Log"],"trace") p in
+				type_expr ctx e Value
+			in
+			let tl = match e1.eexpr with
+				| TField(_,fa) ->
+					begin match extract_field fa with
+						| Some cf -> (e1.etype,cf.cf_doc) :: List.rev_map (fun cf' -> cf'.cf_type,cf.cf_doc) cf.cf_overloads
+						| None -> [e1.etype,None]
+					end
+				| TConst TSuper ->
+					find_constructor_types e1.etype
+				| _ -> [e1.etype,None]
+			in
+			tl,el,e1.epos
+		| ENew(tpath,el) ->
+			let t = Typeload.load_instance ctx tpath true p in
+			find_constructor_types t,el,pos tpath
+		| _ -> error "Call expected" p
+	in
+	let rec follow_with_callable (t,doc) = match follow t with
+		| TAbstract(a,tl) when Meta.has Meta.Callable a.a_meta -> follow_with_callable (Abstract.get_underlying_type a tl,doc)
+		| TFun(args,ret) -> ((args,ret),doc)
+		| _ -> error ("Not a callable type: " ^ (s_type (print_context()) t)) p
+	in
+	let tl = List.map follow_with_callable tl in
+	let rec loop i p1 el = match el with
+		| (e,p2) :: el ->
+			if Display.is_display_position (punion p1 p2) then i else loop (i + 1) p2 el
+		| [] ->
+			i
+	in
+	let display_arg = loop 0 p0 el in
+	(* If our display position exceeds the argument number we add a null expression in order to make
+	   unify_call_args error out. *)
+	let el = if display_arg >= List.length el then el @ [EConst (Ident "null"),null_pos] else el in
+	let rec loop acc tl = match tl with
+		| (t,doc) :: tl ->
+			let keep (args,r) =
+				begin try
+					let _ = unify_call_args' ctx el args r p false false in
+					true
+				with
+				| Error(Call_error (Not_enough_arguments _),_) -> true
+				| _ -> false
+				end
+			in
+			loop (if keep t then (t,doc) :: acc else acc) tl
+		| [] ->
+			acc
+	in
+	let overloads = match loop [] tl with [] -> tl | tl -> tl in
+	raise (Display.DisplaySignatures(overloads,display_arg))
+
+and display_expr ctx e_ast e with_type p =
+	let get_super_constructor () = match ctx.curclass.cl_super with
+		| None -> error "Current class does not have a super" p
+		| Some (c,params) ->
+			let _, f = get_constructor ctx c params p in
+			f
+	in
+	match ctx.com.display.dms_kind with
+	| DMResolve _ | DMPackage | DMSignature ->
+		assert false
+	| DMType ->
+		let rec loop e = match e.eexpr with
+			| TVar(v,_) -> v.v_type,None
+			| TCall({eexpr = TConst TSuper; etype = t},_) -> t,None
+			| TNew({cl_kind = KAbstractImpl a},tl,_) -> TType(abstract_module_type a tl,[]),None
+			| TNew(c,tl,_) ->
+				let t,_ = get_constructor ctx c tl p in
+				t,None
+			| TTypeExpr (TClassDecl {cl_kind = KAbstractImpl a}) -> TType(abstract_module_type a (List.map snd a.a_params),[]),None
+			| TField(e1,FDynamic "bind") when (match follow e1.etype with TFun _ -> true | _ -> false) -> e1.etype,None
+			| TReturn (Some e1) -> loop e1 (* No point in letting the internal Dynamic surface (issue #5655) *)
+			| TField(_,(FStatic(c,cf) | FInstance(c,_,cf) | FClosure(Some(c,_),cf))) ->
+				if Meta.has Meta.CoreApi c.cl_meta then merge_core_doc ctx c;
+				e.etype,cf.cf_doc
+			| TField(_,FEnum(_,ef)) ->
+				e.etype,ef.ef_doc
+			| _ -> e.etype,None
+		in
+		let t,doc = loop e in
+		raise (Display.DisplayType (t,p,doc))
+	| DMUsage _ ->
+		let rec loop e = match e.eexpr with
+		| TField(_,FEnum(_,ef)) ->
+			ef.ef_meta <- (Meta.Usage,[],p) :: ef.ef_meta;
+		| TField(_,(FAnon cf | FInstance (_,_,cf) | FStatic (_,cf) | FClosure (_,cf))) ->
+			cf.cf_meta <- (Meta.Usage,[],p) :: cf.cf_meta;
+		| TLocal v | TVar(v,_) ->
+			v.v_meta <- (Meta.Usage,[],p) :: v.v_meta;
+		| TTypeExpr mt ->
+			let ti = t_infos mt in
+			ti.mt_meta <- (Meta.Usage,[],p) :: ti.mt_meta;
+		| TNew(c,tl,_) ->
+			begin try
+				let _,cf = get_constructor ctx c tl p in
+				cf.cf_meta <- (Meta.Usage,[],p) :: cf.cf_meta;
+			with Not_found ->
+				()
+			end
+		| TCall({eexpr = TConst TSuper},_) ->
+			begin try
+				let cf = get_super_constructor() in
+				cf.cf_meta <- (Meta.Usage,[],p) :: cf.cf_meta;
+			with Not_found ->
+				()
+			end
+		| TConst TSuper ->
+			begin match ctx.curclass.cl_super with
+				| None -> ()
+				| Some (c,_) -> c.cl_meta <- (Meta.Usage,[],p) :: c.cl_meta;
+			end
+		| TCall(e1,_) ->
+			loop e1
+		| _ ->
+			()
+		in
+		loop e;
+		e
+	| DMPosition ->
+		let rec loop e = match e.eexpr with
+		| TField(_,FEnum(_,ef)) -> [ef.ef_pos]
+		| TField(_,(FAnon cf | FInstance (_,_,cf) | FStatic (_,cf) | FClosure (_,cf))) -> [cf.cf_pos]
+		| TLocal v | TVar(v,_) -> [v.v_pos]
+		| TTypeExpr mt -> [(t_infos mt).mt_pos]
+		| TNew(c,tl,_) ->
+			begin try
+				let _,cf = get_constructor ctx c tl p in
+				[cf.cf_pos]
+			with Not_found ->
+				[]
+			end
+		| TCall({eexpr = TConst TSuper},_) ->
+			begin try
+				let cf = get_super_constructor() in
+				[cf.cf_pos]
+			with Not_found ->
+				[]
+			end
+		| TConst TSuper ->
+			begin match ctx.curclass.cl_super with
+				| None -> []
+				| Some (c,_) -> [c.cl_pos]
+			end
+		| TCall(e1,_) ->
+			loop e1
+		| _ ->
+			[]
+		in
+		let pl = loop e in
+		raise (Display.DisplayPosition pl);
+	| DMToplevel ->
+		raise (Display.DisplayToplevel (DisplayToplevel.collect ctx false))
+	| DMField | DMNone | DMModuleSymbols _ | DMDiagnostics _ | DMStatistics ->
+		let fields = DisplayFields.collect ctx e_ast e with_type p in
+		raise (Display.DisplayFields fields)

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä