瀏覽代碼

bugfix with non-constant enums in switches

Nicolas Cannasse 15 年之前
父節點
當前提交
0f0dff3bbe
共有 3 個文件被更改,包括 34 次插入21 次删除
  1. 1 0
      doc/CHANGES.txt
  2. 24 15
      optimizer.ml
  3. 9 6
      typer.ml

+ 1 - 0
doc/CHANGES.txt

@@ -24,6 +24,7 @@
 	all : fixed haxe.rtti.Generic on interfaces
 	all : fixed haxe.rtti.Generic on interfaces
 	php : fixed issue with Reflect.callMethod
 	php : fixed issue with Reflect.callMethod
 	php : fixed issue with PHP reserved word used in callbacks
 	php : fixed issue with PHP reserved word used in callbacks
+	all : bugfix with non-constant enums in switches
 
 
 2009-07-26: 2.04
 2009-07-26: 2.04
 	flash9 : fixed get_full_path error with -D fdb
 	flash9 : fixed get_full_path error with -D fdb

+ 24 - 15
optimizer.ml

@@ -102,11 +102,11 @@ let type_inline ctx cf f ethis params tret p =
 			let old = save_locals ctx in
 			let old = save_locals ctx in
 			let t = ref e.etype in
 			let t = ref e.etype in
 			let rec loop = function
 			let rec loop = function
-				| [] when term -> 
+				| [] when term ->
 					t := mk_mono();
 					t := mk_mono();
 					[mk (TConst TNull) (!t) p]
 					[mk (TConst TNull) (!t) p]
 				| [] -> []
 				| [] -> []
-				| [e] -> 
+				| [e] ->
 					let e = map term e in
 					let e = map term e in
 					if term then t := e.etype;
 					if term then t := e.etype;
 					[e]
 					[e]
@@ -171,7 +171,7 @@ let type_inline ctx cf f ethis params tret p =
 	let init = (match vars with [] -> None | l -> Some (mk (TVars (List.rev l)) ctx.api.tvoid p)) in
 	let init = (match vars with [] -> None | l -> Some (mk (TVars (List.rev l)) ctx.api.tvoid p)) in
 	if Common.defined ctx.com "js" && (init <> None || !has_vars) then
 	if Common.defined ctx.com "js" && (init <> None || !has_vars) then
 		None
 		None
-	else 
+	else
 		let e = (match e.eexpr, init with
 		let e = (match e.eexpr, init with
 			| TBlock [e] , None -> { e with etype = tret; }
 			| TBlock [e] , None -> { e with etype = tret; }
 			| _ , None -> { e with etype = tret; }
 			| _ , None -> { e with etype = tret; }
@@ -183,13 +183,13 @@ let type_inline ctx cf f ethis params tret p =
 		match cf.cf_params, tparams with
 		match cf.cf_params, tparams with
 		| [], ([],_) -> Some e
 		| [], ([],_) -> Some e
 		| _ ->
 		| _ ->
-			let pmonos = List.map (fun _ -> mk_mono()) cf.cf_params in			
+			let pmonos = List.map (fun _ -> mk_mono()) cf.cf_params in
 			let tmonos = snd tparams @ pmonos in
 			let tmonos = snd tparams @ pmonos in
 			let tparams = fst tparams @ cf.cf_params in
 			let tparams = fst tparams @ cf.cf_params in
 			let mt = apply_params tparams tmonos cf.cf_type in
 			let mt = apply_params tparams tmonos cf.cf_type in
 			unify_raise ctx mt (TFun (List.map (fun e -> "",false,e.etype) params,tret)) p;
 			unify_raise ctx mt (TFun (List.map (fun e -> "",false,e.etype) params,tret)) p;
 			(*
 			(*
-				this is very expensive since we are building the substitution list for 
+				this is very expensive since we are building the substitution list for
 				every expression, but hopefully in such cases the expression size is small
 				every expression, but hopefully in such cases the expression size is small
 			*)
 			*)
 			let map_type t = apply_params tparams tmonos t in
 			let map_type t = apply_params tparams tmonos t in
@@ -253,7 +253,7 @@ let optimize_for_loop ctx i e1 e2 p =
 					NormalWhile
 					NormalWhile
 				)) t_void p;
 				)) t_void p;
 			])
 			])
-	| _ , TInst({ cl_path = [],"Array" },[pt]) 
+	| _ , TInst({ cl_path = [],"Array" },[pt])
 	| _ , TInst({ cl_path = ["flash"],"Vector" },[pt]) ->
 	| _ , TInst({ cl_path = ["flash"],"Vector" },[pt]) ->
 		let i = add_local ctx i pt in
 		let i = add_local ctx i pt in
 		let index = gen_local ctx t_int in
 		let index = gen_local ctx t_int in
@@ -314,7 +314,7 @@ let rec reduce_loop com is_sub e =
 	in
 	in
 	let is_text_platform() =
 	let is_text_platform() =
 		match com.platform with
 		match com.platform with
-		| Js | Php -> true 
+		| Js | Php -> true
 		| Neko | Flash | Flash9 | Cross | Cpp -> false
 		| Neko | Flash | Flash9 | Cross | Cpp -> false
 	in
 	in
 	let e = Type.map_expr (reduce_loop com (match e.eexpr with TBlock _ -> false | _ -> true)) e in
 	let e = Type.map_expr (reduce_loop com (match e.eexpr with TBlock _ -> false | _ -> true)) e in
@@ -325,7 +325,7 @@ let rec reduce_loop com is_sub e =
 		(match flag with
 		(match flag with
 		| NormalWhile -> { e with eexpr = TBlock [] } (* erase sub *)
 		| NormalWhile -> { e with eexpr = TBlock [] } (* erase sub *)
 		| DoWhile -> e) (* we cant remove while since sub can contain continue/break *)
 		| DoWhile -> e) (* we cant remove while since sub can contain continue/break *)
-	| TBinop (op,e1,e2) ->		
+	| TBinop (op,e1,e2) ->
 		(match e1.eexpr, e2.eexpr with
 		(match e1.eexpr, e2.eexpr with
 		| TConst (TInt 0l) , _ when op = OpAdd -> e2
 		| TConst (TInt 0l) , _ when op = OpAdd -> e2
 		| TConst (TInt 1l) , _ when op = OpMult -> e2
 		| TConst (TInt 1l) , _ when op = OpMult -> e2
@@ -387,7 +387,7 @@ let rec reduce_loop com is_sub e =
 			| OpGte -> ebool ((>=) 0)
 			| OpGte -> ebool ((>=) 0)
 			| OpLt -> ebool ((<) 0)
 			| OpLt -> ebool ((<) 0)
 			| OpLte -> ebool ((<=) 0)
 			| OpLte -> ebool ((<=) 0)
-			| _ -> e)			
+			| _ -> e)
 		| TConst (TBool a), TConst (TBool b) ->
 		| TConst (TBool a), TConst (TBool b) ->
 			let ebool f =
 			let ebool f =
 				{ e with eexpr = TConst (TBool (f a b)) }
 				{ e with eexpr = TConst (TBool (f a b)) }
@@ -416,8 +416,8 @@ let rec reduce_loop com is_sub e =
 		| _, TCall ({ eexpr = TEnumField _ },_) | TCall ({ eexpr = TEnumField _ },_), _ ->
 		| _, TCall ({ eexpr = TEnumField _ },_) | TCall ({ eexpr = TEnumField _ },_), _ ->
 			(match op with
 			(match op with
 			| OpAssign -> e
 			| OpAssign -> e
-			| _ -> 
-				error "You cannot directly compare enums with arguments. Use either 'switch' or 'Type.enumEq'" e.epos)			
+			| _ ->
+				error "You cannot directly compare enums with arguments. Use either 'switch' or 'Type.enumEq'" e.epos)
 		| _ -> e)
 		| _ -> e)
 	| TUnop (op,flag,esub) ->
 	| TUnop (op,flag,esub) ->
 		(match op, esub.eexpr with
 		(match op, esub.eexpr with
@@ -446,7 +446,7 @@ let rec reduce_loop com is_sub e =
 			| TParenthesis _ | TIf (_,_,Some _) | TSwitch _ | TMatch _ | TTry _ ->
 			| TParenthesis _ | TIf (_,_,Some _) | TSwitch _ | TMatch _ | TTry _ ->
 				(* might only cause issues if some 'return' found in the first expression of if/switch/match *)
 				(* might only cause issues if some 'return' found in the first expression of if/switch/match *)
 				Type.map_expr (build term) e
 				Type.map_expr (build term) e
-			| TReturn eo ->				
+			| TReturn eo ->
 				if not term then raise Exit;
 				if not term then raise Exit;
 				(match eo with
 				(match eo with
 				| None -> { e with eexpr = TBlock [] }
 				| None -> { e with eexpr = TBlock [] }
@@ -459,8 +459,8 @@ let rec reduce_loop com is_sub e =
 			let body = (match body.eexpr with TBlock el -> el | _ -> [body]) in
 			let body = (match body.eexpr with TBlock el -> el | _ -> [body]) in
 			let body = (match el with
 			let body = (match el with
 				| [] -> body
 				| [] -> body
-				| _ ->					
-					if is_sub && is_text_platform() then raise Exit; 
+				| _ ->
+					if is_sub && is_text_platform() then raise Exit;
 					mk (TVars (List.map2 (fun (p,_,t) e -> p,t,Some e) func.tf_args el)) com.type_api.tvoid e.epos :: body
 					mk (TVars (List.map2 (fun (p,_,t) e -> p,t,Some e) func.tf_args el)) com.type_api.tvoid e.epos :: body
 			) in
 			) in
 			{ e with eexpr = TBlock body }
 			{ e with eexpr = TBlock body }
@@ -468,7 +468,16 @@ let rec reduce_loop com is_sub e =
 			Exit -> e)
 			Exit -> e)
 	| TParenthesis ({ eexpr = TConst _ } as ec) | TBlock [{ eexpr = TConst _ } as ec] ->
 	| TParenthesis ({ eexpr = TConst _ } as ec) | TBlock [{ eexpr = TConst _ } as ec] ->
 		{ ec with epos = e.epos }
 		{ ec with epos = e.epos }
-	| _ -> 
+	| TSwitch (_,cases,_) ->
+		List.iter (fun (cl,_) ->
+			List.iter (fun e ->
+				match e.eexpr with
+				| TCall ({ eexpr = TEnumField _ },_) -> error "Not-constant enum in switch cannot be matched" e.epos
+				| _ -> ()
+			) cl
+		) cases;
+		e
+	| _ ->
 		e
 		e
 
 
 let reduce_expression com e =
 let reduce_expression com e =

+ 9 - 6
typer.ml

@@ -319,17 +319,17 @@ let rec acc_get ctx g p =
 			loop e
 			loop e
 
 
 let field_access ctx mode f t e p =
 let field_access ctx mode f t e p =
+	let normal() = AccExpr (mk (TField (e,f.cf_name)) t p) in
 	match (match mode with MGet | MCall -> f.cf_get | MSet -> f.cf_set) with
 	match (match mode with MGet | MCall -> f.cf_get | MSet -> f.cf_set) with
 	| NoAccess ->
 	| NoAccess ->
-		let normal = AccExpr (mk (TField (e,f.cf_name)) t p) in
 		(match follow e.etype with
 		(match follow e.etype with
-		| TInst (c,_) when is_parent c ctx.curclass -> normal
+		| TInst (c,_) when is_parent c ctx.curclass -> normal()
 		| TAnon a ->
 		| TAnon a ->
 			(match !(a.a_status) with
 			(match !(a.a_status) with
-			| Statics c2 when ctx.curclass == c2 -> normal
-			| _ -> if ctx.untyped then normal else AccNo f.cf_name)
+			| Statics c2 when ctx.curclass == c2 -> normal()
+			| _ -> if ctx.untyped then normal() else AccNo f.cf_name)
 		| _ ->
 		| _ ->
-			if ctx.untyped then normal else AccNo f.cf_name)
+			if ctx.untyped then normal() else AccNo f.cf_name)
 	| MethodAccess false when not ctx.untyped ->
 	| MethodAccess false when not ctx.untyped ->
 		error "Cannot rebind this method : please use 'dynamic' before method declaration" p
 		error "Cannot rebind this method : please use 'dynamic' before method declaration" p
 	| NormalAccess | MethodAccess _ ->
 	| NormalAccess | MethodAccess _ ->
@@ -340,7 +340,10 @@ let field_access ctx mode f t e p =
 		(match mode, f.cf_set with
 		(match mode, f.cf_set with
 		| MGet, MethodAccess _ -> AccExpr (mk (TClosure (e,f.cf_name)) t p)
 		| MGet, MethodAccess _ -> AccExpr (mk (TClosure (e,f.cf_name)) t p)
 		| MGet, NoAccess | MGet, NeverAccess when (match follow t with TFun _ -> true | _ -> false) -> AccExpr (mk (TClosure (e,f.cf_name)) t p)
 		| MGet, NoAccess | MGet, NeverAccess when (match follow t with TFun _ -> true | _ -> false) -> AccExpr (mk (TClosure (e,f.cf_name)) t p)
-		| _ -> AccExpr (mk (TField (e,f.cf_name)) t p))
+		| _ ->
+			match follow e.etype with
+			| TAnon a -> (match !(a.a_status) with EnumStatics e -> AccExpr (mk (TEnumField (e,f.cf_name)) t p) | _ -> normal())
+			| _ -> normal())
 	| CallAccess m ->
 	| CallAccess 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.curmethod && (match e.eexpr with TConst TThis -> true | TTypeExpr (TClassDecl c) when c == ctx.curclass -> true | _ -> false) then
 			let prefix = if Common.defined ctx.com "as3" then "$" else "" in
 			let prefix = if Common.defined ctx.com "as3" then "$" else "" in