Browse Source

allow this + member variables access in local functions

Nicolas Cannasse 14 years ago
parent
commit
a937c322a6
4 changed files with 63 additions and 35 deletions
  1. 2 1
      std/cpp/_std/Hash.hx
  2. 8 2
      typecore.ml
  3. 20 20
      typeload.ml
  4. 33 12
      typer.ml

+ 2 - 1
std/cpp/_std/Hash.hx

@@ -62,9 +62,10 @@
 		var a:Array<String> = [];
 		var a:Array<String> = [];
 		untyped __Internal.__GetFields(a);
 		untyped __Internal.__GetFields(a);
 		var it = a.iterator();
 		var it = a.iterator();
+		var me = this;
 		return untyped {
 		return untyped {
 			hasNext : function() { return it.hasNext(); },
 			hasNext : function() { return it.hasNext(); },
-			next : function() { return  untyped __Internal.__Field(it.next()); }
+			next : function() { return me.__Internal.__Field(it.next()); }
 		};
 		};
 	}
 	}
 
 

+ 8 - 2
typecore.ml

@@ -25,6 +25,12 @@ type type_patch = {
 	mutable tp_meta : Ast.metadata;
 	mutable tp_meta : Ast.metadata;
 }
 }
 
 
+type current_fun =
+	| FMember
+	| FStatic
+	| FConstructor
+	| FMemberLocal
+
 type macro_mode =
 type macro_mode =
 	| MExpr
 	| MExpr
 	| MBuild
 	| MBuild
@@ -68,14 +74,14 @@ and typer = {
 	mutable curmethod : string;
 	mutable curmethod : string;
 	mutable untyped : bool;
 	mutable untyped : bool;
 	mutable in_super_call : bool;
 	mutable in_super_call : bool;
-	mutable in_constructor : bool;
-	mutable in_static : bool;
 	mutable in_loop : bool;
 	mutable in_loop : bool;
 	mutable in_display : bool;
 	mutable in_display : bool;
+	mutable curfun : current_fun;
 	mutable ret : t;
 	mutable ret : t;
 	mutable locals : (string, tvar) PMap.t;
 	mutable locals : (string, tvar) PMap.t;
 	mutable opened : anon_status ref list;
 	mutable opened : anon_status ref list;
 	mutable param_type : t option;
 	mutable param_type : t option;
+	mutable vthis : tvar option;
 }
 }
 
 
 type error_msg =
 type error_msg =

+ 20 - 20
typeload.ml

@@ -29,7 +29,7 @@ let type_function_param ctx t e opt p =
 		t, Some e
 		t, Some e
 
 
 let type_static_var ctx t e p =
 let type_static_var ctx t e p =
-	ctx.in_static <- true;
+	ctx.curfun <- FStatic;
 	let e = type_expr ctx e true in
 	let e = type_expr ctx e true in
 	unify ctx e.etype t p;
 	unify ctx e.etype t p;
 	(* specific case for UInt statics *)
 	(* specific case for UInt statics *)
@@ -522,7 +522,7 @@ let type_type_params ctx path get_params p (n,flags) =
 		delay ctx (fun () -> ignore(!r()));
 		delay ctx (fun () -> ignore(!r()));
 		n, TLazy r
 		n, TLazy r
 
 
-let type_function ctx args ret static constr f p =
+let type_function ctx args ret fmode f p =
 	let locals = save_locals ctx in
 	let locals = save_locals ctx in
 	let fargs = List.map (fun (n,c,t) ->
 	let fargs = List.map (fun (n,c,t) ->
 		let c = (match c with
 		let c = (match c with
@@ -538,11 +538,9 @@ let type_function ctx args ret static constr f p =
 		add_local ctx n t, c
 		add_local ctx n t, c
 	) args in
 	) args in
 	let old_ret = ctx.ret in
 	let old_ret = ctx.ret in
-	let old_static = ctx.in_static in
-	let old_constr = ctx.in_constructor in
+	let old_fun = ctx.curfun in
 	let old_opened = ctx.opened in
 	let old_opened = ctx.opened in
-	ctx.in_static <- static;
-	ctx.in_constructor <- constr;
+	ctx.curfun <- fmode;
 	ctx.ret <- ret;
 	ctx.ret <- ret;
 	ctx.opened <- [];
 	ctx.opened <- [];
 	let e = type_expr ctx (match f.f_expr with None -> error "Function body required" p | Some e -> e) false in
 	let e = type_expr ctx (match f.f_expr with None -> error "Function body required" p | Some e -> e) false in
@@ -563,17 +561,24 @@ let type_function ctx args ret static constr f p =
 		| TFunction _ -> ()
 		| TFunction _ -> ()
 		| _ -> Type.iter loop e
 		| _ -> Type.iter loop e
 	in
 	in
-	if constr && (match ctx.curclass.cl_super with None -> false | Some (cl,_) -> cl.cl_constructor <> None) then
+	if fmode = FConstructor && (match ctx.curclass.cl_super with None -> false | Some (cl,_) -> cl.cl_constructor <> None) then
 		(try
 		(try
 			loop e;
 			loop e;
 			display_error ctx "Missing super constructor call" p
 			display_error ctx "Missing super constructor call" p
 		with
 		with
 			Exit -> ());
 			Exit -> ());
 	locals();
 	locals();
+	let e = if ctx.curfun <> FMember then e else (match ctx.vthis with
+		| None -> e
+		| Some v ->
+			let ev = mk (TVars [v,Some (mk (TConst TThis) ctx.tthis p)]) ctx.t.tvoid p in
+			match e.eexpr with
+			| TBlock l -> { e with eexpr = TBlock (ev::l) }
+			| _ -> mk (TBlock [ev;e]) e.etype p
+	) in
 	List.iter (fun r -> r := Closed) ctx.opened;
 	List.iter (fun r -> r := Closed) ctx.opened;
 	ctx.ret <- old_ret;
 	ctx.ret <- old_ret;
-	ctx.in_static <- old_static;
-	ctx.in_constructor <- old_constr;
+	ctx.curfun <- old_fun;
 	ctx.opened <- old_opened;
 	ctx.opened <- old_opened;
 	e , fargs
 	e , fargs
 
 
@@ -841,6 +846,7 @@ let init_class ctx c p herits fields =
 		let p = f.cff_pos in
 		let p = f.cff_pos in
 		let stat = List.mem AStatic f.cff_access in
 		let stat = List.mem AStatic f.cff_access in
 		let inline = List.mem AInline f.cff_access in
 		let inline = List.mem AInline f.cff_access in
+		let ctx = { ctx with curclass = c; tthis = tthis } in
 		match f.cff_kind with
 		match f.cff_kind with
 		| FVar (t,e) ->
 		| FVar (t,e) ->
 			if not stat && has_field name c.cl_super then error ("Redefinition of variable " ^ name ^ " in subclass is not allowed") p;
 			if not stat && has_field name c.cl_super then error ("Redefinition of variable " ^ name ^ " in subclass is not allowed") p;
@@ -884,7 +890,6 @@ let init_class ctx c p herits fields =
 							ignore(!r())
 							ignore(!r())
 					)
 					)
 				| Some e ->
 				| Some e ->
-					let ctx = { ctx with curclass = c; tthis = tthis } in
 					let r = exc_protect (fun r ->
 					let r = exc_protect (fun r ->
 						r := (fun() -> t);
 						r := (fun() -> t);
 						if ctx.com.verbose then print_endline ("Typing " ^ s_type_path c.cl_path ^ "." ^ name);
 						if ctx.com.verbose then print_endline ("Typing " ^ s_type_path c.cl_path ^ "." ^ name);
@@ -903,7 +908,6 @@ let init_class ctx c p herits fields =
 			end else (match e with
 			end else (match e with
 				| None -> (fun() -> ())
 				| None -> (fun() -> ())
 				| Some e ->
 				| Some e ->
-					let ctx = { ctx with curclass = c; tthis = tthis } in
 					let r = exc_protect (fun r ->
 					let r = exc_protect (fun r ->
 						r := (fun() -> t);
 						r := (fun() -> t);
 						if ctx.com.verbose then print_endline ("Typing " ^ s_type_path c.cl_path ^ "." ^ name);
 						if ctx.com.verbose then print_endline ("Typing " ^ s_type_path c.cl_path ^ "." ^ name);
@@ -960,12 +964,8 @@ let init_class ctx c p herits fields =
 			let parent = (if not stat then get_parent c name else None) in
 			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
 			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;
 			if inline && dynamic then error "You can't have both 'inline' and 'dynamic'" p;
-			let ctx = { ctx with
-				curclass = c;
-				curmethod = name;
-				tthis = tthis;
-				type_params = if stat then params else params @ ctx.type_params;
-			} in
+			ctx.curmethod <- name;
+			ctx.type_params <- if stat then params else params @ ctx.type_params;
 			let ret = type_opt ctx p fd.f_type in
 			let ret = type_opt ctx p fd.f_type in
 			let args = List.map (fun (name,opt,t,c) ->
 			let args = List.map (fun (name,opt,t,c) ->
 				let t, c = type_function_param ctx (type_opt ctx p t) c opt p in
 				let t, c = type_function_param ctx (type_opt ctx p t) c opt p in
@@ -993,7 +993,7 @@ let init_class ctx c p herits fields =
 			let r = exc_protect (fun r ->
 			let r = exc_protect (fun r ->
 				r := (fun() -> t);
 				r := (fun() -> t);
 				if ctx.com.verbose then print_endline ("Typing " ^ s_type_path c.cl_path ^ "." ^ name);
 				if ctx.com.verbose then print_endline ("Typing " ^ s_type_path c.cl_path ^ "." ^ name);
-				let e , fargs = type_function ctx args ret stat constr fd p in
+				let e , fargs = type_function ctx args ret (if constr then FConstructor else if stat then FStatic else FMember) fd p in
 				let f = {
 				let f = {
 					tf_args = fargs;
 					tf_args = fargs;
 					tf_type = ret;
 					tf_type = ret;
@@ -1280,15 +1280,15 @@ let type_module ctx m tdecls loadp =
 		local_using = [];
 		local_using = [];
 		type_params = [];
 		type_params = [];
 		curmethod = "";
 		curmethod = "";
+		curfun = FStatic;
 		untyped = false;
 		untyped = false;
 		in_super_call = false;
 		in_super_call = false;
-		in_constructor = false;
-		in_static = false;
 		in_macro = ctx.in_macro;
 		in_macro = ctx.in_macro;
 		in_display = false;
 		in_display = false;
 		in_loop = false;
 		in_loop = false;
 		opened = [];
 		opened = [];
 		param_type = None;
 		param_type = None;
+		vthis = None;
 	} in
 	} in
 	let delays = ref [] in
 	let delays = ref [] in
 	let get_class name =
 	let get_class name =

+ 33 - 12
typer.ml

@@ -455,6 +455,23 @@ let using_field ctx mode e i p =
 	in
 	in
 	loop ctx.local_using
 	loop ctx.local_using
 
 
+let get_this ctx p =
+	match ctx.curfun with
+	| FStatic -> 
+		error "Cannot access this from a static function" p
+	| FMemberLocal ->
+		if ctx.untyped then display_error ctx "Cannot access this in 'untyped' mode : use either '__this__' or var 'me = this' (transitional)" p;
+		let v = (match ctx.vthis with
+			| None ->
+				let v = alloc_var "me" ctx.tthis in
+				ctx.vthis <- Some v;
+				v
+			| Some v -> v
+		) in		
+		mk (TLocal v) ctx.tthis p
+	| FConstructor | FMember ->
+		mk (TConst TThis) ctx.tthis p
+
 let type_ident ctx i is_type p mode =
 let type_ident ctx i is_type p mode =
 	match i with
 	match i with
 	| "true" ->
 	| "true" ->
@@ -468,9 +485,8 @@ let type_ident ctx i is_type p mode =
 		else
 		else
 			AKNo i
 			AKNo i
 	| "this" ->
 	| "this" ->
-		if ctx.in_static then display_error ctx "Cannot access this from a static function" p;
 		if mode = MGet then
 		if mode = MGet then
-			AKExpr (mk (TConst TThis) ctx.tthis p)
+			AKExpr (get_this ctx p)
 		else
 		else
 			AKNo i
 			AKNo i
 	| "super" ->
 	| "super" ->
@@ -478,7 +494,10 @@ let type_ident ctx i is_type p mode =
 			| None -> error "Current class does not have a superclass" p
 			| None -> error "Current class does not have a superclass" p
 			| Some (c,params) -> TInst(c,params)
 			| Some (c,params) -> TInst(c,params)
 		) in
 		) in
-		if ctx.in_static then error "Cannot access super from a static function" p;
+		(match ctx.curfun with
+		| FMember | FConstructor -> ()
+		| FStatic -> error "Cannot access super inside a static function" p;
+		| FMemberLocal -> error "Cannot access super inside a local function" p);
 		if mode = MSet || not ctx.in_super_call then
 		if mode = MSet || not ctx.in_super_call then
 			AKNo i
 			AKNo i
 		else begin
 		else begin
@@ -496,12 +515,14 @@ let type_ident ctx i is_type p mode =
 		AKExpr (mk (TLocal v) v.v_type p)
 		AKExpr (mk (TLocal v) v.v_type p)
 	with Not_found -> try
 	with Not_found -> try
 		(* member variable lookup *)
 		(* member variable lookup *)
-		if ctx.in_static then raise Not_found;
+		if ctx.curfun = FStatic then raise Not_found;
 		let t , f = class_field ctx.curclass i in
 		let t , f = class_field ctx.curclass i in
-		field_access ctx mode f t (mk (TConst TThis) ctx.tthis p) p
+		field_access ctx mode f t (get_this ctx p) p
 	with Not_found -> try
 	with Not_found -> try
-		if ctx.in_static then raise Not_found;
-		using_field ctx mode (mk (TConst TThis) ctx.tthis p) i p
+		if ctx.curfun = FStatic then raise Not_found;
+		(match using_field ctx mode (mk (TConst TThis) ctx.tthis p) i p with
+		| AKUsing (et,f,_) -> AKUsing (et,f,get_this ctx p)
+		| _ -> assert false)
 	with Not_found -> try
 	with Not_found -> try
 		(* static variable lookup *)
 		(* static variable lookup *)
 		let f = PMap.find i ctx.curclass.cl_statics in
 		let f = PMap.find i ctx.curclass.cl_statics in
@@ -1128,7 +1149,7 @@ and type_ident_noerr ctx i is_type p mode =
 				let t = mk_mono() in
 				let t = mk_mono() in
 				AKExpr (mk (TLocal (alloc_var i t)) t p)
 				AKExpr (mk (TLocal (alloc_var i t)) t p)
 		end else begin
 		end else begin
-			if ctx.in_static && PMap.mem i ctx.curclass.cl_fields then error ("Cannot access " ^ i ^ " in static function") p;
+			if ctx.curfun = FStatic && PMap.mem i ctx.curclass.cl_fields then error ("Cannot access " ^ i ^ " in static function") p;
 			let err = Unknown_ident i in
 			let err = Unknown_ident i in
 			if ctx.in_display then raise (Error (err,p));
 			if ctx.in_display then raise (Error (err,p));
 			display_error ctx (error_msg err) p;
 			display_error ctx (error_msg err) p;
@@ -1546,7 +1567,7 @@ and type_expr ctx ?(need_val=true) (e,p) =
 			| None -> None
 			| None -> None
 			| Some v -> Some (add_local ctx v ft)
 			| Some v -> Some (add_local ctx v ft)
 		) in
 		) in
-		let e , fargs = Typeload.type_function ctx args rt true false f p in
+		let e , fargs = Typeload.type_function ctx args rt (match ctx.curfun with FStatic -> FStatic | _ -> FMemberLocal) f p in
 		let f = {
 		let f = {
 			tf_args = fargs;
 			tf_args = fargs;
 			tf_type = rt;
 			tf_type = rt;
@@ -1719,7 +1740,7 @@ and type_call ctx e el p =
 		else
 		else
 			e
 			e
 	| (EConst (Ident "super"),sp) , el ->
 	| (EConst (Ident "super"),sp) , el ->
-		if ctx.in_static || not ctx.in_constructor then error "Cannot call superconstructor outside class constructor" p;
+		if ctx.curfun <> FConstructor then error "Cannot call superconstructor outside class constructor" p;
 		let el, t = (match ctx.curclass.cl_super with
 		let el, t = (match ctx.curclass.cl_super with
 		| None -> error "Current class does not have a super" p
 		| None -> error "Current class does not have a super" p
 		| Some (c,params) ->
 		| Some (c,params) ->
@@ -2386,8 +2407,7 @@ let rec create com =
 			do_build_instance = Codegen.build_instance;
 			do_build_instance = Codegen.build_instance;
 		};
 		};
 		untyped = false;
 		untyped = false;
-		in_constructor = false;
-		in_static = false;
+		curfun = FStatic;
 		in_loop = false;
 		in_loop = false;
 		in_super_call = false;
 		in_super_call = false;
 		in_display = false;
 		in_display = false;
@@ -2403,6 +2423,7 @@ let rec create com =
 		current = empty;
 		current = empty;
 		opened = [];
 		opened = [];
 		param_type = None;
 		param_type = None;
+		vthis = None;
 	} in
 	} in
 	ctx.g.std <- (try
 	ctx.g.std <- (try
 		Typeload.load_module ctx ([],"StdTypes") null_pos
 		Typeload.load_module ctx ([],"StdTypes") null_pos