소스 검색

Improve function type printing (#9360)

* Improve function type printing, fixes #9353

* Add regression tests for #9353

* Fix TestMacro.hx
George Corney 5 년 전
부모
커밋
efae7f1449
2개의 변경된 파일30개의 추가작업 그리고 10개의 파일을 삭제
  1. 8 7
      std/haxe/macro/Printer.hx
  2. 22 3
      tests/unit/src/unit/TestMacro.hx

+ 8 - 7
std/haxe/macro/Printer.hx

@@ -120,14 +120,15 @@ class Printer {
 		return switch (ct) {
 			case TPath(tp): printTypePath(tp);
 			case TFunction(args, ret):
-				if (args.length == 1 && !(args[0].match(TNamed(_, _)) || args[0].match(TFunction(_, _)))) {
-					// This special case handles an ambigity between the old function syntax and the new
-					// (T) -> T parses as `TFunction([TParent(TPath)], ...`, rather than `TFunction([TPath], ...`
-					// We forgo patenthesis in this case so that (T) -> T doesn't get round-tripped to ((T)) -> T
-					printComplexType(args[0]) + " -> " + printComplexType(ret);
-				} else {
-					'(${args.map(printComplexType).join(", ")})' + " -> " + printComplexType(ret);
+				var wrapArgumentsInParentheses = switch args {
+					// type `:(a:X) -> Y` has args as [TParent(TNamed(...))], i.e `a:X` gets wrapped in `TParent()`. We don't add parentheses to avoid printing `:((a:X)) -> Y`
+					case [TParent(t)]: false;
+					// this case catches a single argument that's a type-path, so that `X -> Y` prints `X -> Y` not `(X) -> Y`
+					case [TPath(_) | TOptional(TPath(_))]: false;
+					default: true;
 				}
+				var argStr = args.map(printComplexType).join(", ");
+				(wrapArgumentsInParentheses ? '($argStr)' : argStr) + " -> " + printComplexType(ret);
 			case TAnonymous(fields): "{ " + [for (f in fields) printField(f) + "; "].join("") + "}";
 			case TParent(ct): "(" + printComplexType(ct) + ")";
 			case TOptional(ct): "?" + printComplexType(ct);

+ 22 - 3
tests/unit/src/unit/TestMacro.hx

@@ -63,14 +63,33 @@ class TestMacro extends Test {
 		parseAndPrint("var a:() -> A");
 		parseAndPrint("var a:() -> (() -> A)");
 		parseAndPrint("var a:(x:(y:Y) -> Z) -> A");
-		// special case with 1 argument
-		parseAndPrint("var a:X -> Y");
-		parseAndPrint("var a:(X) -> Y");
 		// local functions
 		parseAndPrint('a -> b');
 		parseAndPrint('(a:Int) -> b');
 		parseAndPrint('(a, b) -> c');
 		parseAndPrint('function(a) return b');
 		parseAndPrint('function named(a) return b');
+
+		var p = new haxe.macro.Printer();
+		// special handling of single arguments (don't add parentheses)
+		//	types
+		eq(p.printComplexType(macro :X -> Y), "X -> Y");
+		eq(p.printComplexType(macro :(X) -> Y), "(X) -> Y");
+		eq(p.printComplexType(macro :((X)) -> Y), "((X)) -> Y");
+		eq(p.printComplexType(macro :?X -> Y), "?X -> Y");
+		eq(p.printComplexType(macro :(?X) -> Y), "(?X) -> Y");
+		//	named
+		eq(
+			// see issue #9353
+			p.printComplexType( TFunction( [ TOptional( TNamed('a', macro :Int) ) ], macro :Int) ),
+			"(?a:Int) -> Int"
+		);
+		eq(p.printComplexType(macro :(a:X) -> Y), "(a:X) -> Y");
+		eq(p.printComplexType(macro :(?a:X) -> Y), "(?a:X) -> Y");
+		eq(p.printComplexType(macro :((?a:X)) -> Y), "((?a:X)) -> Y");
+		// multiple arguments are always wrapped with parentheses
+		eq(p.printComplexType(macro :(X, Y) -> Z), "(X, Y) -> Z");
+		eq(p.printComplexType(macro :X -> Y -> Z), "(X, Y) -> Z");
+		eq(p.printComplexType(macro :(X -> Y) -> Z), "(X -> Y) -> Z");
 	}
 }