Browse Source

completely rewrote compiler priority passes system

Nicolas Cannasse 13 years ago
parent
commit
52434b48dd
5 changed files with 455 additions and 314 deletions
  1. 9 9
      codegen.ml
  2. 26 10
      type.ml
  3. 152 25
      typecore.ml
  4. 227 221
      typeload.ml
  5. 41 49
      typer.ml

+ 9 - 9
codegen.ml

@@ -218,7 +218,7 @@ let make_generic ctx ps pt p =
 	in
 	let name =
 		String.concat "_" (List.map2 (fun (s,_) t ->
-			let path = (match follow t with		
+			let path = (match follow t with
 				| TInst (ct,_) -> ct.cl_path
 				| TEnum (e,_) -> e.e_path
 				| TAbstract (a,_) when has_meta ":runtime_value" a.a_meta -> a.a_path
@@ -489,8 +489,8 @@ let build_instance ctx mtype p =
 					r := (fun() -> t);
 					unify_raise ctx (build_generic ctx c p pl) t p;
 					t
-				) in
-				delay ctx (fun() -> ignore ((!r)()));
+				) "build_generic" in
+				delay ctx PForce (fun() -> ignore ((!r)()));
 				TLazy r
 			| KMacroType ->
 				let r = exc_protect ctx (fun r ->
@@ -498,8 +498,8 @@ let build_instance ctx mtype p =
 					r := (fun() -> t);
 					unify_raise ctx (build_macro_type ctx pl p) t p;
 					t
-				) in
-				delay ctx (fun() -> ignore ((!r)()));
+				) "macro_type" in
+				delay ctx PForce (fun() -> ignore ((!r)()));
 				TLazy r
 			| _ ->
 				TInst (c,pl)
@@ -567,7 +567,7 @@ let remove_generic_base ctx t = match t with
 		(try
 			let (_,_,prec) = get_meta ":?genericRec" c.cl_meta in
 			(try
-				let (_,_,pnew) = get_meta ":?genericT" c.cl_meta in			
+				let (_,_,pnew) = get_meta ":?genericT" c.cl_meta in
 				display_error ctx ("Class " ^ (s_type_path c.cl_path) ^ " was used recursively and cannot use its type parameter") prec;
 				error "Type parameter usage was here" pnew
 			with Not_found _ ->
@@ -603,7 +603,7 @@ let apply_native_paths ctx t =
 		()
 
 (* Adds the __rtti field if required *)
-let add_rtti ctx t = 
+let add_rtti ctx t =
 	let has_rtti c =
 		let rec has_rtti_new c =
 			has_meta ":rttiInfos" c.cl_meta || match c.cl_super with None -> false | Some (csup,_) -> has_rtti_new csup
@@ -1563,10 +1563,10 @@ let rec create_dumpfile acc = function
 	| [] -> assert false
 	| d :: [] ->
 		let ch = open_out (String.concat "/" (List.rev (d :: acc)) ^ ".dump") in
-		let buf = Buffer.create 0 in		
+		let buf = Buffer.create 0 in
 		buf, (fun () ->
 			output_string ch (Buffer.contents buf);
-			close_out ch)		
+			close_out ch)
 	| d :: l ->
 		let dir = String.concat "/" (List.rev (d :: acc)) in
 		if not (Sys.file_exists dir) then Unix.mkdir dir 0o755;

+ 26 - 10
type.ml

@@ -273,7 +273,7 @@ let alloc_var =
 	let uid = ref 0 in
 	(fun n t -> incr uid; { v_name = n; v_type = t; v_id = !uid; v_capture = false; v_extra = None })
 
-let alloc_mid = 
+let alloc_mid =
 	let mid = ref 0 in
 	(fun() -> incr mid; !mid)
 
@@ -320,7 +320,7 @@ let mk_class m path pos =
 		cl_restore = (fun() -> ());
 	}
 
-let module_extra file sign time kind = 
+let module_extra file sign time kind =
 	{
 		m_file = file;
 		m_sign = sign;
@@ -335,6 +335,20 @@ let module_extra file sign time kind =
 		m_macro_calls = [];
 	}
 
+
+let mk_field name t p = {
+	cf_name = name;
+	cf_type = t;
+	cf_pos = p;
+	cf_doc = None;
+	cf_meta = [];
+	cf_public = true;
+	cf_kind = Var { v_read = AccNormal; v_write = AccNormal };
+	cf_expr = None;
+	cf_params = [];
+	cf_overloads = [];
+}
+
 let null_module = {
 		m_id = alloc_mid();
 		m_path = [] , "";
@@ -347,6 +361,8 @@ let null_class =
 	c.cl_private <- true;
 	c
 
+let null_field = mk_field "" t_dynamic Ast.null_pos
+
 let add_dependency m mdep =
 	if m != null_module && m != mdep then m.m_extra.m_deps <- PMap.add mdep.m_id mdep m.m_extra.m_deps
 
@@ -567,7 +583,7 @@ let rec is_nullable ?(no_lazy=false) = function
 (*
 	Type parameters will most of the time be nullable objects, so we don't want to make it hard for users
 	to have to specify Null<T> all over the place, so while they could be a basic type, let's assume they will not.
-	
+
 	This will still cause issues with inlining and haxe.rtti.Generic. In that case proper explicit Null<T> is required to
 	work correctly with basic types. This could still be fixed by redoing a nullability inference on the typed AST.
 
@@ -854,10 +870,10 @@ let rec raw_class_field build_type c i =
 					| _ ->
 						loop ctl
 			in
-			loop tl		
+			loop tl
 		| _ ->
 			if not c.cl_interface then raise Not_found;
-			(* 
+			(*
 				an interface can implements other interfaces without
 				having to redeclare its fields
 			*)
@@ -924,14 +940,14 @@ let rec unify a b =
 		unify_types a b tl1 tl2
 	| TAbstract (a1,tl1) , TAbstract (a2,tl2) when a1 == a2 ->
 		unify_types a b tl1 tl2
-	| TAbstract (a1,tl1) , TAbstract (a2,tl2) ->		
+	| TAbstract (a1,tl1) , TAbstract (a2,tl2) ->
 		if not (List.exists (fun t ->
 			let t = apply_params a1.a_types tl1 t in
 			try unify t b; true with Unify_error _ -> false
 		) a1.a_super) && not (List.exists (fun t ->
 			let t = apply_params a2.a_types tl2 t in
 			try unify a t; true with Unify_error _ -> false
-		) a2.a_sub) then error [cannot_unify a b]		
+		) a2.a_sub) then error [cannot_unify a b]
 	| TInst (c1,tl1) , TInst (c2,tl2) ->
 		let rec loop c tl =
 			if c == c2 then begin
@@ -943,7 +959,7 @@ let rec unify a b =
 					loop cs (List.map (apply_params c.cl_types tl) tls)
 			) || List.exists (fun (cs,tls) ->
 				loop cs (List.map (apply_params c.cl_types tl) tls)
-			) c.cl_implements 
+			) c.cl_implements
 			|| (match c.cl_kind with
 			| KTypeParameter pl -> List.exists (fun t -> match follow t with TInst (cs,tls) -> loop cs (List.map (apply_params c.cl_types tl) tls) | _ -> false) pl
 			| _ -> false)
@@ -987,7 +1003,7 @@ let rec unify a b =
 			PMap.iter (fun n f2 ->
 			try
 				let f1 = PMap.find n a1.a_fields in
-				if not (unify_kind f1.cf_kind f2.cf_kind) then 
+				if not (unify_kind f1.cf_kind f2.cf_kind) then
 					(match !(a1.a_status), f1.cf_kind, f2.cf_kind with
 					| Opened, Var { v_read = AccNormal; v_write = AccNo }, Var { v_read = AccNormal; v_write = AccNormal } ->
 						f1.cf_kind <- f2.cf_kind;
@@ -1088,7 +1104,7 @@ let rec unify a b =
 and unify_types a b tl1 tl2 =
 	List.iter2 (fun t1 t2 ->
 		try
-			type_eq EqRightDynamic t1 t2 
+			type_eq EqRightDynamic t1 t2
 		with Unify_error l ->
 			let err = cannot_unify a b in
 			error (try unify t1 t2; (err :: (Invariant_parameter (t1,t2)) :: l) with _ -> err :: l)

+ 152 - 25
typecore.ml

@@ -36,15 +36,23 @@ type macro_mode =
 	| MBuild
 	| MMacroType
 
-type delayed_functions = {
-	mutable df_normal : (unit -> unit) list;
-	mutable df_late : (unit -> unit) list;
-}
+
+type typer_pass =
+	| PBuildModule			(* build the module structure and setup module type parameters *)
+	| PInitModuleTypes		(* resolve imports and typedefs : dont follow types ! *)
+	| PResolveTypedefs		(* using and other functions that need to follow typededs *)
+	| PBuildClass			(* build the class structure *)
+	| PDefineConstructor	(* add an inherited constructor *)
+	| PTypeField			(* type the class field, allow access to types structures *)
+	| PCheckConstraint		(* perform late constraint checks with inferred types *)
+	| PForce				(* usually ensure that lazy have been evaluated *)
+	| PFinal				(* not used, only mark for finalize *)
 
 type typer_globals = {
 	types_module : (path, path) Hashtbl.t;
 	modules : (path , module_def) Hashtbl.t;
-	mutable delayed : delayed_functions;
+	mutable delayed : (typer_pass * (unit -> unit) list) list;
+	mutable debug_delayed : (typer_pass * ((unit -> unit) * string * typer) list) list;
 	doinline : bool;
 	mutable core_api : typer option;
 	mutable macros : ((unit -> unit) * typer) option;
@@ -64,6 +72,7 @@ type typer_globals = {
 and typer = {
 	(* shared *)
 	com : context;
+	mutable pass : typer_pass;
 	mutable t : basic_types;
 	g : typer_globals;
 	mutable in_macro : bool;
@@ -78,7 +87,7 @@ and typer = {
 	mutable tthis : t;
 	mutable type_params : (string * t) list;
 	(* per-function *)
-	mutable curmethod : string;
+	mutable curfield : tclass_field;
 	mutable untyped : bool;
 	mutable in_super_call : bool;
 	mutable in_loop : bool;
@@ -162,6 +171,17 @@ let rec error_msg = function
 	| Custom s -> s
 	| Stack (m1,m2) -> error_msg m1 ^ "\n" ^ error_msg m2
 
+let pass_name = function
+	| PBuildModule -> "build-module"
+	| PInitModuleTypes -> "init-types"
+	| PResolveTypedefs -> "resolve-types"
+	| PBuildClass -> "build-class"
+	| PDefineConstructor -> "define-constructor"
+	| PTypeField -> "type-field"
+	| PCheckConstraint -> "check-constraint"
+	| PForce -> "force"
+	| PFinal -> "final"
+
 let display_error ctx msg p = ctx.on_error ctx msg p
 
 let error msg p = raise (Error (Custom msg,p))
@@ -187,7 +207,7 @@ let unify_raise ctx t1 t2 p =
 			(* no untyped check *)
 			raise (Error (Unify l,p))
 
-let exc_protect ctx f =
+let exc_protect ctx f (where:string) =
 	let rec r = ref (fun() ->
 		try
 			f r
@@ -223,24 +243,31 @@ let gen_local ctx t =
 let not_opened = ref Closed
 let mk_anon fl = TAnon { a_fields = fl; a_status = not_opened; }
 
-let delay ctx f =
-	ctx.g.delayed.df_normal <- f :: ctx.g.delayed.df_normal
-
-let delay_late ctx f =
-	ctx.g.delayed.df_late <- f :: ctx.g.delayed.df_late
-
-let mk_field name t p = {
-	cf_name = name;
-	cf_type = t;
-	cf_pos = p;
-	cf_doc = None;
-	cf_meta = no_meta;
-	cf_public = true;
-	cf_kind = Var { v_read = AccNormal; v_write = AccNormal };
-	cf_expr = None;
-	cf_params = [];
-	cf_overloads = [];
-}
+let delay ctx p f =
+	let rec loop = function
+		| [] -> [p,[f]]
+		| (p2,l) :: rest ->
+			if p2 = p then
+				(p, f :: l) :: rest
+			else if p2 < p then
+				(p2,l) :: loop rest
+			else
+				(p,[f]) :: (p2,l) :: rest
+	in
+	ctx.g.delayed <- loop ctx.g.delayed
+
+let rec flush_pass ctx p (where:string) =
+	match ctx.g.delayed with
+	| (p2,l) :: rest when p2 <= p ->
+		(match l with
+		| [] ->
+			ctx.g.delayed <- rest;
+		| f :: l ->
+			ctx.g.delayed <- (p2,l) :: rest;
+			f());
+		flush_pass ctx p where
+	| _ ->
+		()
 
 let fake_modules = Hashtbl.create 0
 let create_fake_module ctx file =
@@ -258,3 +285,103 @@ let create_fake_module ctx file =
 	Hashtbl.replace ctx.g.modules mdep.m_path mdep;
 	mdep
 
+(* -------------- debug functions to activate when debugging typer passes ------------------------------- *)
+(*/*
+
+let delay_tabs = ref ""
+
+let context_ident ctx =
+	if Common.defined ctx.com "core_api" then
+		" core "
+	else if Common.defined ctx.com "macro" then
+		"macro "
+	else
+		"  out "
+
+let debug ctx str =
+	if Common.defined ctx.com "cdebug" then prerr_endline (context_ident ctx ^ !delay_tabs ^ str)
+
+let pass_infos ctx p =
+	let inf = Ast.s_type_path ctx.current.m_path in
+	let inf = (match snd ctx.curclass.cl_path with "" -> inf | n when n = snd ctx.current.m_path -> inf | n -> inf ^ "." ^ n) in
+	let inf = (match ctx.curfield.cf_name with "" -> inf | n -> inf ^ ":" ^ n) in
+	let inf = pass_name p ^ " ("  ^ inf ^ ")" in
+	let inf = if ctx.pass > p then inf ^ " ??CURPASS=" ^ pass_name ctx.pass else inf in
+	inf
+
+let delay ctx p f =
+	let inf = pass_infos ctx p in
+	let rec loop = function
+		| [] -> [p,[f,inf,ctx]]
+		| (p2,l) :: rest ->
+			if p2 = p then
+				(p, (f,inf,ctx) :: l) :: rest
+			else if p2 < p then
+				(p2,l) :: loop rest
+			else
+				(p,[f,inf,ctx]) :: (p2,l) :: rest
+	in
+	ctx.g.debug_delayed <- loop ctx.g.debug_delayed;
+	if p <> PForce then debug ctx ("add " ^ inf)
+
+let pending_passes ctx =
+	let rec loop acc = function
+		| (PDefineConstructor,_) :: pl -> loop acc pl (* SKIP SINCE HAVE SPECIAL BEHAVIOR *)
+		| (p,l) :: pl when p < ctx.pass -> loop (acc @ l) pl
+		| _ -> acc
+	in
+	match loop [] ctx.g.debug_delayed with
+	| [] -> ""
+	| l -> " ??PENDING[" ^ String.concat ";" (List.map (fun (_,i,_) -> i) l) ^ "]"
+
+let display_error ctx msg p =
+	debug ctx ("ERROR " ^ msg);
+	display_error ctx msg p
+
+let rec flush_pass ctx p where =
+	let rec loop() =
+		match ctx.g.debug_delayed with
+		| (p2,l) :: rest when p2 <= p ->
+			(match l with
+			| [] ->
+				ctx.g.debug_delayed <- rest
+			| (f,inf,ctx2) :: l ->
+				ctx.g.debug_delayed <- (p2,l) :: rest;
+				let old = !delay_tabs in
+				(match p2 with
+				| PForce | PTypeField -> ()
+				| _ ->
+					debug ctx ("run " ^ inf ^ pending_passes ctx2);
+					delay_tabs := !delay_tabs ^ "\t");
+				(try f() with Fatal_error -> delay_tabs := old; raise Fatal_error | exc when not (Common.defined ctx.com "stack") -> debug ctx ("FATAL " ^ Printexc.to_string exc); delay_tabs := old; raise exc);
+				delay_tabs := old);
+			loop()
+		| _ ->
+			()
+	in
+	match ctx.g.debug_delayed with
+	| (p2,_) :: _ when p2 <= p ->
+		let old = !delay_tabs in
+		debug ctx ("flush " ^ pass_name p ^ "(" ^ where ^ ")");
+		delay_tabs := !delay_tabs ^ "\t";
+		loop();
+		delay_tabs := old;
+		debug ctx "flush-done";
+	| _ ->
+		()
+
+let exc_protect ctx f where =
+	let inf = pass_infos ctx ctx.pass in
+	exc_protect ctx (fun r ->
+		flush_pass ctx PBuildClass where;
+		debug ctx ("run " ^ inf ^ pending_passes ctx);
+		let old = !delay_tabs in
+		delay_tabs := !delay_tabs ^ "\t";
+		let t = f r in
+		delay_tabs := old;
+		t
+	) where
+
+*/*)
+(* --------------------------------------------------- *)
+

+ 227 - 221
typeload.ml

@@ -78,7 +78,7 @@ let rec load_type_def ctx p t =
 			let next() =
 				let t, m = (try
 					t, ctx.g.do_load_module ctx (t.tpackage,t.tname) p
-				with Error (Module_not_found _,p2) as e when p == p2 -> 
+				with Error (Module_not_found _,p2) as e when p == p2 ->
 					match t.tpackage with
 					| "std" :: l ->
 						let t = { t with tpackage = l } in
@@ -139,7 +139,7 @@ let rec load_instance ctx t p allow_no_params =
 		if t.tparams <> [] then error ("Class type parameter " ^ t.tname ^ " can't have parameters") p;
 		pt
 	with Not_found ->
-		let mt = (load_type_def ctx p t) in
+		let mt = load_type_def ctx p t in
 		let is_generic = match mt with TClassDecl {cl_kind = KGeneric} -> true | _ -> false in
 		let types , path , f = ctx.g.do_build_instance ctx mt p in
 		if allow_no_params && t.tparams = [] then begin
@@ -148,7 +148,7 @@ let rec load_instance ctx t p allow_no_params =
 				match follow t with
 				| TInst (c,_) ->
 					let t = mk_mono() in
-					if c.cl_kind <> KTypeParameter [] || is_generic then delay_late ctx (fun() -> check_param_constraints ctx types t (!pl) c p);
+					if c.cl_kind <> KTypeParameter [] || is_generic then delay ctx PCheckConstraint (fun() -> check_param_constraints ctx types t (!pl) c p);
 					t;
 				| _ -> assert false
 			) types;
@@ -183,10 +183,10 @@ let rec load_instance ctx t p allow_no_params =
 				| TInst (c,[]) ->
 					let r = exc_protect ctx (fun r ->
 						r := (fun() -> t);
-						delay_late ctx (fun() -> check_param_constraints ctx types t tparams c p);
+						delay ctx PCheckConstraint (fun() -> check_param_constraints ctx types t tparams c p);
 						t
-					) in
-					delay ctx (fun () -> ignore(!r()));
+					) "constraint" in
+					delay ctx PForce (fun () -> ignore(!r()));
 					TLazy r
 				| _ -> assert false
 			) tparams types in
@@ -372,17 +372,17 @@ let valid_redefinition ctx f1 t1 f2 t2 =
 	let t1, t2 = (match f1.cf_params, f2.cf_params with
 		| [], [] -> t1, t2
 		| l1, l2 when List.length l1 = List.length l2 ->
-			let monos = List.map2 (fun (_,p1) (_,p2) -> 
+			let monos = List.map2 (fun (_,p1) (_,p2) ->
 				match follow p1, follow p2 with
 				| TInst ({ cl_kind = KTypeParameter ct1 } as c1,pl1), TInst ({ cl_kind = KTypeParameter ct2 } as c2,pl2) ->
 					(match ct1, ct2 with
-					| [], [] -> 
+					| [], [] ->
 						let m = mk_mono() in
 						m,m
 					| _, _ when List.length ct1 = List.length ct2 ->
 						(* if same constraints, they are the same type *)
 						List.iter2 (fun t1 t2  ->
-							try 
+							try
 								type_eq EqStrict (apply_params c1.cl_types pl1 t1) (apply_params c2.cl_types pl2 t2)
 							with Unify_error l ->
 								raise (Unify_error (Unify_custom "Constraints differ" :: l))
@@ -418,7 +418,7 @@ let copy_meta meta_src meta_target sl =
 	) meta_src;
 	!meta
 
-let check_overriding ctx c p () =
+let check_overriding ctx c p =
 	match c.cl_super with
 	| None ->
 		(match c.cl_overrides with
@@ -500,7 +500,7 @@ let rec check_interface ctx c p intf params =
 		check_interface ctx c p i2 (List.map (apply_params intf.cl_types params) p2)
 	) intf.cl_implements
 
-let check_interfaces ctx c p () =
+let check_interfaces ctx c p =
 	match c.cl_path with
 	| "Proxy" :: _ , _ -> ()
 	| _ ->
@@ -612,15 +612,16 @@ let set_heritance ctx c herits p =
 		| HImplements t -> HImplements (resolve_imports t)
 		| h -> h
 	) herits in
+	flush_pass ctx PBuildClass "init_class"; (* make sure super classes are fully initialized *)
 	List.iter loop (List.filter (ctx.g.do_inherit ctx c p) herits)
 
 let rec type_type_params ctx path get_params p tp =
 	let n = tp.tp_name in
 	let c = mk_class ctx.current (fst path @ [snd path],n) p in
 	c.cl_types <- List.map (type_type_params ctx c.cl_path get_params p) tp.tp_params;
-	let t = TInst (c,List.map snd c.cl_types) in	
+	let t = TInst (c,List.map snd c.cl_types) in
 	match tp.tp_constraints with
-	| [] -> 
+	| [] ->
 		c.cl_kind <- KTypeParameter [];
 		n, t
 	| _ ->
@@ -629,8 +630,8 @@ let rec type_type_params ctx path get_params p tp =
 			let ctx = { ctx with type_params = ctx.type_params @ get_params() } in
 			c.cl_kind <- KTypeParameter (List.map (load_complex_type ctx p) tp.tp_constraints);
 			t
-		) in
-		delay ctx (fun () -> ignore(!r()));
+		) "constraint" in
+		delay ctx PForce (fun () -> ignore(!r()));
 		n, TLazy r
 
 let type_function_params ctx fd fname p =
@@ -721,6 +722,7 @@ let init_core_api ctx c =
 			c
 	) in
 	let t = load_instance ctx2 { tpackage = fst c.cl_path; tname = snd c.cl_path; tparams = []; tsub = None; } c.cl_pos true in
+	flush_pass ctx2 PFinal "core_final";
 	match t with
 	| TInst (ccore,_) ->
 		(match c.cl_doc with
@@ -741,7 +743,7 @@ let init_core_api ctx c =
 				match f2.cf_kind, f.cf_kind with
 				| Method MethInline, Method MethNormal -> () (* allow to add 'inline' *)
 				| Method MethNormal, Method MethInline -> () (* allow to disable 'inline' *)
-				| _ ->					
+				| _ ->
 					error ("Field " ^ f.cf_name ^ " has different property access than core type") p;
 			end;
 			(match follow f.cf_type, follow f2.cf_type with
@@ -811,7 +813,7 @@ let patch_class ctx c fields =
 		in
 		List.rev (loop [] fields)
 
-let rec string_list_of_expr_path (e,p) = 
+let rec string_list_of_expr_path (e,p) =
 	match e with
 	| EConst (Ident i) -> [i]
 	| EField (e,f) -> f :: string_list_of_expr_path e
@@ -842,13 +844,11 @@ let build_module_def ctx mt meta fvars fbuild =
 		display_error ctx msg p
 
 let init_class ctx c p herits fields =
+	let ctx = { ctx with curclass = c; type_params = c.cl_types; pass = PBuildClass } in
 	incr stats.s_classes_built;
 	let fields = patch_class ctx c fields in
-	let ctx = { ctx with type_params = c.cl_types } in
 	c.cl_extern <- List.mem HExtern herits;
 	c.cl_interface <- List.mem HInterface herits;
-	if has_meta ":generic" c.cl_meta && c.cl_types <> [] then c.cl_kind <- KGeneric;
-	if c.cl_path = (["haxe";"macro"],"MacroType") then c.cl_kind <- KMacroType;
 	set_heritance ctx c herits p;
 	let fields = ref fields in
 	let get_fields() = !fields in
@@ -864,7 +864,7 @@ let init_class ctx c p herits fields =
 		c.cl_extern <- true;
 		List.filter (fun f -> List.mem AStatic f.cff_access) fields, []
 	end else fields, herits in
-	if core_api && not (ctx.com.display || Common.defined ctx.com "dce") then delay ctx (fun() -> init_core_api ctx c);
+	if core_api && not (ctx.com.display || Common.defined ctx.com "dce") then delay ctx PForce (fun() -> init_core_api ctx c);
 	let tthis = TInst (c,List.map snd c.cl_types) in
 	let rec extends_public c =
 		List.exists (fun (c,_) -> c.cl_path = (["haxe"],"Public") || extends_public c) c.cl_implements ||
@@ -914,32 +914,33 @@ let init_class ctx c p herits fields =
 
 	let fields = if not display_file || Common.defined ctx.com "no-copt" then fields else Optimizer.optimize_completion c fields in
 
+	let delayed_expr = ref [] in
+
 	let rec is_full_type t =
 		match t with
 		| TFun (args,ret) -> is_full_type ret && List.for_all (fun (_,_,t) -> is_full_type t) args
 		| TMono r -> (match !r with None -> false | Some t -> is_full_type t)
 		| TAbstract _ | TInst _ | TEnum _ | TLazy _ | TDynamic _ | TAnon _ | TType _ -> true
 	in
-	let bind_type cf r p macro =
+	let bind_type ctx cf r p macro =
 		if ctx.com.display then begin
 			let cp = !Parser.resume_display in
 			if display_file && (cp.pmin = 0 || (p.pmin <= cp.pmin && p.pmax >= cp.pmax)) then begin
 				if macro && not ctx.in_macro then
 					(* force macro system loading of this class in order to get completion *)
-					(fun() -> ignore(ctx.g.do_macro ctx MExpr c.cl_path cf.cf_name [] p))
+					delay ctx PTypeField (fun() -> ignore(ctx.g.do_macro ctx MExpr c.cl_path cf.cf_name [] p))
 				else begin
 					cf.cf_type <- TLazy r;
-					(fun() -> ignore((!r)()))
+					delayed_expr := (ctx,r) :: !delayed_expr;
 				end
 			end else begin
 				if not (is_full_type cf.cf_type) then cf.cf_type <- TLazy r;
-				(fun() -> ())
 			end
 		end else if macro && not ctx.in_macro then
-			(fun () -> ())
+			()
 		else begin
 			cf.cf_type <- TLazy r;
-			(fun () -> ignore(!r()))
+			delayed_expr := (ctx,r) :: !delayed_expr;
 		end
 	in
 
@@ -948,8 +949,7 @@ let init_class ctx c p herits fields =
 		if not stat && has_field cf.cf_name c.cl_super then error ("Redefinition of variable " ^ cf.cf_name ^ " in subclass is not allowed") p;
 		let t = cf.cf_type in
 		match e with
-		| None ->
-			(fun() -> ())
+		| None -> ()
 		| Some e ->
 			let r = exc_protect ctx (fun r ->
 				if not !return_partial_type then begin
@@ -989,8 +989,8 @@ let init_class ctx c p herits fields =
 					cf.cf_type <- t;
 				end;
 				t
-			) in
-			bind_type cf r (snd e) false
+			) "bind_var" in
+			bind_type ctx cf r (snd e) false
 	in
 
 	(* ----------------------- FIELD INIT ----------------------------- *)
@@ -1001,9 +1001,9 @@ let init_class ctx c p herits fields =
 		let stat = List.mem AStatic f.cff_access in
 		let inline = List.mem AInline f.cff_access in
 		let override = List.mem AOverride f.cff_access in
-		let ctx = { ctx with 
-			curclass = c;
+		let ctx = { ctx with
 			tthis = tthis;
+			pass = PTypeField;
 			on_error = (fun ctx msg ep ->
 				ctx.com.error msg ep;
 				(* macros expressions might reference other code, let's recall which class we are actually compiling *)
@@ -1040,8 +1040,9 @@ let init_class ctx c p herits fields =
 				cf_params = [];
 				cf_overloads = [];
 			} in
-			let delay = bind_var ctx cf e stat inline in
-			f, false, cf, delay
+			ctx.curfield <- cf;
+			bind_var ctx cf e stat inline;
+			f, false, cf
 		| FFun fd ->
 			let params = type_function_params ctx fd f.cff_name p in
 			if inline && c.cl_interface then error "You can't declare inline methods in interfaces" p;
@@ -1083,7 +1084,6 @@ let init_class ctx c p herits fields =
 			let parent = (if not stat then get_parent c name else None) in
 			let dynamic = List.mem ADynamic f.cff_access || (match parent with Some { cf_kind = Method MethDynamic } -> true | _ -> false) in
 			if inline && dynamic then error "You can't have both 'inline' and 'dynamic'" p;
-			ctx.curmethod <- name;
 			ctx.type_params <- if stat then params else params @ ctx.type_params;
 			let constr = (name = "new") in
 			let ret = if constr then ctx.t.tvoid else type_opt ctx p fd.f_type in
@@ -1110,6 +1110,7 @@ let init_class ctx c p herits fields =
 				cf_params = params;
 				cf_overloads = [];
 			} in
+			ctx.curfield <- cf;
 			init_meta_overloads ctx cf;
 			let r = exc_protect ctx (fun r ->
 				if not !return_partial_type then begin
@@ -1131,13 +1132,9 @@ let init_class ctx c p herits fields =
 					cf.cf_type <- t;
 				end;
 				t
-			) in
-			let delay = if ((c.cl_extern && not inline) || c.cl_interface) && cf.cf_name <> "__init__" then
-				(fun() -> ())
-			else
-				bind_type cf r (match fd.f_expr with Some e -> snd e | None -> f.cff_pos) is_macro
-			in
-			f, constr, cf, delay
+			) "type_fun" in
+			if not (((c.cl_extern && not inline) || c.cl_interface) && cf.cf_name <> "__init__") then bind_type ctx cf r (match fd.f_expr with Some e -> snd e | None -> f.cff_pos) is_macro;
+			f, constr, cf
 		| FProp (get,set,t,eo) ->
 			if override then error "You cannot override properties" p;
 			let ret = (match t, eo with
@@ -1192,8 +1189,11 @@ let init_class ctx c p herits fields =
 				cf_params = [];
 				cf_overloads = [];
 			} in
-			let delay = bind_var ctx cf eo stat inline in
-			f, false, cf, (fun() -> delay(); (!check_get)(); (!check_set)())
+			ctx.curfield <- cf;
+			bind_var ctx cf eo stat inline;
+			delay ctx PForce (fun() -> (!check_get)());
+			delay ctx PForce (fun() -> (!check_set)());
+			f, false, cf
 	in
 	let rec check_require = function
 		| [] -> None
@@ -1212,10 +1212,10 @@ let init_class ctx c p herits fields =
 			check_require l
 	in
 	let cl_req = check_require c.cl_meta in
-	let fl = List.fold_left (fun acc f ->
+	List.iter (fun f ->
 		try
 			let p = f.cff_pos in
-			let fd , constr, f , delayed = loop_cf f in
+			let fd , constr, f = loop_cf f in
 			let is_static = List.mem AStatic fd.cff_access in
 			if is_static && f.cf_name = "name" && Common.defined ctx.com "js" then error "This identifier cannot be used in Javascript for statics" p;
 			if (is_static || constr) && c.cl_interface && f.cf_name <> "__init__" then error "You can't declare static fields in interfaces" p;
@@ -1238,12 +1238,10 @@ let init_class ctx c p herits fields =
 					c.cl_ordered_fields <- f :: c.cl_ordered_fields;
 					if List.mem AOverride fd.cff_access then c.cl_overrides <- f.cf_name :: c.cl_overrides;
 				end;
-			end;
-			delayed :: acc
+			end
 		with Error (Custom str,p) ->
-			display_error ctx str p;
-			acc
-	) [] fields in
+			display_error ctx str p
+	) fields;
 	c.cl_ordered_statics <- List.rev c.cl_ordered_statics;
 	c.cl_ordered_fields <- List.rev c.cl_ordered_fields;
 	(*
@@ -1258,10 +1256,10 @@ let init_class ctx c p herits fields =
 			| Some cf ->
 				ignore (follow cf.cf_type); (* make sure it's typed *)
 				let args = (match cf.cf_expr with
-					| Some { eexpr = TFunction f } -> 
-						List.map (fun (v,def) -> 
+					| Some { eexpr = TFunction f } ->
+						List.map (fun (v,def) ->
 							(*
-								let's optimize a bit the output by not always copying the default value 
+								let's optimize a bit the output by not always copying the default value
 								into the inherited constructor when it's not necessary for the platform
 							*)
 							match ctx.com.platform, def with
@@ -1289,8 +1287,9 @@ let init_class ctx c p herits fields =
 			(* nothing to do *)
 			()
 	in
-	delay ctx (fun() -> add_constructor c);
-	List.rev fl
+	if c.cl_constructor = None & c.cl_super <> None then delay ctx PDefineConstructor (fun() -> add_constructor c);
+	(* push delays in reverse order so they will be run in correct order *)
+	List.iter (fun (ctx,r) -> delay ctx PTypeField (fun() -> ignore((!r)()))) !delayed_expr
 
 let resolve_typedef t =
 	match t with
@@ -1316,11 +1315,153 @@ let add_module ctx m p =
 	List.iter decl_type m.m_types;
 	Hashtbl.add ctx.g.modules m.m_path m
 
+let init_module_type ctx usings (decl,p) =
+	let get_type name =
+		try List.find (fun t -> snd (t_infos t).mt_path = name) ctx.current.m_types with Not_found -> assert false
+	in
+	match decl with
+	| EImport t ->
+		(match t.tsub with
+		| None ->
+			let md = ctx.g.do_load_module ctx (t.tpackage,t.tname) p in
+			let types = List.filter (fun t -> not (t_infos t).mt_private) md.m_types in
+			ctx.local_types <- ctx.local_types @ types
+		| Some _ ->
+			let t = load_type_def ctx p t in
+			ctx.local_types <- ctx.local_types @ [t]
+		)
+	| EUsing t ->
+		let filter_classes types =
+			let rec loop acc types = match List.rev types with
+				| td :: l ->
+					(match resolve_typedef td with
+					| TClassDecl c ->
+						loop (c :: acc) l
+					| td ->
+						loop acc l)
+				| [] ->
+					acc
+			in
+			loop [] types
+		in
+		(* make sure using are processed in the declaration order *)
+		if !usings = [] then delay ctx PResolveTypedefs (fun() -> List.iter (fun f -> f()) (List.rev !usings));
+		usings := (fun() ->
+			match t.tsub with
+			| None ->
+				let md = ctx.g.do_load_module ctx (t.tpackage,t.tname) p in
+				let types = List.filter (fun t -> not (t_infos t).mt_private) md.m_types in
+				flush_pass ctx PInitModuleTypes "using";
+				ctx.local_using <- ctx.local_using @ (filter_classes types);
+				ctx.local_types <- ctx.local_types @ types
+			| Some _ ->
+				let t = load_type_def ctx p t in
+				flush_pass ctx PInitModuleTypes "using";
+				ctx.local_using <- ctx.local_using @ (filter_classes [t]);
+				ctx.local_types <- ctx.local_types @ [t]
+		) :: !usings
+	| EClass d ->
+		let c = (match get_type d.d_name with TClassDecl c -> c | _ -> assert false) in
+		if has_meta ":generic" c.cl_meta && c.cl_types <> [] then c.cl_kind <- KGeneric;
+		if c.cl_path = (["haxe";"macro"],"MacroType") then c.cl_kind <- KMacroType;
+		(* for debug only - we can't shadow ctx since it will get injected 'using' *)
+		ctx.curclass <- c;
+		delay ctx PForce (fun() -> check_overriding ctx c p);
+		delay ctx PForce (fun() -> check_interfaces ctx c p);
+		delay ctx PBuildClass (fun() -> init_class ctx c p d.d_flags d.d_data);
+		ctx.curclass <- null_class;
+	| EEnum d ->
+		let e = (match get_type d.d_name with TEnumDecl e -> e | _ -> assert false) in
+		let ctx = { ctx with type_params = e.e_types } in
+		let h = (try Some (Hashtbl.find ctx.g.type_patches e.e_path) with Not_found -> None) in
+		(match h with
+		| None -> ()
+		| Some (h,hcl) ->
+			Hashtbl.iter (fun _ _ -> error "Field type patch not supported for enums" e.e_pos) h;
+			e.e_meta <- e.e_meta @ hcl.tp_meta);
+		let constructs = ref d.d_data in
+		let get_constructs() =
+			List.map (fun (c,doc,meta,pl,p) ->
+				{
+					cff_name = c;
+					cff_doc = doc;
+					cff_meta = meta;
+					cff_pos = p;
+					cff_access = [];
+					cff_kind = (match pl with
+						| [] -> FVar (None,None)
+						| _ -> FFun { f_params = []; f_type = None; f_expr = None; f_args = List.map (fun (n,o,t) -> n,o,Some t,None) pl });
+				}
+			) (!constructs)
+		in
+		build_module_def ctx (TEnumDecl e) e.e_meta get_constructs (fun (e,p) ->
+			match e with
+			| EVars [_,Some (CTAnonymous fields),None] ->
+				constructs := List.map (fun f ->
+					(f.cff_name,f.cff_doc,f.cff_meta,(match f.cff_kind with
+					| FVar (None,None) -> []
+					| FFun { f_params = []; f_type = None; f_expr = (None|Some (EBlock [],_)); f_args = pl } -> List.map (fun (n,o,t,_) -> match t with None -> error "Missing function parameter type" f.cff_pos | Some t -> n,o,t) pl
+					| _ -> error "Invalid enum constructor in @:build result" p
+					),f.cff_pos)
+				) fields
+			| _ -> error "Enum build macro must return a single variable with anonymous object fields" p
+		);
+		let et = TEnum (e,List.map snd e.e_types) in
+		let names = ref [] in
+		let index = ref 0 in
+		List.iter (fun (c,doc,meta,t,p) ->
+			let t = (match t with
+				| [] -> et
+				| l ->
+					let pnames = ref PMap.empty in
+					TFun (List.map (fun (s,opt,t) ->
+						if PMap.mem s (!pnames) then error ("Duplicate parameter '" ^ s ^ "' in enum constructor " ^ c) p;
+						pnames := PMap.add s () (!pnames);
+						s, opt, load_type_opt ~opt ctx p (Some t)
+					) l, et)
+			) in
+			if PMap.mem c e.e_constrs then error ("Duplicate constructor " ^ c) p;
+			e.e_constrs <- PMap.add c {
+				ef_name = c;
+				ef_type = t;
+				ef_pos = p;
+				ef_doc = doc;
+				ef_index = !index;
+				ef_meta = meta;
+			} e.e_constrs;
+			incr index;
+			names := c :: !names;
+		) (!constructs);
+		e.e_names <- List.rev !names;
+		e.e_extern <- e.e_extern || e.e_names = [];
+	| ETypedef d ->
+		let t = (match get_type d.d_name with TTypeDecl t -> t | _ -> assert false) in
+		let ctx = { ctx with type_params = t.t_types } in
+		let tt = load_complex_type ctx p d.d_data in
+		(*
+			we exceptionnaly allow follow here because we don't care the type we get as long as it's not our own
+		*)
+		if t.t_type == follow tt then error "Recursive typedef is not allowed" p;
+		(match t.t_type with
+		| TMono r ->
+			(match !r with
+			| None -> r := Some tt;
+			| Some _ -> assert false);
+		| _ -> assert false);
+	| EAbstract d ->
+		let a = (match get_type d.d_name with TAbstractDecl a -> a | _ -> assert false) in
+		let ctx = { ctx with type_params = a.a_types } in
+		List.iter (function
+			| APrivAbstract -> ()
+			| ASubType t -> a.a_sub <- load_complex_type ctx p t :: a.a_sub
+			| ASuperType t -> a.a_super <- load_complex_type ctx p t :: a.a_super
+		) d.d_flags
+
 let type_module ctx m file tdecls loadp =
 	(* PASS 1 : build module structure - does not load any module or type - should be atomic ! *)
 	let decls = ref [] in
 	let make_path name priv =
-		if List.exists (fun t -> snd (t_path t) = name) (!decls) then error ("Type name " ^ name ^ " is already defined in this module") loadp;
+		if List.exists (fun (t,_) -> snd (t_path t) = name) !decls then error ("Type name " ^ name ^ " is already defined in this module") loadp;
 		if priv then (fst m @ ["_" ^ snd m], name) else (fst m, name)
 	in
 	let m = {
@@ -1329,8 +1470,9 @@ let type_module ctx m file tdecls loadp =
 		m_types = [];
 		m_extra = module_extra (Common.unique_full_path file) (Common.get_signature ctx.com) (file_time file) (if ctx.in_macro then MMacro else MCode);
 	} in
-	List.iter (fun (d,p) ->
-		match d with
+	List.iter (fun decl ->
+		let p = snd decl in
+		match fst decl with
 		| EImport _ | EUsing _ -> ()
 		| EClass d ->
 			let priv = List.mem HPrivate d.d_flags in
@@ -1340,7 +1482,7 @@ let type_module ctx m file tdecls loadp =
 			c.cl_private <- priv;
 			c.cl_doc <- d.d_doc;
 			c.cl_meta <- d.d_meta;
-			decls := TClassDecl c :: !decls
+			decls := (TClassDecl c, decl) :: !decls
 		| EEnum d ->
 			let priv = List.mem EPrivate d.d_flags in
 			let path = make_path d.d_name priv in
@@ -1356,7 +1498,7 @@ let type_module ctx m file tdecls loadp =
 				e_constrs = PMap.empty;
 				e_names = [];
 			} in
-			decls := TEnumDecl e :: !decls
+			decls := (TEnumDecl e, decl) :: !decls
 		| ETypedef d ->
 			let priv = List.mem EPrivate d.d_flags in
 			let path = make_path d.d_name priv in
@@ -1370,7 +1512,7 @@ let type_module ctx m file tdecls loadp =
 				t_type = mk_mono();
 				t_meta = d.d_meta;
 			} in
-			decls := TTypeDecl t :: !decls
+			decls := (TTypeDecl t, decl) :: !decls
 	   | EAbstract d ->
 			let priv = List.mem APrivAbstract d.d_flags in
 			let path = make_path d.d_name priv in
@@ -1385,18 +1527,21 @@ let type_module ctx m file tdecls loadp =
 				a_sub = [];
 				a_super = [];
 			} in
-			decls := TAbstractDecl a :: !decls
+			decls := (TAbstractDecl a, decl) :: !decls
 	) tdecls;
-	m.m_types <- List.rev !decls;
+	let decls = List.rev !decls in
+	m.m_types <- List.map fst decls;
 	add_module ctx m loadp;
-	(* PASS 2 : build types structure - does not type any expression ! *)
+	(* define the per-module context for the next pass *)
 	let ctx = {
 		com = ctx.com;
 		g = ctx.g;
 		t = ctx.t;
+		pass = PInitModuleTypes;
 		on_error = (fun ctx msg p -> ctx.com.error msg p);
 		macro_depth = ctx.macro_depth;
-		curclass = ctx.curclass;
+		curclass = null_class;
+		curfield = null_field;
 		tthis = ctx.tthis;
 		ret = ctx.ret;
 		current = m;
@@ -1404,7 +1549,6 @@ let type_module ctx m file tdecls loadp =
 		local_types = ctx.g.std.m_types @ m.m_types;
 		local_using = [];
 		type_params = [];
-		curmethod = "";
 		curfun = FStatic;
 		untyped = false;
 		in_super_call = false;
@@ -1415,164 +1559,25 @@ let type_module ctx m file tdecls loadp =
 		param_type = None;
 		vthis = None;
 	} in
-	let delays = ref [] in
-	let get_class name =
-		let c = List.find (fun d -> match d with TClassDecl { cl_path = _ , n } -> n = name | _ -> false) m.m_types in
-		match c with TClassDecl c -> c | _ -> assert false
-	in
-	let get_enum name =
-		let e = List.find (fun d -> match d with TEnumDecl { e_path = _ , n } -> n = name | _ -> false) m.m_types in
-		match e with TEnumDecl e -> e | _ -> assert false
-	in
-	let get_tdef name =
-		let s = List.find (fun d -> match d with TTypeDecl { t_path = _ , n } -> n = name | _ -> false) m.m_types in
-		match s with TTypeDecl s -> s | _ -> assert false
-	in
-	let get_abstract name =
-		let s = List.find (fun d -> match d with TAbstractDecl { a_path = _ , n } -> n = name | _ -> false) m.m_types in
-		match s with TAbstractDecl a -> a | _ -> assert false
-	in
-	let filter_classes types =
-		let rec loop acc types = match List.rev types with
-			| t :: l ->
-				(match resolve_typedef t with TClassDecl c -> loop (c :: acc) l | _ -> loop acc l)
-			| [] ->
-				acc
-		in
-		loop [] types
-	in
-	(* here is an additional PASS 1 phase, which handle the type parameters declaration, with lazy contraints *)
-	List.iter (fun (d,p) ->
+	(* here is an additional PASS 1 phase, which define the type parameters for all module types.
+	   Constraints are handled lazily (no other type is loaded) because they might be recursive anyway *)
+	List.iter (fun d ->
 		match d with
-		| EImport _ | EUsing _ -> ()
-		| EClass d ->
-			let c = get_class d.d_name in
+		| (TClassDecl c, (EClass d, p)) ->
 			c.cl_types <- List.map (type_type_params ctx c.cl_path (fun() -> c.cl_types) p) d.d_params;
-		| EEnum d ->
-			let e = get_enum d.d_name in
+		| (TEnumDecl e, (EEnum d, p)) ->
 			e.e_types <- List.map (type_type_params ctx e.e_path (fun() -> e.e_types) p) d.d_params;
-		| ETypedef d ->
-			let t = get_tdef d.d_name in
+		| (TTypeDecl t, (ETypedef d, p)) ->
 			t.t_types <- List.map (type_type_params ctx t.t_path (fun() -> t.t_types) p) d.d_params;
-		| EAbstract d ->
-			let a = get_abstract d.d_name in
+		| (TAbstractDecl a, (EAbstract d, p)) ->
 			a.a_types <- List.map (type_type_params ctx a.a_path (fun() -> a.a_types) p) d.d_params;
-	) tdecls;
-	(* back to PASS2 *)
-	List.iter (fun (d,p) ->
-		match d with
-		| EImport t ->
-			(match t.tsub with
-			| None ->
-				let md = ctx.g.do_load_module ctx (t.tpackage,t.tname) p in
-				let types = List.filter (fun t -> not (t_infos t).mt_private) md.m_types in
-				ctx.local_types <- ctx.local_types @ types
-			| Some _ ->
-				let t = load_type_def ctx p t in
-				ctx.local_types <- ctx.local_types @ [t]
-			)
-		| EUsing t ->
-			(match t.tsub with
-			| None ->
-				let md = ctx.g.do_load_module ctx (t.tpackage,t.tname) p in
-				let types = List.filter (fun t -> not (t_infos t).mt_private) md.m_types in
-				ctx.local_using <- ctx.local_using @ (filter_classes types);
-				ctx.local_types <- ctx.local_types @ types
-			| Some _ ->
-				let t = load_type_def ctx p t in
-				ctx.local_using <- ctx.local_using @ (filter_classes [t]);
-				ctx.local_types <- ctx.local_types @ [t])
-		| EClass d ->
-			let c = get_class d.d_name in
-			let checks = if not ctx.com.display then [check_overriding ctx c p; check_interfaces ctx c p] else [] in
-			delays := !delays @ (checks @ init_class ctx c p d.d_flags d.d_data)
-		| EEnum d ->
-			let e = get_enum d.d_name in
-			let ctx = { ctx with type_params = e.e_types } in
-			let h = (try Some (Hashtbl.find ctx.g.type_patches e.e_path) with Not_found -> None) in
-			(match h with
-			| None -> ()
-			| Some (h,hcl) ->
-				Hashtbl.iter (fun _ _ -> error "Field type patch not supported for enums" e.e_pos) h;
-				e.e_meta <- e.e_meta @ hcl.tp_meta);
-			let constructs = ref d.d_data in
-			let get_constructs() =
-				List.map (fun (c,doc,meta,pl,p) ->
-					{
-						cff_name = c;
-						cff_doc = doc;
-						cff_meta = meta;
-						cff_pos = p;
-						cff_access = [];
-						cff_kind = (match pl with
-							| [] -> FVar (None,None)
-							| _ -> FFun { f_params = []; f_type = None; f_expr = None; f_args = List.map (fun (n,o,t) -> n,o,Some t,None) pl });
-					}
-				) (!constructs)
-			in
-			build_module_def ctx (TEnumDecl e) e.e_meta get_constructs (fun (e,p) ->
-				match e with
-				| EVars [_,Some (CTAnonymous fields),None] ->
-					constructs := List.map (fun f ->
-						(f.cff_name,f.cff_doc,f.cff_meta,(match f.cff_kind with
-						| FVar (None,None) -> []
-						| FFun { f_params = []; f_type = None; f_expr = (None|Some (EBlock [],_)); f_args = pl } -> List.map (fun (n,o,t,_) -> match t with None -> error "Missing function parameter type" f.cff_pos | Some t -> n,o,t) pl
-						| _ -> error "Invalid enum constructor in @:build result" p
-						),f.cff_pos)
-					) fields
-				| _ -> error "Enum build macro must return a single variable with anonymous object fields" p
-			);
-			let et = TEnum (e,List.map snd e.e_types) in
-			let names = ref [] in
-			let index = ref 0 in
-			List.iter (fun (c,doc,meta,t,p) ->
-				if c = "name" && Common.defined ctx.com "js" then error "This identifier cannot be used in Javascript" p;
-				let t = (match t with
-					| [] -> et
-					| l ->
-						let pnames = ref PMap.empty in
-						TFun (List.map (fun (s,opt,t) ->
-							if PMap.mem s (!pnames) then error ("Duplicate parameter '" ^ s ^ "' in enum constructor " ^ c) p;
-							pnames := PMap.add s () (!pnames);
-							s, opt, load_type_opt ~opt ctx p (Some t)
-						) l, et)
-				) in
-				if PMap.mem c e.e_constrs then error ("Duplicate constructor " ^ c) p;
-				e.e_constrs <- PMap.add c {
-					ef_name = c;
-					ef_type = t;
-					ef_pos = p;
-					ef_doc = doc;
-					ef_index = !index;
-					ef_meta = meta;
-				} e.e_constrs;
-				incr index;
-				names := c :: !names;
-			) (!constructs);
-			e.e_names <- List.rev !names;
-			e.e_extern <- e.e_extern || e.e_names = [];
-		| ETypedef d ->
-			let t = get_tdef d.d_name in
-			let ctx = { ctx with type_params = t.t_types } in
-			let tt = load_complex_type ctx p d.d_data in
-			if t.t_type == follow tt then error "Recursive typedef is not allowed" p;
-			(match t.t_type with
-			| TMono r ->
-				(match !r with
-				| None -> r := Some tt;
-				| Some _ -> assert false);
-			| _ -> assert false);
-		| EAbstract d ->
-			let a = get_abstract d.d_name in
-			let ctx = { ctx with type_params = a.a_types } in
-			List.iter (function
-				| APrivAbstract -> ()
-				| ASubType t -> a.a_sub <- load_complex_type ctx p t :: a.a_sub
-				| ASuperType t -> a.a_super <- load_complex_type ctx p t :: a.a_super
-			) d.d_flags
-	) tdecls;
-	(* PASS 3 : type checking, delayed until all modules and types are built *)
-	List.iter (delay ctx) (List.rev (!delays));
+		| _ ->
+			assert false
+	) decls;
+	(* enter the next pass *)
+	let usings = ref [] in
+	delay ctx PInitModuleTypes (fun() -> List.iter (init_module_type ctx usings) tdecls);
+	flush_pass ctx (if ctx.pass < PBuildClass then ctx.pass else PBuildClass) "type_module";
 	m
 
 let resolve_module_file com m remap p =
@@ -1665,6 +1670,7 @@ let load_module ctx m p =
 				raise (Forbid_package (inf,p::pl))
 	) in
 	add_dependency ctx.current m2;
+	flush_pass ctx (if ctx.pass < PBuildClass then ctx.pass else PBuildClass) "load_module";
 	m2
 
 ;;

+ 41 - 49
typer.ml

@@ -51,10 +51,10 @@ let mk_infos ctx p params =
 		("fileName" , (EConst (String file) , p)) ::
 		("lineNumber" , (EConst (Int (string_of_int (Lexer.get_error_line p))),p)) ::
 		("className" , (EConst (String (s_type_path ctx.curclass.cl_path)),p)) ::
-		if ctx.curmethod = "" then
+		if ctx.curfield.cf_name = "" then
 			params
 		else
-			("methodName", (EConst (String ctx.curmethod),p)) :: params
+			("methodName", (EConst (String ctx.curfield.cf_name),p)) :: params
 	) ,p)
 
 let check_assign ctx e =
@@ -81,7 +81,7 @@ let rec classify t =
 	| TInst ({ cl_path = ([],"Float") },[]) -> KFloat
 	| TInst ({ cl_path = ([],"String") },[]) -> KString
 	| TAbstract ({ a_path = [],"Int" },[]) -> KInt
-	| TAbstract ({ a_path = [],"Float" },[]) -> KFloat	
+	| TAbstract ({ a_path = [],"Float" },[]) -> KFloat
 	| TInst ({ cl_kind = KTypeParameter ctl },_) when List.exists (fun t -> match classify t with KInt | KFloat -> true | _ -> false) ctl -> KParam t
 	| TMono r when !r = None -> KUnk
 	| TDynamic _ -> KDyn
@@ -107,16 +107,16 @@ let rec is_pos_infos = function
 		false
 
 let add_constraint_checks ctx c pl f tl p =
-	List.iter2 (fun m (name,t) -> 
+	List.iter2 (fun m (name,t) ->
 		match follow t with
 		| TInst ({ cl_kind = KTypeParameter constr },_) when constr <> [] ->
-			let constr = List.map (fun t -> 
+			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 c.cl_types pl t) in
 				t
 			) constr in
-			delay_late ctx (fun() ->
+			delay ctx PCheckConstraint (fun() ->
 				List.iter (fun ct ->
 					try
 						Type.unify m ct
@@ -140,7 +140,7 @@ let class_field ctx c pl name p =
 
 (* checks if class cs(ource) can access field cf of class ct(arget) *)
 let can_access cs ct cf stat =
-	let rec loop ct = 
+	let rec loop ct =
 		((is_parent ct cs) && (PMap.mem cf.cf_name (if stat then ct.cl_statics else ct.cl_fields)))
 	 	|| match ct.cl_super with
 	 	   | Some (ct,_) -> loop ct
@@ -298,7 +298,7 @@ let rec unify_call_params ctx cf el args r p inline =
 			let args, ret = (match Type.field_type o with
 				| TFun (tl,t) -> tl, t
 				| _ -> assert false
-			) in		
+			) in
 			Some (unify_call_params ctx (Some (t, { o with cf_overloads = l })) el args ret p inline)
 		| _ ->
 			None
@@ -438,7 +438,7 @@ let rec type_module_type ctx t tparams p =
 			t_types = [];
 			t_meta = no_meta;
 		} in
-		mk (TTypeExpr (TAbstractDecl a)) (TType (t_tmp,[])) p		
+		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
@@ -539,9 +539,9 @@ let field_access ctx mode f t e p =
 	let fnormal() = AKField ((mk (TField (e,f.cf_name)) t p),f) in
 	let normal() =
 		match follow e.etype with
-		| TAnon a -> 
+		| TAnon a ->
 			(match !(a.a_status) with
-			| EnumStatics e -> 
+			| EnumStatics e ->
 				AKField ((mk (TEnumField (e,f.cf_name)) t p),f)
 			| _ -> fnormal())
 		| _ -> fnormal()
@@ -587,7 +587,7 @@ let field_access ctx mode f t e p =
 			else
 				normal()
 		| AccCall m ->
-			if m = ctx.curmethod && (match e.eexpr with TConst TThis -> true | TTypeExpr (TClassDecl c) when c == ctx.curclass -> true | _ -> false) then
+			if m = ctx.curfield.cf_name && (match e.eexpr with TConst TThis -> true | TTypeExpr (TClassDecl c) when c == ctx.curclass -> true | _ -> false) then
 				let prefix = (match ctx.com.platform with Flash when Common.defined ctx.com "as3" -> "$" | _ -> "") in
 				AKExpr (mk (TField (e,prefix ^ f.cf_name)) t p)
 			else if mode = MSet then
@@ -701,13 +701,13 @@ let type_ident_raise ?(imported_enums=true) ctx i p mode =
 			| Some ({ eexpr = TFunction f } as e) ->
 				(* create a fake class with a fake field to emulate inlining *)
 				let c = mk_class ctx.current (["local"],v.v_name) e.epos in
-				let cf = { (mk_field v.v_name v.v_type e.epos) with cf_params = params; cf_expr = Some e; cf_kind = Method MethInline } in				
+				let cf = { (mk_field v.v_name v.v_type e.epos) with cf_params = params; cf_expr = Some e; cf_kind = Method MethInline } in
 				c.cl_extern <- true;
 				c.cl_fields <- PMap.add cf.cf_name cf PMap.empty;
 				AKInline (mk (TConst TNull) (TInst (c,[])) p, cf, t)
-			| _ -> 
+			| _ ->
 				AKExpr (mk (TLocal v) t p))
-		| _ -> 
+		| _ ->
 			AKExpr (mk (TLocal v) v.v_type p))
 	with Not_found -> try
 		(* member variable lookup *)
@@ -875,7 +875,7 @@ let type_callback ctx e params p =
 					ordered_args @ [type_expr ctx infos true]
 				else if ctx.com.config.pf_pad_nulls then
 					(ordered_args @ [(mk (TConst TNull) t_dynamic p)])
-				else 
+				else
 					ordered_args
 			in
 			loop args [] given_args missing_args a
@@ -1014,7 +1014,7 @@ let type_generic_function ctx (e,cf) el p =
 		(el,ret,e)
 	with Codegen.Generic_Exception (msg,p) ->
 		error msg p)
-	
+
 let rec type_binop ctx op e1 e2 p =
 	match op with
 	| OpAssign ->
@@ -2024,7 +2024,7 @@ and type_expr ctx ?(need_val=true) (e,p) =
 		let el, c , params = (match follow t with
 		| TInst ({cl_kind = KTypeParameter tl} as c,params) ->
 			(* first check field parameters, then class parameters *)
-			let cf = PMap.find ctx.curmethod (match ctx.curfun with FStatic -> ctx.curclass.cl_statics | _ -> ctx.curclass.cl_fields) in
+			let cf = PMap.find ctx.curfield.cf_name (match ctx.curfun with FStatic -> ctx.curclass.cl_statics | _ -> ctx.curclass.cl_fields) in
 			(try
 				let tt = List.assoc (snd c.cl_path) cf.cf_params in
 				if not (type_iseq tt t) then raise Not_found;
@@ -2032,7 +2032,7 @@ and type_expr ctx ?(need_val=true) (e,p) =
 				let tt = List.assoc (snd c.cl_path) ctx.type_params in
 				if not (type_iseq tt t) then raise Not_found;
 				if not (has_meta ":?genericT" ctx.curclass.cl_meta) then ctx.curclass.cl_meta <- (":?genericT",[],p) :: ctx.curclass.cl_meta;
-			with Not_found ->			
+			with Not_found ->
 				error "Only generic type parameters can be constructed" p);
 			let el = List.map (type_expr ctx) el in
 			let ctor = mk_field "new" (tfun (List.map (fun e -> e.etype) el) ctx.t.tvoid) p in
@@ -2061,7 +2061,7 @@ and type_expr ctx ?(need_val=true) (e,p) =
 				(try
 					fst (unify_call_params ctx (Some (TInst(c,params),f)) el args r p false)
 				with Error (e,p) ->
-					display_error ctx (error_msg e) p; 
+					display_error ctx (error_msg e) p;
 					[])
 			| _ ->
 				error "Constructor is not a function" p
@@ -2190,7 +2190,7 @@ and type_expr ctx ?(need_val=true) (e,p) =
 			| _ ->
 				t
 		in
-		let rec get_fields t = 
+		let rec get_fields t =
 			match follow t with
 			| TInst (c,params) ->
 				let priv = is_parent c ctx.curclass in
@@ -2400,16 +2400,16 @@ and build_call ctx acc el twith p =
 	| AKExpr e | AKField (e,_) ->
 		let el , t, e = (match follow e.etype with
 		| TFun (args,r) ->
-			let fopts = (match acc with 
+			let fopts = (match acc with
 				| AKField (e,f) ->
-					(match e.eexpr with 
+					(match e.eexpr with
 					| TField (e,_) -> fopts e.etype f
 					| _ -> None)
 				| _ ->
 					None
 			) in
 			(match fopts,acc with
-				| Some (_,cf),AKField({eexpr = TField(e,_)},_) when has_meta ":generic" cf.cf_meta -> 
+				| Some (_,cf),AKField({eexpr = TField(e,_)},_) when has_meta ":generic" cf.cf_meta ->
 					type_generic_function ctx (e,cf) el p
 				| _ ->
 					let el, tfunc = unify_call_params ctx fopts el args r p false in
@@ -2464,20 +2464,8 @@ let get_main ctx =
 		let emain = type_type ctx cl null_pos in
 		Some (mk (TCall (mk (TField (emain,"main")) ft null_pos,[])) r null_pos)
 
-let rec finalize ctx =
-	match ctx.g.delayed.df_normal,ctx.g.delayed.df_late with
-	| [],[] ->
-		(* at last done *)
-		()
-	| [],l ->
-		(* normal done, but late remains *)
-		ctx.g.delayed.df_late <- [];
-		List.iter (fun f -> f()) l;
-		finalize ctx		
-	| l,_ ->
-		ctx.g.delayed.df_normal <- [];
-		List.iter (fun f -> f()) l;
-		finalize ctx
+let finalize ctx =
+	flush_pass ctx PFinal "final"
 
 type state =
 	| Generating
@@ -2729,12 +2717,14 @@ let make_macro_api ctx p =
 		Interp.get_display = (fun s ->
 			let is_displaying = ctx.com.display in
 			let old_resume = !Parser.resume_display in
+			let old_error = ctx.on_error in
 			let restore () =
 				if not is_displaying then begin
 					ctx.com.defines <- PMap.remove "display" ctx.com.defines;
-					ctx.com.display <- false;
+					ctx.com.display <- false
 				end;
-				Parser.resume_display := old_resume
+				Parser.resume_display := old_resume;
+				ctx.on_error <- old_error;
 			in
 			(* temporarily enter display mode with a fake position *)
 			if not is_displaying then begin
@@ -2746,6 +2736,7 @@ let make_macro_api ctx p =
 				Ast.pmin = 0;
 				Ast.pmax = 0;
 			};
+			ctx.on_error <- (fun ctx msg p -> raise (Error(Custom msg,p)));
 			let str = try
 				let e = parse_expr_string s Ast.null_pos true in
 				let e = Optimizer.optimize_completion_expr e in
@@ -2753,7 +2744,7 @@ let make_macro_api ctx p =
 				"NO COMPLETION"
 			with DisplayFields fields ->
 				let pctx = print_context() in
-				String.concat "," (List.map (fun (f,t,_) -> f ^ ":" ^ s_type pctx t) fields)				
+				String.concat "," (List.map (fun (f,t,_) -> f ^ ":" ^ s_type pctx t) fields)
 			| DisplayTypes tl ->
 				let pctx = print_context() in
 				String.concat "," (List.map (s_type pctx) tl)
@@ -2855,7 +2846,7 @@ let make_macro_api ctx p =
 					Some (TInst (ctx.curclass,[]))
 		);
 		Interp.get_local_method = (fun() ->
-			ctx.curmethod;
+			ctx.curfield.cf_name;
 		);
 		Interp.get_local_using = (fun() ->
 			ctx.local_using;
@@ -2887,7 +2878,7 @@ let make_macro_api ctx p =
 		);
 	}
 
-let flush_macro_context mctx ctx = 
+let flush_macro_context mctx ctx =
 	finalize ctx;
 	let _, types, modules = generate ctx in
 	ctx.com.types <- types;
@@ -2949,7 +2940,9 @@ let load_macro ctx cpath f p =
 	ctx2.local_types <- mloaded.m_types;
 	add_dependency ctx.current mloaded;
 	let cl, meth = (match Typeload.load_instance ctx2 { tpackage = fst cpath; tname = snd cpath; tparams = []; tsub = None } p true with
-		| TInst (c,_) -> c, (try PMap.find f c.cl_statics with Not_found -> error ("Method " ^ f ^ " not found on class " ^ s_type_path cpath) p)
+		| TInst (c,_) ->
+			finalize ctx2;
+			c, (try PMap.find f c.cl_statics with Not_found -> error ("Method " ^ f ^ " not found on class " ^ s_type_path cpath) p)
 		| _ -> error "Macro should be called on a class" p
 	) in
 	let meth = (match follow meth.cf_type with TFun (args,ret) -> args,ret,cl,meth | _ -> error "Macro call should be a method" p) in
@@ -3140,10 +3133,8 @@ let rec create com =
 			modules = Hashtbl.create 0;
 			types_module = Hashtbl.create 0;
 			type_patches = Hashtbl.create 0;
-			delayed = {
-				df_normal = [];
-				df_late = [];
-			};
+			delayed = [];
+			debug_delayed = [];
 			doinline = not (Common.defined com "no_inline" || com.display);
 			hook_generate = [];
 			get_build_infos = (fun() -> None);
@@ -3155,6 +3146,7 @@ let rec create com =
 			do_optimize = Optimizer.reduce_expression;
 			do_build_instance = Codegen.build_instance;
 		};
+		pass = PBuildModule;
 		macro_depth = 0;
 		untyped = false;
 		curfun = FStatic;
@@ -3167,8 +3159,8 @@ let rec create com =
 		local_types = [];
 		local_using = [];
 		type_params = [];
-		curmethod = "";
 		curclass = null_class;
+		curfield = null_field;
 		tthis = mk_mono();
 		current = null_module;
 		opened = [];