diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index c70a68982b65..e0053f0f8aff 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -218,32 +218,15 @@ object desugar { * def f$default$2[T](x: Int) = x + "m" */ private def defDef(meth: DefDef, isPrimaryConstructor: Boolean = false)(using Context): Tree = - addDefaultGetters(elimContextBounds(Nil, meth, isPrimaryConstructor)) + addDefaultGetters(elimContextBounds(meth, isPrimaryConstructor)) - private def defDef(extParamss: List[ParamClause], meth: DefDef)(using Context): Tree = - addDefaultGetters(elimContextBounds(extParamss, meth, false)) - - private def elimContextBounds(extParamss: List[ParamClause], meth: DefDef, isPrimaryConstructor: Boolean)(using Context): DefDef = + private def elimContextBounds(meth: DefDef, isPrimaryConstructor: Boolean)(using Context): DefDef = val DefDef(_, paramss, tpt, rhs) = meth - - rhs match - case MacroTree(call) => - cpy.DefDef(meth)(rhs = call).withMods(meth.mods | Macro | Erased) - case _ => - cpy.DefDef(meth)( - name = normalizeName(meth, tpt).asTermName, - paramss = - elimContextBounds(extParamss, isPrimaryConstructor, true) ++ - elimContextBounds(paramss, isPrimaryConstructor, false) - ) - end elimContextBounds - - private def elimContextBounds(paramss: List[ParamClause], isPrimaryConstructor: Boolean, ext: Boolean)(using Context): List[ParamClause] = val evidenceParamBuf = ListBuffer[ValDef]() def desugarContextBounds(rhs: Tree): Tree = rhs match case ContextBounds(tbounds, cxbounds) => - val iflag = if ext || sourceVersion.isAtLeast(`future`) then Given else Implicit + val iflag = if sourceVersion.isAtLeast(`future`) then Given else Implicit evidenceParamBuf ++= makeImplicitParameters( cxbounds, iflag, forPrimaryConstructor = isPrimaryConstructor) tbounds @@ -257,7 +240,15 @@ object desugar { tparam => cpy.TypeDef(tparam)(rhs = desugarContextBounds(tparam.rhs)) }(identity) - addEvidenceParams(paramssNoContextBounds, evidenceParamBuf.toList) + rhs match + case MacroTree(call) => + cpy.DefDef(meth)(rhs = call).withMods(meth.mods | Macro | Erased) + case _ => + addEvidenceParams( + cpy.DefDef(meth)( + name = normalizeName(meth, tpt).asTermName, + paramss = paramssNoContextBounds), + evidenceParamBuf.toList) end elimContextBounds def addDefaultGetters(meth: DefDef)(using Context): Tree = @@ -357,22 +348,22 @@ object desugar { adaptToExpectedTpt(tree) } - /** Add all evidence parameters in `params` as implicit parameters to `paramss`. - * If the parameters of `paramss` end in an implicit parameter list or using clause, + /** Add all evidence parameters in `params` as implicit parameters to `meth`. + * If the parameters of `meth` end in an implicit parameter list or using clause, * evidence parameters are added in front of that list. Otherwise they are added * as a separate parameter clause. */ - - private def addEvidenceParams(paramss: List[ParamClause], params: List[ValDef])(using Context): List[ParamClause] = - paramss.reverse match - case ValDefs(vparams @ (vparam :: _)) :: rparamss if vparam.mods.isOneOf(GivenOrImplicit) => - ((params ++ vparams) :: rparamss).reverse - case _ => - params match - case Nil => - paramss - case evidenceParams => - paramss :+ evidenceParams + private def addEvidenceParams(meth: DefDef, params: List[ValDef])(using Context): DefDef = + params match + case Nil => + meth + case evidenceParams => + val paramss1 = meth.paramss.reverse match + case ValDefs(vparams @ (vparam :: _)) :: rparamss if vparam.mods.isOneOf(GivenOrImplicit) => + ((evidenceParams ++ vparams) :: rparamss).reverse + case _ => + meth.paramss :+ evidenceParams + cpy.DefDef(meth)(paramss = paramss1) /** The implicit evidence parameters of `meth`, as generated by `desugar.defDef` */ private def evidenceParams(meth: DefDef)(using Context): List[ValDef] = @@ -496,8 +487,9 @@ object desugar { case ddef: DefDef if ddef.name.isConstructorName => decompose( defDef( - cpy.DefDef(ddef)(paramss = addEvidenceParams(joinParams(constrTparams, ddef.paramss), - evidenceParams(constr1).map(toDefParam(_, keepAnnotations = false, keepDefault = false)))))) + addEvidenceParams( + cpy.DefDef(ddef)(paramss = joinParams(constrTparams, ddef.paramss)), + evidenceParams(constr1).map(toDefParam(_, keepAnnotations = false, keepDefault = false))))) case stat => stat } @@ -907,29 +899,34 @@ object desugar { /** Transform extension construct to list of extension methods */ def extMethods(ext: ExtMethods)(using Context): Tree = flatTree { for mdef <- ext.methods yield - def ret(ess: List[ParamClause], mss: List[ParamClause]) = - defDef( - ess, - cpy.DefDef(mdef)( - name = normalizeName(mdef, ext).asTermName, - paramss = mss - ).withMods(mdef.mods | ExtensionMethod) - ) - mdef.paramss match - case params1 :: paramss1 if mdef.name.isRightAssocOperatorName => - def badRightAssoc(problem: String) = - report.error(i"right-associative extension method $problem", mdef.srcPos) - ret(ext.paramss, mdef.paramss) - params1 match - case ValDefs(vparam :: Nil) => - if !vparam.mods.is(Given) then - val (leadingUsing, otherExtParamss) = ext.paramss.span(isUsingOrTypeParamClause) - ret(Nil, leadingUsing ::: params1 :: otherExtParamss ::: paramss1) - else badRightAssoc("cannot start with using clause") + defDef( + cpy.DefDef(mdef)( + name = normalizeName(mdef, ext).asTermName, + paramss = mdef.paramss match + case params1 :: paramss1 if mdef.name.isRightAssocOperatorName => + def badRightAssoc(problem: String) = + report.error(i"right-associative extension method $problem", mdef.srcPos) + ext.paramss ++ mdef.paramss + def noVParam = badRightAssoc("must start with a single parameter") + def checkVparam(params: ParamClause) = params match + case ValDefs(vparam :: Nil) => + if !vparam.mods.is(Given) then + val (leadingUsing, otherExtParamss) = ext.paramss.span(isUsingOrTypeParamClause) + leadingUsing ::: params1 :: otherExtParamss ::: paramss1 + else badRightAssoc("cannot start with using clause") + case _ => + noVParam + params1 match + case TypeDefs(_) => paramss1 match + case params2 :: _ => checkVparam(params2) + case _ => noVParam + case _ => + checkVparam(params1) + case _ => - badRightAssoc("must start with a single parameter") - case _ => - ret(ext.paramss, mdef.paramss) + ext.paramss ++ mdef.paramss + ).withMods(mdef.mods | ExtensionMethod) + ) } /** Transforms diff --git a/tests/neg/i10901.check b/tests/neg/i10901.check index 55a8f23e60ac..01a1cc0cdb21 100644 --- a/tests/neg/i10901.check +++ b/tests/neg/i10901.check @@ -1,18 +1,21 @@ -- [E008] Not Found Error: tests/neg/i10901.scala:45:38 ---------------------------------------------------------------- 45 | val pos1: Point2D[Int,Double] = x º y // error | ^^^ - |value º is not a member of object BugExp4Point2D.IntT. - |An extension method was tried, but could not be fully constructed: + | value º is not a member of object BugExp4Point2D.IntT. + | An extension method was tried, but could not be fully constructed: | - | º(x) failed with + | º(x) failed with | - | Ambiguous overload. The overloaded alternatives of method º in object dsl with types - | [T1, T2] - | (x: BugExp4Point2D.ColumnType[T1]) - | (y: BugExp4Point2D.ColumnType[T2])(using x$3: Numeric[T1], x$4: Numeric[T2]): BugExp4Point2D.Point2D[T1, T2] - | [T1, T2] - | (x: T1)(y: BugExp4Point2D.ColumnType[T2])(using x$3: Numeric[T1], x$4: Numeric[T2]): BugExp4Point2D.Point2D[T1, T2] - | both match arguments ((x : BugExp4Point2D.IntT.type)) + | Ambiguous overload. The overloaded alternatives of method º in object dsl with types + | [T1, T2] + | (x: BugExp4Point2D.ColumnType[T1]) + | (y: BugExp4Point2D.ColumnType[T2]) + | (implicit evidence$7: Numeric[T1], evidence$8: Numeric[T2]): BugExp4Point2D.Point2D[T1, T2] + | [T1, T2] + | (x: T1) + | (y: BugExp4Point2D.ColumnType[T2]) + | (implicit evidence$5: Numeric[T1], evidence$6: Numeric[T2]): BugExp4Point2D.Point2D[T1, T2] + | both match arguments ((x : BugExp4Point2D.IntT.type)) -- [E008] Not Found Error: tests/neg/i10901.scala:48:38 ---------------------------------------------------------------- 48 | val pos4: Point2D[Int,Double] = x º 201.1 // error | ^^^ @@ -23,8 +26,9 @@ | | Ambiguous overload. The overloaded alternatives of method º in object dsl with types | [T1, T2] - | (x: BugExp4Point2D.ColumnType[T1])(y: T2)(using x$3: Numeric[T1], x$4: Numeric[T2]): BugExp4Point2D.Point2D[T1, T2] - | [T1, T2](x: T1)(y: T2)(using x$3: Numeric[T1], x$4: Numeric[T2]): BugExp4Point2D.Point2D[T1, T2] + | (x: BugExp4Point2D.ColumnType[T1]) + | (y: T2)(implicit evidence$9: Numeric[T1], evidence$10: Numeric[T2]): BugExp4Point2D.Point2D[T1, T2] + | [T1, T2](x: T1)(y: T2)(implicit evidence$3: Numeric[T1], evidence$4: Numeric[T2]): BugExp4Point2D.Point2D[T1, T2] | both match arguments ((x : BugExp4Point2D.IntT.type)) -- [E008] Not Found Error: tests/neg/i10901.scala:62:16 ---------------------------------------------------------------- 62 | val y = "abc".foo // error diff --git a/tests/neg/i10901.scala b/tests/neg/i10901.scala index 5ef6d6e08554..19a2e3023c85 100644 --- a/tests/neg/i10901.scala +++ b/tests/neg/i10901.scala @@ -9,27 +9,27 @@ object BugExp4Point2D { object dsl { - extension [T1, T2](x: T1) + extension [T1:Numeric, T2:Numeric](x: T1) // N - N @targetName("point2DConstant") - def º(y: T2)(using Numeric[T1], Numeric[T2]): Point2D[T1,T2] = ??? + def º(y: T2): Point2D[T1,T2] = ??? // N - C @targetName("point2DConstantData") - def º(y: ColumnType[T2])(using Numeric[T1], Numeric[T2]): Point2D[T1,T2] = ??? + def º(y: ColumnType[T2]): Point2D[T1,T2] = ??? - extension [T1, T2](x: ColumnType[T1]) + extension [T1:Numeric, T2:Numeric](x: ColumnType[T1]) // C - C @targetName("point2DData") - def º(y: ColumnType[T2])(using Numeric[T1], Numeric[T2]): Point2D[T1,T2] = ??? + def º(y: ColumnType[T2]): Point2D[T1,T2] = ??? // C - N @targetName("point2DDataConstant") - def º(y: T2)(using Numeric[T1], Numeric[T2]): Point2D[T1,T2] = ??? + def º(y: T2): Point2D[T1,T2] = ??? } diff --git a/tests/neg/missing-implicit1.check b/tests/neg/missing-implicit1.check index f93175f8ea40..4ff1d5d84225 100644 --- a/tests/neg/missing-implicit1.check +++ b/tests/neg/missing-implicit1.check @@ -19,7 +19,7 @@ -- Error: tests/neg/missing-implicit1.scala:23:42 ---------------------------------------------------------------------- 23 | List(1, 2, 3).traverse(x => Option(x)) // error | ^ - |no implicit argument of type testObjectInstance.Zip[Option] was found for parameter x$3 of method traverse in trait Traverse + |no implicit argument of type testObjectInstance.Zip[Option] was found for an implicit parameter of method traverse in trait Traverse | |The following import might fix the problem: | diff --git a/tests/neg/missing-implicit1.scala b/tests/neg/missing-implicit1.scala index f530004fae4f..66c70f446d37 100644 --- a/tests/neg/missing-implicit1.scala +++ b/tests/neg/missing-implicit1.scala @@ -1,7 +1,7 @@ object testObjectInstance: trait Zip[F[_]] trait Traverse[F[_]] { - extension [A, B, G[_]](fa: F[A]) def traverse(f: A => G[B])(using Zip[G]): G[F[B]] + extension [A, B, G[_] : Zip](fa: F[A]) def traverse(f: A => G[B]): G[F[B]] } object instances { diff --git a/tests/neg/missing-implicit4.check b/tests/neg/missing-implicit4.check index 108ceb37cf2f..4653dd8df351 100644 --- a/tests/neg/missing-implicit4.check +++ b/tests/neg/missing-implicit4.check @@ -19,9 +19,9 @@ -- Error: tests/neg/missing-implicit4.scala:20:42 ---------------------------------------------------------------------- 20 | List(1, 2, 3).traverse(x => Option(x)) // error | ^ - | no implicit argument of type Zip[Option] was found for parameter x$3 of method traverse in trait Traverse + |no implicit argument of type Zip[Option] was found for an implicit parameter of method traverse in trait Traverse | - | The following import might fix the problem: + |The following import might fix the problem: | - | import instances.zipOption + | import instances.zipOption | diff --git a/tests/neg/missing-implicit4.scala b/tests/neg/missing-implicit4.scala index 1a22560578b3..317dc516c7c3 100644 --- a/tests/neg/missing-implicit4.scala +++ b/tests/neg/missing-implicit4.scala @@ -1,7 +1,7 @@ def testLocalInstance = trait Zip[F[_]] trait Traverse[F[_]] { - extension [A, B, G[_]](fa: F[A]) def traverse(f: A => G[B])(using Zip[G]): G[F[B]] + extension [A, B, G[_] : Zip](fa: F[A]) def traverse(f: A => G[B]): G[F[B]] } object instances { diff --git a/tests/pos/i11358.scala b/tests/pos/i11358.scala index 3046589fde6b..aa246a45fba4 100644 --- a/tests/pos/i11358.scala +++ b/tests/pos/i11358.scala @@ -9,6 +9,6 @@ object Test: def test7 = +++(IArray(1, 2))[Int](IArray(2, 3)) def test8 = +++(IArray(1, 2))[Int](List(2, 3)) - extension [A](arr: IArray[A]) - def +++[B >: A](suffix: IArray[B])(using reflect.ClassTag[A], reflect.ClassTag[B]): IArray[B] = ??? - def +++[B >: A](suffix: IterableOnce[B])(using reflect.ClassTag[A], reflect.ClassTag[B]): IArray[B] = ??? + 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] = ??? diff --git a/tests/pos/i11583.scala b/tests/pos/i11583.scala new file mode 100644 index 000000000000..d3c3dcb84329 --- /dev/null +++ b/tests/pos/i11583.scala @@ -0,0 +1,2 @@ +extension (s: String) + def :*:[T <: Tuple](that: T) : String *: T = ??? diff --git a/tests/pos/i11586.scala b/tests/pos/i11586.scala deleted file mode 100644 index 5518a61f76e4..000000000000 --- a/tests/pos/i11586.scala +++ /dev/null @@ -1,10 +0,0 @@ -type Conv[T] = [X] =>> X => T - -trait SemiGroup[T]: - extension [U: Conv[T]](x: U) - def combine(y: T): T - extension (x: T) - def combine[U: Conv[T]](y: U): T - -trait Q[T, R: SemiGroup] extends SemiGroup[T]: - def res(x: R, y: R) = x.combine(y)