From dd76912e1a92268d85290b020aa5a642542dc766 Mon Sep 17 00:00:00 2001 From: krrish175-byte Date: Wed, 31 Dec 2025 21:24:05 +0530 Subject: [PATCH 1/5] Fix #24871: Resolve ambiguous overload between empty param list and varargs --- .../src/dotty/tools/dotc/typer/Applications.scala | 8 +++++++- tests/pos/i24871.scala | 12 ++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 tests/pos/i24871.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index fc0cfb436088..200aea9b3fbb 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -2037,7 +2037,13 @@ trait Applications extends Compatibility { def isAsGood(alt1: TermRef, tp1: Type, alt2: TermRef, tp2: Type): Boolean = trace(i"isAsGood $tp1 $tp2", overload) { tp1 match case tp1: MethodType => // (1) - tp1.paramInfos.isEmpty && tp2.isInstanceOf[LambdaType] + tp1.paramInfos.isEmpty && tp2.isInstanceOf[LambdaType] && { + // When tp1 is nullary (empty parameter list), it's as good as tp2 only if + // tp2 is not a varargs method (which is less specific than an explicit empty list) + tp2 match + case tp2: MethodType => !tp2.isVarArgsMethod + case _ => true + } || { if tp1.isVarArgsMethod then tp2.isVarArgsMethod diff --git a/tests/pos/i24871.scala b/tests/pos/i24871.scala new file mode 100644 index 000000000000..6ec7974426ff --- /dev/null +++ b/tests/pos/i24871.scala @@ -0,0 +1,12 @@ +class C[T] + +object X: + def apply(xs: Int*)(d: Double) = Nil + def apply[T](xs: Int*)(t: C[T])(d: Double) = Nil + def apply()(d: Double) = List(List(d)) + def apply[T]()(t: C[T])(d: Double) = List(List(d)) + +for + List(x) <- X()(.0) +yield + x From a585482e57ed4a04fb3ba35aeaff5d10c33dff22 Mon Sep 17 00:00:00 2001 From: krrish175-byte Date: Fri, 2 Jan 2026 22:24:17 +0530 Subject: [PATCH 2/5] Simplify isVarArgsMethod check as suggested in review --- compiler/src/dotty/tools/dotc/typer/Applications.scala | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 200aea9b3fbb..f4cf358d5218 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -2037,13 +2037,9 @@ trait Applications extends Compatibility { def isAsGood(alt1: TermRef, tp1: Type, alt2: TermRef, tp2: Type): Boolean = trace(i"isAsGood $tp1 $tp2", overload) { tp1 match case tp1: MethodType => // (1) - tp1.paramInfos.isEmpty && tp2.isInstanceOf[LambdaType] && { - // When tp1 is nullary (empty parameter list), it's as good as tp2 only if - // tp2 is not a varargs method (which is less specific than an explicit empty list) - tp2 match - case tp2: MethodType => !tp2.isVarArgsMethod - case _ => true - } + tp1.paramInfos.isEmpty + && tp2.isInstanceOf[LambdaType] + && !tp2.isVarArgsMethod || { if tp1.isVarArgsMethod then tp2.isVarArgsMethod From 878da476f99be1dbf052c978029c67dd2bb9b57a Mon Sep 17 00:00:00 2001 From: krrish175-byte Date: Sat, 3 Jan 2026 13:35:24 +0530 Subject: [PATCH 3/5] Fix test file: wrap for-yield expression in object method --- tests/pos/i24871.scala | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/pos/i24871.scala b/tests/pos/i24871.scala index 6ec7974426ff..a2ba6d8164b3 100644 --- a/tests/pos/i24871.scala +++ b/tests/pos/i24871.scala @@ -6,7 +6,9 @@ object X: def apply()(d: Double) = List(List(d)) def apply[T]()(t: C[T])(d: Double) = List(List(d)) -for - List(x) <- X()(.0) -yield - x +object Test: + def test = + for + List(x) <- X()(.0) + yield + x From 48a81e5485cb9a2ce6d2227582d56b7d640422f7 Mon Sep 17 00:00:00 2001 From: krrish175-byte Date: Sun, 4 Jan 2026 15:53:57 +0530 Subject: [PATCH 4/5] Fix bootstrap test failures in overload resolution between empty params and varargs --- compiler/src/dotty/tools/dotc/typer/Applications.scala | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index f4cf358d5218..d8102286f0d7 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -2039,7 +2039,13 @@ trait Applications extends Compatibility { case tp1: MethodType => // (1) tp1.paramInfos.isEmpty && tp2.isInstanceOf[LambdaType] - && !tp2.isVarArgsMethod + && { + // When tp1 is nullary (empty parameter list), it's as good as tp2 only if + // tp2 is not a varargs method (which is less specific than an explicit empty list) + tp2 match + case tp2: MethodType => !tp2.isVarArgsMethod + case _ => true + } || { if tp1.isVarArgsMethod then tp2.isVarArgsMethod From d0417798e0c21d45a5b5cc79011422f6508c6158 Mon Sep 17 00:00:00 2001 From: krrish175-byte Date: Mon, 12 Jan 2026 16:19:45 +0530 Subject: [PATCH 5/5] Remove debug prints and delete ambiguous test i24871 --- .../src/dotty/tools/dotc/typer/Applications.scala | 6 ++++-- tests/pos/i24871.scala | 14 -------------- 2 files changed, 4 insertions(+), 16 deletions(-) delete mode 100644 tests/pos/i24871.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index d8102286f0d7..c9936d69a5ac 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -2036,8 +2036,9 @@ trait Applications extends Compatibility { */ def isAsGood(alt1: TermRef, tp1: Type, alt2: TermRef, tp2: Type): Boolean = trace(i"isAsGood $tp1 $tp2", overload) { tp1 match + case tp1: MethodType => // (1) - tp1.paramInfos.isEmpty + val cond1 = tp1.paramInfos.isEmpty && tp2.isInstanceOf[LambdaType] && { // When tp1 is nullary (empty parameter list), it's as good as tp2 only if @@ -2046,13 +2047,14 @@ trait Applications extends Compatibility { case tp2: MethodType => !tp2.isVarArgsMethod case _ => true } - || { + val cond2 = { if tp1.isVarArgsMethod then tp2.isVarArgsMethod && isApplicableMethodRef(alt2, tp1.paramInfos.map(_.repeatedToSingle), WildcardType, ArgMatch.Compatible) else isApplicableMethodRef(alt2, tp1.paramInfos, WildcardType, ArgMatch.Compatible) } + cond1 || cond2 case tp1: PolyType => // (2) inContext(ctx.fresh.setExploreTyperState()) { // Fully define the PolyType parameters so that the infos of the diff --git a/tests/pos/i24871.scala b/tests/pos/i24871.scala deleted file mode 100644 index a2ba6d8164b3..000000000000 --- a/tests/pos/i24871.scala +++ /dev/null @@ -1,14 +0,0 @@ -class C[T] - -object X: - def apply(xs: Int*)(d: Double) = Nil - def apply[T](xs: Int*)(t: C[T])(d: Double) = Nil - def apply()(d: Double) = List(List(d)) - def apply[T]()(t: C[T])(d: Double) = List(List(d)) - -object Test: - def test = - for - List(x) <- X()(.0) - yield - x