From 07323867806b9bc364cf693f5a869260ca7886d8 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 10 Feb 2021 13:04:25 +0100 Subject: [PATCH 1/3] Merge multiple parameter lists in resolveOverloaded Resolve overloaded does an applicability test which can make use of only a single type parameter list. When going deeper into several alternatives that contain a common prefex we might uncover other type parameter lists. These need to be merged. --- compiler/src/dotty/tools/dotc/typer/Applications.scala | 4 ++-- tests/pos/i11358.scala | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 tests/pos/i11358.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index ec23b8fe77dc..b55cf92c070d 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -1903,7 +1903,7 @@ trait Applications extends Compatibility { def skip(tp: Type): Type = tp match { case tp: PolyType => val rt = skip(tp.resultType) - if (rt.exists) tp.derivedLambdaType(resType = rt) else rt + if rt.exists then tp.derivedLambdaType(resType = rt).asInstanceOf[PolyType].flatten else rt case tp: MethodType => tp.instantiate(argTypes) case _ => @@ -1974,7 +1974,7 @@ trait Applications extends Compatibility { None } val mapped = reverseMapping.map(_._1) - overload.println(i"resolve mapped: $mapped") + overload.println(i"resolve mapped: ${mapped.map(_.widen)}%, % with $pt") resolveOverloaded(mapped, pt).map(reverseMapping.toMap) /** Try to typecheck any arguments in `pt` that are function values missing a diff --git a/tests/pos/i11358.scala b/tests/pos/i11358.scala new file mode 100644 index 000000000000..b153f487fdf0 --- /dev/null +++ b/tests/pos/i11358.scala @@ -0,0 +1,8 @@ +object Test: + + def test1: IArray[Int] = IArray(1, 2) +++ IArray(2, 3) + def test2: IArray[Int] = IArray(1, 2) +++ List(2, 3) + + extension [A: reflect.ClassTag](arr: IArray[A]) + def +++[B >: A: reflect.ClassTag](suffix: IArray[B]): IArray[B] = ??? + def +++[B >: A: reflect.ClassTag](suffix: IterableOnce[B]): IArray[B] = ??? From aef96f6e369b4ac58cc37f57dd66334cf1b08735 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 10 Feb 2021 14:56:04 +0100 Subject: [PATCH 2/3] Support all combinations of explicit type parameters Support all combinations of explicit vs inferred type parameters in overloaded variants with multiple type parameter lists. --- .../dotty/tools/dotc/typer/Applications.scala | 18 ++++++++++++++---- tests/pos/i11358.scala | 6 ++++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index b55cf92c070d..7a932daf6b1d 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -1899,11 +1899,16 @@ trait Applications extends Compatibility { /** The type of alternative `alt` after instantiating its first parameter * clause with `argTypes`. */ - def skipParamClause(argTypes: List[Type])(alt: TermRef): Type = + def skipParamClause(argTypes: List[Type], typeArgs: List[Type])(alt: TermRef): Type = def skip(tp: Type): Type = tp match { case tp: PolyType => - val rt = skip(tp.resultType) - if rt.exists then tp.derivedLambdaType(resType = rt).asInstanceOf[PolyType].flatten else rt + skip(tp.resultType) match + case NoType => + NoType + case rt: PolyType if typeArgs.length == rt.paramInfos.length => + tp.derivedLambdaType(resType = rt.instantiate(typeArgs)) + case rt => + tp.derivedLambdaType(resType = rt).asInstanceOf[PolyType].flatten case tp: MethodType => tp.instantiate(argTypes) case _ => @@ -1926,9 +1931,14 @@ trait Applications extends Compatibility { else val deepPt = pt.deepenProto deepPt match + case pt @ FunProto(_, PolyProto(targs, resType)) => + // try to narrow further with snd argument list and following type params + resolveMapped(candidates, + skipParamClause(pt.typedArgs().tpes, targs.tpes), resType) case pt @ FunProto(_, resType: FunOrPolyProto) => // try to narrow further with snd argument list - resolveMapped(candidates, skipParamClause(pt.typedArgs().tpes), resType) + resolveMapped(candidates, + skipParamClause(pt.typedArgs().tpes, Nil), resType) case _ => // prefer alternatives that need no eta expansion val noCurried = alts.filter(!resultIsMethod(_)) diff --git a/tests/pos/i11358.scala b/tests/pos/i11358.scala index b153f487fdf0..aa246a45fba4 100644 --- a/tests/pos/i11358.scala +++ b/tests/pos/i11358.scala @@ -2,6 +2,12 @@ object Test: def test1: IArray[Int] = IArray(1, 2) +++ IArray(2, 3) def test2: IArray[Int] = IArray(1, 2) +++ List(2, 3) + def test3 = +++[Int](IArray(1, 2))(IArray(2, 3)) + def test4 = +++[Int](IArray(1, 2))(List(2, 3)) + def test5: IArray[Int] = IArray(1, 2).+++[Int](IArray(2, 3)) + def test6: IArray[Int] = IArray(1, 2).+++[Int](List(2, 3)) + def test7 = +++(IArray(1, 2))[Int](IArray(2, 3)) + def test8 = +++(IArray(1, 2))[Int](List(2, 3)) extension [A: reflect.ClassTag](arr: IArray[A]) def +++[B >: A: reflect.ClassTag](suffix: IArray[B]): IArray[B] = ??? From c812c5dc0c5986b4fcf28e164a786b17b3ab1512 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 10 Feb 2021 15:10:30 +0100 Subject: [PATCH 3/3] Add comment --- compiler/src/dotty/tools/dotc/typer/Applications.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 7a932daf6b1d..f17889b9bbfd 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -1897,7 +1897,8 @@ trait Applications extends Compatibility { } /** The type of alternative `alt` after instantiating its first parameter - * clause with `argTypes`. + * clause with `argTypes`. In addition, if the resulting type is a PolyType + * and `typeArgs` matches its parameter list, instantiate the result with `typeArgs`. */ def skipParamClause(argTypes: List[Type], typeArgs: List[Type])(alt: TermRef): Type = def skip(tp: Type): Type = tp match {