Kaynağa Gözat

compiler : fixed issue with cascading inline+haxe.rtti.Generic
optimizer : reduce constant int/float/bool expressions and immediate function calls
flash9/as3/php : don't add Boot.skip_constructor test if no side effects in constructor

Nicolas Cannasse 16 yıl önce
ebeveyn
işleme
93cd97ddb7
11 değiştirilmiş dosya ile 244 ekleme ve 55 silme
  1. 23 39
      codegen.ml
  2. 2 0
      common.ml
  3. 3 2
      doc/CHANGES.txt
  4. 1 1
      genas3.ml
  5. 5 2
      genphp.ml
  6. 1 0
      genswf9.ml
  7. 6 1
      main.ml
  8. 140 6
      optimizer.ml
  9. 61 3
      type.ml
  10. 1 1
      typeload.ml
  11. 1 0
      typer.ml

+ 23 - 39
codegen.ml

@@ -180,38 +180,7 @@ let build_generic ctx c p tl =
 			| _ ->
 			| _ ->
 				try List.assq t subst with Not_found -> Type.map build_type t
 				try List.assq t subst with Not_found -> Type.map build_type t
 		in
 		in
-		let rec build_expr e =
-			let t = build_type e.etype in
-			match e.eexpr with
-			| TFunction f ->
-				{
-					eexpr = TFunction {
-						tf_args = List.map (fun (n,o,t) -> n, o, build_type t) f.tf_args;
-						tf_type = build_type f.tf_type;
-						tf_expr = build_expr f.tf_expr;
-					};
-					etype = t;
-					epos = e.epos;
-				}
-			| TNew (c,tl,el) ->
-				let c, tl = (match follow t with TInst (c,tl) -> c, tl | _ -> assert false) in
-				{
-					eexpr = TNew (c,tl,List.map build_expr el);
-					etype = t;
-					epos = e.epos;
-				};
-			| TVars vl ->
-				{
-					eexpr = TVars (List.map (fun (v,t,eo) ->
-						v, build_type t, (match eo with None -> None | Some e -> Some (build_expr e))
-					) vl);
-					etype = t;
-					epos = e.epos;
-				}
-			(* there's still some 't' lefts in TFor, TMatch and TTry *)
-			| _ ->
-				Type.map_expr build_expr { e with etype = t }
-		in
+		let rec build_expr e = map_expr_type build_expr build_type e in
 		let build_field f =
 		let build_field f =
 			let t = build_type f.cf_type in
 			let t = build_type f.cf_type in
 			{ f with cf_type = t; cf_expr = (match f.cf_expr with None -> None | Some e -> Some (build_expr e)) }
 			{ f with cf_type = t; cf_expr = (match f.cf_expr with None -> None | Some e -> Some (build_expr e)) }
@@ -655,20 +624,20 @@ let check_local_vars_init e =
 		| _ ->
 		| _ ->
 			Type.iter (loop vars) e
 			Type.iter (loop vars) e
 	in
 	in
-	loop (ref PMap.empty) e
+	loop (ref PMap.empty) e;
+	e
 
 
 (* -------------------------------------------------------------------------- *)
 (* -------------------------------------------------------------------------- *)
 (* POST PROCESS *)
 (* POST PROCESS *)
 
 
-let post_process ctx =
+let post_process ctx filters =
 	List.iter (function
 	List.iter (function
 		| TClassDecl c ->
 		| TClassDecl c ->
 			let process_field f =
 			let process_field f =
 				match f.cf_expr with
 				match f.cf_expr with
 				| None -> ()
 				| None -> ()
 				| Some e ->
 				| Some e ->
-					check_local_vars_init e; 
-					f.cf_expr <- Some (block_vars ctx e)
+					f.cf_expr <- Some (List.fold_left (fun e f -> f e) e filters)
 			in
 			in
 			List.iter process_field c.cl_ordered_fields;
 			List.iter process_field c.cl_ordered_fields;
 			List.iter process_field c.cl_ordered_statics;
 			List.iter process_field c.cl_ordered_statics;
@@ -677,9 +646,8 @@ let post_process ctx =
 			| Some f -> process_field f);
 			| Some f -> process_field f);
 			(match c.cl_init with
 			(match c.cl_init with
 			| None -> ()
 			| None -> ()
-			| Some e ->
-				check_local_vars_init e;
-				c.cl_init <- Some (block_vars ctx e));
+			| Some e ->				
+				c.cl_init <- Some (List.fold_left (fun e f -> f e) e filters));
 		| TEnumDecl _ -> ()
 		| TEnumDecl _ -> ()
 		| TTypeDecl _ -> ()
 		| TTypeDecl _ -> ()
 	) ctx.types
 	) ctx.types
@@ -859,3 +827,19 @@ let bytes_serialize data =
 	let tbl = Array.init (String.length b64) (fun i -> String.get b64 i) in
 	let tbl = Array.init (String.length b64) (fun i -> String.get b64 i) in
 	let str = Base64.str_encode ~tbl data in
 	let str = Base64.str_encode ~tbl data in
 	"s" ^ string_of_int (String.length str) ^ ":" ^ str
 	"s" ^ string_of_int (String.length str) ^ ":" ^ str
+
+(*
+	Tells if the constructor might be called without any issue whatever its parameters
+*)
+let rec constructor_side_effects e =
+	match e.eexpr with
+	| TBinop (op,_,_) when op <> OpAssign ->
+		true
+	| TUnop _ | TArray _ | TField _ | TCall _ | TNew _ | TFor _ | TWhile _ | TSwitch _ | TMatch _ | TReturn _ | TThrow _ ->
+		true
+	| _ -> 
+		try 
+			Type.iter (fun e -> if constructor_side_effects e then raise Exit) e;
+			false;
+		with Exit ->
+			true

+ 2 - 0
common.ml

@@ -47,6 +47,7 @@ type context_type_api = {
 	mutable build_instance : module_type -> pos -> ((string * t) list * path * (t list -> t));
 	mutable build_instance : module_type -> pos -> ((string * t) list * path * (t list -> t));
 	mutable on_generate : module_type -> unit;
 	mutable on_generate : module_type -> unit;
 	mutable get_type_module : module_type -> module_def;
 	mutable get_type_module : module_type -> module_def;
+	mutable optimize : texpr -> texpr;
 }
 }
 
 
 type context = {
 type context = {
@@ -104,6 +105,7 @@ let create v =
 			build_instance = (fun _ _ -> assert false);
 			build_instance = (fun _ _ -> assert false);
 			on_generate = (fun _ -> ());
 			on_generate = (fun _ -> ());
 			get_type_module = (fun _ -> assert false);
 			get_type_module = (fun _ -> assert false);
+			optimize = (fun _ -> assert false);
 		};
 		};
 		lines = Lexer.build_line_index();
 		lines = Lexer.build_line_index();
 	}
 	}

+ 3 - 2
doc/CHANGES.txt

@@ -1,8 +1,6 @@
 TODO :
 TODO :
 	SWC input support
 	SWC input support
-	optimizer : reduce/calculate expressions
 	flash9 : optimize enum parameters storage
 	flash9 : optimize enum parameters storage
-	don't use Boot.skip_constructor if no side effects in constructor
 	rtti : allow rtti on all types and store them in a global static Hash<CType> (instead of XML)
 	rtti : allow rtti on all types and store them in a global static Hash<CType> (instead of XML)
 
 
 2009-??-??: 2.03
 2009-??-??: 2.03
@@ -34,6 +32,9 @@ TODO :
 	flash9 : fixed verify error with loop variable beeing a specific class
 	flash9 : fixed verify error with loop variable beeing a specific class
 	compiler : prevent truncating float dynamic values to int when using numerical operations
 	compiler : prevent truncating float dynamic values to int when using numerical operations
 	neko.db.Manager fix : synchronize fields after locking an unlocked cached object
 	neko.db.Manager fix : synchronize fields after locking an unlocked cached object
+	compiler : fixed issue with cascading inline+haxe.rtti.Generic
+	optimizer : reduce constant int/float/bool expressions and immediate function calls
+	flash9/as3/php : don't add Boot.skip_constructor test if no side effects in constructor
 
 
 2008-11-23: 2.02
 2008-11-23: 2.02
 	Std.is(MyInterface, Class) now returns true (haXe/PHP)
 	Std.is(MyInterface, Class) now returns true (haXe/PHP)

+ 1 - 1
genas3.ml

@@ -477,7 +477,7 @@ and gen_expr ctx e =
 		let b = save_locals ctx in
 		let b = save_locals ctx in
 		print ctx "{";
 		print ctx "{";
 		let bend = open_block ctx in
 		let bend = open_block ctx in
-		let cb = (if not ctx.constructor_block then
+		let cb = (if not ctx.constructor_block || not (Codegen.constructor_side_effects e) then
 			(fun () -> ())
 			(fun () -> ())
 		else begin
 		else begin
 			ctx.constructor_block <- false;
 			ctx.constructor_block <- false;

+ 5 - 2
genphp.ml

@@ -1135,8 +1135,11 @@ and gen_expr ctx e =
 					newline ctx;
 					newline ctx;
 				| _ -> ()
 				| _ -> ()
 			) ctx.dynamic_methods;
 			) ctx.dynamic_methods;
-			print ctx "if( !%s::$skip_constructor ) {" (s_path ctx (["php"],"Boot") false e.epos);
-			(fun() -> print ctx "}")
+			if Codegen.constructor_side_effects e then begin
+				print ctx "if( !%s::$skip_constructor ) {" (s_path ctx (["php"],"Boot") false e.epos);
+				(fun() -> print ctx "}")
+			end else
+				(fun() -> ())
 			end) in
 			end) in
 		List.iter (fun e -> newline ctx; gen_expr ctx e) el;
 		List.iter (fun e -> newline ctx; gen_expr ctx e) el;
 		bend();
 		bend();

+ 1 - 0
genswf9.ml

@@ -1565,6 +1565,7 @@ let generate_construct ctx fdata c =
 	(* if skip_constructor, then returns immediatly *)
 	(* if skip_constructor, then returns immediatly *)
 	(match c.cl_kind with
 	(match c.cl_kind with
 	| KGenericInstance _ -> ()
 	| KGenericInstance _ -> ()
+	| _ when not (Codegen.constructor_side_effects fdata.tf_expr) -> ()
 	| _ ->
 	| _ ->
 		let id = ident "skip_constructor" in
 		let id = ident "skip_constructor" in
 		getvar ctx (VGlobal (type_path ctx (["flash"],"Boot")));
 		getvar ctx (VGlobal (type_path ctx (["flash"],"Boot")));

+ 6 - 1
main.ml

@@ -438,7 +438,12 @@ try
 		if !no_output then com.platform <- Cross;
 		if !no_output then com.platform <- Cross;
 		com.types <- Typer.types ctx com.main_class (!excludes);
 		com.types <- Typer.types ctx com.main_class (!excludes);
 		com.lines <- Lexer.build_line_index();
 		com.lines <- Lexer.build_line_index();
-		Codegen.post_process com;
+		let filters = [
+			Codegen.check_local_vars_init;
+			Codegen.block_vars com;
+			Optimizer.reduce_expression com;
+		] in
+		Codegen.post_process com filters;
 		(match com.platform with
 		(match com.platform with
 		| Cross ->
 		| Cross ->
 			()
 			()

+ 140 - 6
optimizer.ml

@@ -143,7 +143,7 @@ let type_inline ctx cf f ethis params tret p =
 			| TBlock l, Some init -> mk (TBlock (init :: l)) tret e.epos
 			| TBlock l, Some init -> mk (TBlock (init :: l)) tret e.epos
 			| _, Some init -> mk (TBlock [init;e]) tret e.epos
 			| _, Some init -> mk (TBlock [init;e]) tret e.epos
 		) in
 		) in
-		(* we need to replace type-parameters that were used in the expression *)		
+		(* we need to replace type-parameters that were used in the expression *)
 		let tparams = (match follow ethis.etype with TInst (c,pl) -> (c.cl_types,pl) | _ -> ([],[])) in
 		let tparams = (match follow ethis.etype with TInst (c,pl) -> (c.cl_types,pl) | _ -> ([],[])) in
 		match cf.cf_params, tparams with
 		match cf.cf_params, tparams with
 		| [], ([],_) -> Some e
 		| [], ([],_) -> Some e
@@ -157,11 +157,9 @@ let type_inline ctx cf f ethis 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 rec map_type e = 
-				let e = { e with etype = apply_params tparams tmonos e.etype } in
-				Type.map_expr map_type e
-			in
-			Some (map_type e)
+			let map_type t = apply_params tparams tmonos t in
+			let rec map_expr_type e = Type.map_expr_type map_expr_type map_type e in
+			Some (map_expr_type e)
 
 
 (* ---------------------------------------------------------------------- *)
 (* ---------------------------------------------------------------------- *)
 (* LOOPS *)
 (* LOOPS *)
@@ -269,3 +267,139 @@ let optimize_for_loop ctx i e1 e2 p =
 		]
 		]
 	| _ ->
 	| _ ->
 		None
 		None
+
+(* ---------------------------------------------------------------------- *)
+(* REDUCE *)
+
+let rec reduce_loop com is_sub e =
+	let is_float t =
+		match follow t with
+		| TInst ({ cl_path = ([],"Float") },_) -> true
+		| _ -> false
+	in
+	let is_text_platform() =
+		match com.platform with
+		| Js | Php -> true 
+		| Neko | Flash | Flash9 | Cross -> false
+	in
+	let e = Type.map_expr (reduce_loop com (match e.eexpr with TBlock _ -> false | _ -> true)) e in
+	match e.eexpr with
+	| TIf ({ eexpr = TConst (TBool t) },e1,e2) ->
+		(if t then e1 else match e2 with None -> { e with eexpr = TBlock [] } | Some e -> e)
+	| TWhile ({ eexpr = TConst (TBool false) },sub,flag) ->
+		(match flag with
+		| NormalWhile -> { e with eexpr = TBlock [] } (* erase sub *)
+		| DoWhile -> e) (* we cant remove while since sub can contain continue/break *)
+	| TBinop (op,e1,e2) ->		
+		let zero = (match op with
+			| OpAdd | OpSub | OpShl | OpShr | OpUShr | OpXor -> Some (0l,0.)
+			| OpMult | OpDiv -> Some (1l,1.)
+			| _ -> None
+		) in
+		(match e1.eexpr, e2.eexpr with
+		| TConst (TInt v) , _ when (match zero with Some (z,_) when z = v -> true | _ -> false) -> e2
+		| _ , TConst (TInt v) when (match zero with Some (z,_) when z = v -> true | _ -> false) -> e1
+		| TConst (TFloat v) , _ when (match zero with Some (_,z) when z = float_of_string v -> is_float e2.etype | _ -> false) -> e2
+		| _ , TConst (TFloat v) when (match zero with Some (_,z) when z = float_of_string v -> is_float e1.etype | _ -> false) -> e1
+		| TConst (TInt a), TConst (TInt b) ->
+			let opt f = try { e with eexpr = TConst (TInt (f a b)) } with Exit -> e in
+			let check_overflow f =
+				opt (fun a b ->
+					let v = f (Int64.of_int32 a) (Int64.of_int32 b) in
+					let iv = Int64.to_int32 v in
+					if Int64.compare (Int64.of_int32 iv) v <> 0 then raise Exit;
+					iv
+				)
+			in
+			let ebool t =
+				{ e with eexpr = TConst (TBool (t (Int32.compare a b))) }
+			in
+			(match op with
+			| OpAdd -> check_overflow Int64.add
+			| OpSub -> check_overflow Int64.sub
+			| OpMult -> check_overflow Int64.mul
+			| OpAnd -> opt Int32.logand
+			| OpOr -> opt Int32.logor
+			| OpXor -> opt Int32.logxor
+			| OpShl -> opt (fun a b -> Int32.shift_left a (Int32.to_int b))
+			| OpShr -> opt (fun a b -> Int32.shift_right a (Int32.to_int b))
+			| OpUShr -> opt (fun a b -> Int32.shift_right_logical a (Int32.to_int b))
+			| OpEq -> ebool ((=) 0)
+			| OpNotEq -> ebool ((<>) 0)
+			| OpGt -> ebool ((>) 0)
+			| OpGte -> ebool ((>=) 0)
+			| OpLt -> ebool ((<) 0)
+			| OpLte -> ebool ((<=) 0)
+			| _ -> e)
+		| TConst (TFloat a), TConst (TFloat b) ->
+			let fop f =
+				let v = f (float_of_string a) (float_of_string b) in
+				let vstr = string_of_float v in
+				if v = float_of_string vstr then
+					{ e with eexpr = TConst (TFloat vstr) }
+				else
+					e
+			in
+			let ebool t =
+				{ e with eexpr = TConst (TBool (t (compare a b))) }
+			in
+			(match op with
+			| OpAdd -> fop (+.)
+			| OpSub -> fop (-.)
+			| OpMult -> fop ( *. )
+			| OpEq -> ebool ((=) 0)
+			| OpNotEq -> ebool ((<>) 0)
+			| OpGt -> ebool ((>) 0)
+			| OpGte -> ebool ((>=) 0)
+			| OpLt -> ebool ((<) 0)
+			| OpLte -> ebool ((<=) 0)
+			| _ -> e)			
+		| TConst (TBool a), TConst (TBool b) ->
+			let ebool f =
+				{ e with eexpr = TConst (TBool (f a b)) }
+			in
+			(match op with
+			| OpEq -> ebool (=)
+			| OpNotEq -> ebool (<>)
+			| OpBoolAnd -> ebool (&&)
+			| OpBoolOr -> ebool (||)
+			| _ -> e)
+		| _ -> e)
+	| TCall ({ eexpr = TFunction func },el) ->
+		let rec build term e =
+			match e.eexpr with
+			| TBlock el ->
+				(match List.rev el with
+				| [] -> e
+				| e1 :: el ->
+					let el = List.map (build false) (List.rev el) in
+					let e1 = build term e1 in
+					{ e with eexpr = TBlock (e1 :: el) })
+			| TParenthesis _ | TIf (_,_,Some _) | TSwitch _ | TMatch _ | TTry _ ->
+				(* might only cause issues if some 'return' found in the first expression of if/switch/match *)
+				Type.map_expr (build term) e
+			| TReturn eo ->				
+				if not term then raise Exit;
+				(match eo with
+				| None -> { e with eexpr = TBlock [] }
+				| Some e -> build term e)
+			| _ ->
+				Type.map_expr (build false) e
+		in
+		(try
+			let body = build true func.tf_expr in
+			let body = (match body.eexpr with TBlock el -> el | _ -> [body]) in
+			let body = (match el with
+				| [] -> body
+				| _ ->					
+					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
+			) in
+			{ e with eexpr = TBlock body }
+		with
+			Exit -> e)
+	| _ -> 
+		e
+
+let reduce_expression com e =
+	reduce_loop com false e

+ 61 - 3
type.ml

@@ -8,7 +8,7 @@
  *  (at your option) any later version.
  *  (at your option) any later version.
  *
  *
  *  This program is distributed in the hope that it will be useful,
  *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  but WITHOUT ANY WARRANTY; without even the implied warraTFnty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *  GNU General Public License for more details.
  *
  *
@@ -758,7 +758,7 @@ and unify_with_access t f =
 	| _ , NoAccess -> unify t f.cf_type
 	| _ , NoAccess -> unify t f.cf_type
 	| _ , _ -> type_eq EqBothDynamic t f.cf_type
 	| _ , _ -> type_eq EqBothDynamic t f.cf_type
 
 
-let rec iter f e =
+let iter f e =
 	match e.eexpr with
 	match e.eexpr with
 	| TConst _
 	| TConst _
 	| TLocal _
 	| TLocal _
@@ -809,7 +809,7 @@ let rec iter f e =
 	| TReturn eo ->
 	| TReturn eo ->
 		(match eo with None -> () | Some e -> f e)
 		(match eo with None -> () | Some e -> f e)
 
 
-let rec map_expr f e =
+let map_expr f e =
 	match e.eexpr with
 	match e.eexpr with
 	| TConst _
 	| TConst _
 	| TLocal _
 	| TLocal _
@@ -858,3 +858,61 @@ let rec map_expr f e =
 		{ e with eexpr = TTry (f e1, List.map (fun (v,t,e) -> v, t, f e) catches) }
 		{ e with eexpr = TTry (f e1, List.map (fun (v,t,e) -> v, t, f e) catches) }
 	| TReturn eo ->
 	| TReturn eo ->
 		{ e with eexpr = TReturn (match eo with None -> None | Some e -> Some (f e)) }
 		{ e with eexpr = TReturn (match eo with None -> None | Some e -> Some (f e)) }
+
+let map_expr_type f ft e =
+	match e.eexpr with
+	| TConst _
+	| TLocal _
+	| TEnumField _
+	| TBreak
+	| TContinue
+	| TTypeExpr _ ->
+		{ e with etype = ft e.etype }
+	| TArray (e1,e2) ->
+		{ e with eexpr = TArray (f e1,f e2); etype = ft e.etype }
+	| TBinop (op,e1,e2) ->
+		{ e with eexpr = TBinop (op,f e1,f e2); etype = ft e.etype }
+	| TFor (v,t,e1,e2) ->
+		{ e with eexpr = TFor (v,ft t,f e1,f e2); etype = ft e.etype }
+	| TWhile (e1,e2,flag) ->
+		{ e with eexpr = TWhile (f e1,f e2,flag); etype = ft e.etype }
+	| TThrow e1 ->
+		{ e with eexpr = TThrow (f e1); etype = ft e.etype }
+	| TField (e1,v) ->
+		{ e with eexpr = TField (f e1,v); etype = ft e.etype }
+	| TParenthesis e1 ->
+		{ e with eexpr = TParenthesis (f e1); etype = ft e.etype }
+	| TUnop (op,pre,e1) ->
+		{ e with eexpr = TUnop (op,pre,f e1); etype = ft e.etype }
+	| TArrayDecl el ->
+		{ e with eexpr = TArrayDecl (List.map f el); etype = ft e.etype }
+	| TNew (_,_,el) ->
+		let et = ft e.etype in
+		(* make sure that we use the class corresponding to the replaced type *)
+		let c, pl = (match follow et with TInst (c,pl) -> (c,pl) | _ -> assert false) in
+		{ e with eexpr = TNew (c,pl,List.map f el); etype = et }
+	| TBlock el ->
+		{ e with eexpr = TBlock (List.map f el); etype = ft e.etype }
+	| TObjectDecl el ->
+		{ e with eexpr = TObjectDecl (List.map (fun (v,e) -> v, f e) el); etype = ft e.etype }
+	| TCall (e1,el) ->
+		{ e with eexpr = TCall (f e1, List.map f el); etype = ft e.etype }
+	| TVars vl ->
+		{ e with eexpr = TVars (List.map (fun (v,t,e) -> v , ft t , match e with None -> None | Some e -> Some (f e)) vl); etype = ft e.etype }
+	| TFunction fu ->
+		let fu = {
+			tf_expr = f fu.tf_expr;
+			tf_args = List.map (fun (n,o,t) -> n, o, ft t) fu.tf_args;
+			tf_type = ft fu.tf_type;
+		} in
+		{ e with eexpr = TFunction fu; etype = ft e.etype }
+	| TIf (ec,e1,e2) ->
+		{ e with eexpr = TIf (f ec,f e1,match e2 with None -> None | Some e -> Some (f e)); etype = ft e.etype }
+	| TSwitch (e1,cases,def) ->
+		{ e with eexpr = TSwitch (f e1, List.map (fun (el,e2) -> List.map f el, f e2) cases, match def with None -> None | Some e -> Some (f e)); etype = ft e.etype }
+	| TMatch (e1,(en,pl),cases,def) ->
+		{ e with eexpr = TMatch (f e1, (en,List.map ft pl), List.map (fun (cl,params,e) -> cl, params, f e) cases, match def with None -> None | Some e -> Some (f e)); etype = ft e.etype }
+	| TTry (e1,catches) ->
+		{ e with eexpr = TTry (f e1, List.map (fun (v,t,e) -> v, ft t, f e) catches); etype = ft e.etype }
+	| TReturn eo ->
+		{ e with eexpr = TReturn (match eo with None -> None | Some e -> Some (f e)); etype = ft e.etype }

+ 1 - 1
typeload.ml

@@ -466,7 +466,7 @@ let type_function ctx args ret static constr f p =
 			| None -> None
 			| None -> None
 			| Some e -> 
 			| Some e -> 
 				let p = pos e in
 				let p = pos e in
-				let e = type_expr ctx e true in
+				let e = ctx.api.optimize (type_expr ctx e true) in
 				unify ctx e.etype t p;
 				unify ctx e.etype t p;
 				match e.eexpr with
 				match e.eexpr with
 				| TConst c -> Some c
 				| TConst c -> Some c

+ 1 - 0
typer.ml

@@ -1728,6 +1728,7 @@ let create com =
 	ctx.api.build_instance <- Codegen.build_instance ctx;
 	ctx.api.build_instance <- Codegen.build_instance ctx;
 	ctx.api.on_generate <- Codegen.on_generate ctx;
 	ctx.api.on_generate <- Codegen.on_generate ctx;
 	ctx.api.get_type_module <- get_type_module ctx;
 	ctx.api.get_type_module <- get_type_module ctx;
+	ctx.api.optimize <- Optimizer.reduce_expression com;
 	ctx.std <- (try
 	ctx.std <- (try
 		Typeload.load_module ctx ([],"StdTypes") null_pos
 		Typeload.load_module ctx ([],"StdTypes") null_pos
 	with
 	with