Browse Source

fix typing of parametrized inline method in another method of the same parametrized class (#8658)

Aleksandr Kuzmenko 6 years ago
parent
commit
84f74018ca

+ 14 - 4
src/optimization/inline.ml

@@ -537,21 +537,31 @@ class inline_state ctx ethis params cf f p = object(self)
 			| _ -> unify_func());
 		end;
 		let vars = Hashtbl.create 0 in
-		let rec map_var v =
+		let rec map_var map_type v =
 			if not (Hashtbl.mem vars v.v_id) then begin
 				Hashtbl.add vars v.v_id ();
 				if not (self#read v).i_outside then begin
 					v.v_type <- map_type v.v_type;
 					match v.v_extra with
 					| Some(tl,Some e) ->
-						v.v_extra <- Some(tl,Some (map_expr_type e));
+						v.v_extra <- Some(tl,Some (map_expr_type map_type e));
 					| _ ->
 						()
 				end
 			end;
 			v
-		and map_expr_type e = Type.map_expr_type map_expr_type map_type map_var e in
-		map_expr_type e
+		and map_expr_type map_type e =
+			(*
+				No need to change typing of arguments of inlined call
+				because they were already properly typed prior to inlining.
+			*)
+			let map_type =
+				if List.memq e params then (fun t -> t)
+				else map_type
+			in
+			Type.map_expr_type (map_expr_type map_type) map_type (map_var map_type) e
+		in
+		map_expr_type map_type e
 end
 
 let rec type_inline ctx cf f ethis params tret config p ?(self_calling_closure=false) force =

+ 9 - 0
tests/misc/projects/Issue8654/Arr.hx

@@ -0,0 +1,9 @@
+class Arr<T> {
+	var get:T;
+
+	inline function set(val:T):Void {}
+
+	@:keep
+	public function map<S>(f:T->S)
+		(null:Arr<S>).set(f(get));
+}

+ 50 - 0
tests/misc/projects/Issue8654/Check.hx

@@ -0,0 +1,50 @@
+import haxe.macro.Compiler;
+import haxe.macro.Context;
+import haxe.macro.Expr;
+import haxe.macro.Type;
+
+class Check {
+	static public function run() {
+
+		Context.onAfterTyping(function(types) {
+			for(type in types) {
+				switch type {
+					case TClassDecl(_.get() => cls) if (cls.name == 'Arr'):
+						for(field in cls.fields.get()) {
+							if(field.name == 'map') {
+								var expr = field.expr();
+								switch expr.expr {
+									/*
+										{
+											var val = f(this.get);
+											null;
+										}
+									*/
+									case TFunction({expr: {expr: TBlock(exprs)}}):
+										switch exprs[0].expr {
+											// var val = f(this.get);
+											case TVar(_, {expr: TCall({expr: TLocal(_), t: t}, _)}):
+												// type of `f` from expr above
+												switch t {
+													//Should be `Arr.T->map.S`. Before the fix it was `map.S->map.S`
+													case TFun([{t: TInst(_.toString() => 'Arr.T',[])}], _):
+														//success;
+														return;
+													case _:
+														Context.error('Invalid invalid type of "f(get())" in Arr.map: $t', exprs[0].pos);
+												}
+											case _:
+												Context.error('Invalid expression of Arr.map block', exprs[0].pos);
+										}
+									case _:
+										Context.error('Invalid expression of Arr.map', expr.pos);
+								}
+							}
+						}
+					case _:
+				}
+			}
+			Context.error('Class "Arr" was not found', Context.currentPos());
+		});
+	}
+}

+ 2 - 0
tests/misc/projects/Issue8654/compile.hxml

@@ -0,0 +1,2 @@
+Arr
+--macro Check.run()