Kaynağa Gözat

prefer explicit `iterator` declaration instead of a Dynamic unified with Iterator<T> (fixes #4705)

Aleksandr Kuzmenko 6 yıl önce
ebeveyn
işleme
bcaa684784
2 değiştirilmiş dosya ile 32 ekleme ve 5 silme
  1. 15 5
      src/typing/forLoop.ml
  2. 17 0
      tests/unit/src/unit/issues/Issue4705.hx

+ 15 - 5
src/typing/forLoop.ml

@@ -55,8 +55,15 @@ module IterationKind = struct
 
 	let check_iterator ?(resume=false) ?last_resort ctx s e p =
 		let t,pt = Typeload.t_iterator ctx in
+		let dynamic_iterator = ref None in
 		let e1 = try
-			AbstractCast.cast_or_unify_raise ctx t e p
+			let e = AbstractCast.cast_or_unify_raise ctx t e p in
+			match Abstract.follow_with_abstracts e.etype with
+			| TDynamic _ | TMono _ ->
+				(* try to find something better than a dynamic value to iterate on *)
+				dynamic_iterator := Some e;
+				raise (Error (Unify [Unify_custom "Avoid iterating on a dynamic value"], p))
+			| _ -> e
 		with Error (Unify _,_) ->
 			let try_last_resort after =
 				try
@@ -73,10 +80,13 @@ module IterationKind = struct
 					acc_expr
 				with Error (Unify(l),p) ->
 					try_last_resort (fun () ->
-						if resume then raise Not_found;
-						display_error ctx "Field iterator has an invalid type" acc_expr.epos;
-						display_error ctx (error_msg (Unify l)) p;
-						mk (TConst TNull) t_dynamic p
+						match !dynamic_iterator with
+						| Some e -> e
+						| None ->
+							if resume then raise Not_found;
+							display_error ctx "Field iterator has an invalid type" acc_expr.epos;
+							display_error ctx (error_msg (Unify l)) p;
+							mk (TConst TNull) t_dynamic p
 					)
 			in
 			try

+ 17 - 0
tests/unit/src/unit/issues/Issue4705.hx

@@ -0,0 +1,17 @@
+package unit.issues;
+
+class Issue4705 extends unit.Test {
+	function test() {
+		var a:Object = { foo: 12, bar: '13' };
+		aeq(['foo', 'bar'], [for(f in a) f]);
+	}
+}
+
+@:forward
+abstract Object(Dynamic) from Dynamic to Dynamic {
+	public function iterator ():Iterator<String> {
+		var fields = Reflect.fields (this);
+		if (fields == null) fields = [];
+		return fields.iterator();
+	}
+}