From fdc1ced15b11df57eab76ddb6ffe79ca1486f5dc Mon Sep 17 00:00:00 2001 From: Quentin Bernet Date: Tue, 28 Sep 2021 19:19:22 +0200 Subject: [PATCH 01/11] First working version --- TypesEverywhere.scala | 5 +++ .../dotty/tools/dotc/parsing/Parsers.scala | 44 +++++++++++++++++-- 2 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 TypesEverywhere.scala diff --git a/TypesEverywhere.scala b/TypesEverywhere.scala new file mode 100644 index 000000000000..f96ac8ce9343 --- /dev/null +++ b/TypesEverywhere.scala @@ -0,0 +1,5 @@ +class TypesEverywhere{ + def f1[T](x: T): T = x + def f2[T][U](x: T, y: U): (T, U) = (x, y) + def f3[T](x: T)[U](y: U): (T, U) = (x, y) +} \ No newline at end of file diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 27c1dead4482..34f5e56c701b 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -2890,6 +2890,42 @@ object Parsers { /* -------- PARAMETERS ------------------------------------------- */ + def typeOrTermParamClause(nparams: Int, // number of parameters preceding this clause +// ofClass: Boolean = false, // owner is a class +// ofCaseClass: Boolean = false, // owner is a case class +// prefix: Boolean = false, // clause precedes name of an extension method +// givenOnly: Boolean = false, // only given parameters allowed + firstClause: Boolean = false, // clause is the first in regular list of clauses + ownerKind: ParamOwner.Value + ): List[TypeDef] | List[ValDef] = { + if(in.token == LPAREN){ + paramClause(nparams, firstClause = firstClause) + }else if(in.token == LBRACKET){ + typeParamClause(ownerKind) + }else{ + Nil + } + } + + def typeOrTermParamClauses(nparams: Int, // number of parameters preceding this clause +// ofClass: Boolean = false, // owner is a class +// ofCaseClass: Boolean = false, // owner is a case class +// prefix: Boolean = false, // clause precedes name of an extension method +// givenOnly: Boolean = false, // only given parameters allowed + firstClause: Boolean = false, // clause is the first in regular list of clauses + ownerKind: ParamOwner.Value + ): List[List[TypeDef] | List[ValDef]] = { + def rec(): List[List[TypeDef] | List[ValDef]] = { + val curr = typeOrTermParamClause(nparams,firstClause,ownerKind) + curr match { + case Nil => Nil + case l => curr :: rec() + } + } + rec() + } + + /** ClsTypeParamClause::= ‘[’ ClsTypeParam {‘,’ ClsTypeParam} ‘]’ * ClsTypeParam ::= {Annotation} [‘+’ | ‘-’] * id [HkTypeParamClause] TypeParamBounds @@ -3348,8 +3384,9 @@ object Parsers { val mods1 = addFlag(mods, Method) val ident = termIdent() var name = ident.name.asTermName - val tparams = typeParamClauseOpt(ParamOwner.Def) - val vparamss = paramClauses(numLeadParams = numLeadParams) + val paramss = typeOrTermParamClauses(nparams = numLeadParams, ownerKind = ParamOwner.Def) + //val tparams = typeParamClauseOpt(ParamOwner.Def) + //val vparamss = paramClauses(numLeadParams = numLeadParams) var tpt = fromWithinReturnType { typedOpt() } if (migrateTo3) newLineOptWhenFollowedBy(LBRACE) val rhs = @@ -3367,7 +3404,8 @@ object Parsers { accept(EQUALS) expr() - val ddef = DefDef(name, joinParams(tparams, vparamss), tpt, rhs) + //val ddef = DefDef(name, joinParams(tparams, vparamss), tpt, rhs) + val ddef = DefDef(name, paramss, tpt, rhs) if (isBackquoted(ident)) ddef.pushAttachment(Backquoted, ()) finalizeDef(ddef, mods1, start) } From 708aeae2316722df783e379c7340ada717dd5771 Mon Sep 17 00:00:00 2001 From: Quentin Bernet Date: Tue, 5 Oct 2021 14:28:01 +0200 Subject: [PATCH 02/11] Refactor `typeOrTermParamClauses` and Add tests --- Infer.scala | 18 +++++ TypesEverywhere.scala | 12 +++- .../dotty/tools/dotc/parsing/Parsers.scala | 67 ++++++++++++------- tests/neg/_TypeInterweaving/ab.scala | 8 +++ .../neg/_TypeInterweaving/nameCollision.scala | 2 + tests/pos/_typeInterweaving/ba.scala | 8 +++ .../pos/_typeInterweaving/chainedParams.scala | 6 ++ tests/pos/_typeInterweaving/classless.scala | 2 + .../_typeInterweaving/functorCurrying.scala | 16 +++++ .../functorInterweaving.scala | 16 +++++ .../pos/_typeInterweaving/nameCollision.scala | 3 + 11 files changed, 130 insertions(+), 28 deletions(-) create mode 100644 Infer.scala create mode 100644 tests/neg/_TypeInterweaving/ab.scala create mode 100644 tests/neg/_TypeInterweaving/nameCollision.scala create mode 100644 tests/pos/_typeInterweaving/ba.scala create mode 100644 tests/pos/_typeInterweaving/chainedParams.scala create mode 100644 tests/pos/_typeInterweaving/classless.scala create mode 100644 tests/pos/_typeInterweaving/functorCurrying.scala create mode 100644 tests/pos/_typeInterweaving/functorInterweaving.scala create mode 100644 tests/pos/_typeInterweaving/nameCollision.scala diff --git a/Infer.scala b/Infer.scala new file mode 100644 index 000000000000..27ac557029a0 --- /dev/null +++ b/Infer.scala @@ -0,0 +1,18 @@ +object Infer{ + def r2_[F,G,H](in1: F => (G => H))(in2: F => G )(x: F): H = { + val t1: G => H = in1(x) + val t2: G = in2(x) + val t3: H = t1(t2) + t3 + } + + + given r1[F,G]: ( F => (G => F) ) = x: F => (_ => x) + given r2[F,G,H]: ( (F => (G => H)) => ((F => G) => (F => H)) ) = r2_ + given r3[F,G](using imp: F => G, t: F): G = imp(t) + + def concl[A]: A => A = + summon[A => A] + + @main def main = concl[Int] +} \ No newline at end of file diff --git a/TypesEverywhere.scala b/TypesEverywhere.scala index f96ac8ce9343..ad39b0166780 100644 --- a/TypesEverywhere.scala +++ b/TypesEverywhere.scala @@ -1,5 +1,13 @@ +import scala.annotation.targetName class TypesEverywhere{ def f1[T](x: T): T = x def f2[T][U](x: T, y: U): (T, U) = (x, y) - def f3[T](x: T)[U](y: U): (T, U) = (x, y) -} \ No newline at end of file + def f3[T](x: T)[U <: x.type](y: U): (T, U) = (x, y) + + + + def f4[T](x: T)(y: T) = (x,y) + @targetName("f5") def f4[T](x: T, y: T) = (x,y) +} + + diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 34f5e56c701b..6a4d9ae81352 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -2891,39 +2891,54 @@ object Parsers { /* -------- PARAMETERS ------------------------------------------- */ def typeOrTermParamClause(nparams: Int, // number of parameters preceding this clause -// ofClass: Boolean = false, // owner is a class -// ofCaseClass: Boolean = false, // owner is a case class -// prefix: Boolean = false, // clause precedes name of an extension method -// givenOnly: Boolean = false, // only given parameters allowed + ofClass: Boolean = false, // owner is a class + ofCaseClass: Boolean = false, // owner is a case class + prefix: Boolean = false, // clause precedes name of an extension method + givenOnly: Boolean = false, // only given parameters allowed firstClause: Boolean = false, // clause is the first in regular list of clauses ownerKind: ParamOwner.Value - ): List[TypeDef] | List[ValDef] = { + ): List[TypeDef] | List[ValDef] = if(in.token == LPAREN){ - paramClause(nparams, firstClause = firstClause) + paramClause(nparams, ofClass, ofCaseClass, prefix, givenOnly, firstClause) }else if(in.token == LBRACKET){ typeParamClause(ownerKind) }else{ Nil } - } + end typeOrTermParamClause - def typeOrTermParamClauses(nparams: Int, // number of parameters preceding this clause -// ofClass: Boolean = false, // owner is a class -// ofCaseClass: Boolean = false, // owner is a case class -// prefix: Boolean = false, // clause precedes name of an extension method -// givenOnly: Boolean = false, // only given parameters allowed - firstClause: Boolean = false, // clause is the first in regular list of clauses + def typeOrTermParamClauses( + ofClass: Boolean = false, + ofCaseClass: Boolean = false, + givenOnly: Boolean = false, + numLeadParams: Int = 0, ownerKind: ParamOwner.Value - ): List[List[TypeDef] | List[ValDef]] = { - def rec(): List[List[TypeDef] | List[ValDef]] = { - val curr = typeOrTermParamClause(nparams,firstClause,ownerKind) - curr match { - case Nil => Nil - case l => curr :: rec() - } - } - rec() - } + ): List[List[TypeDef] | List[ValDef]] = + + def recur(firstClause: Boolean, nparams: Int): List[List[TypeDef] | List[ValDef]] = + newLineOptWhenFollowedBy(LPAREN) + newLineOptWhenFollowedBy(LBRACKET) //I have doubts this works + if in.token == LPAREN then + val paramsStart = in.offset + val params = paramClause( + nparams, + ofClass = ofClass, + ofCaseClass = ofCaseClass, + givenOnly = givenOnly, + firstClause = firstClause) + val lastClause = params.nonEmpty && params.head.mods.flags.is(Implicit) + params :: ( + if lastClause then Nil + else recur(firstClause = false, nparams + params.length)) + else if in.token == LBRACKET then + typeParamClause(ownerKind) :: recur(firstClause, nparams) + else Nil + end recur + + //recur(firstClause = true, numLeadParams) + + recur(firstClause = true, nparams = numLeadParams) + end typeOrTermParamClauses /** ClsTypeParamClause::= ‘[’ ClsTypeParam {‘,’ ClsTypeParam} ‘]’ @@ -3384,7 +3399,7 @@ object Parsers { val mods1 = addFlag(mods, Method) val ident = termIdent() var name = ident.name.asTermName - val paramss = typeOrTermParamClauses(nparams = numLeadParams, ownerKind = ParamOwner.Def) + val paramss = typeOrTermParamClauses(numLeadParams = numLeadParams, ownerKind = ParamOwner.Def) //val tparams = typeParamClauseOpt(ParamOwner.Def) //val vparamss = paramClauses(numLeadParams = numLeadParams) var tpt = fromWithinReturnType { typedOpt() } @@ -3527,7 +3542,7 @@ object Parsers { val tparams = typeParamClauseOpt(ParamOwner.Class) val cmods = fromWithinClassConstr(constrModsOpt()) val vparamss = paramClauses(ofClass = true, ofCaseClass = isCaseClass) - makeConstructor(tparams, vparamss).withMods(cmods) + makeConstructor(tparams, vparamss).withMods(cmods) //TODO: Reafactor to take List[List[ValDef] | List[TypeDef]] } /** ConstrMods ::= {Annotation} [AccessModifier] @@ -3628,7 +3643,7 @@ object Parsers { newLineOpt() val vparamss = if in.token == LPAREN && in.lookahead.isIdent(nme.using) - then paramClauses(givenOnly = true) + then paramClauses(givenOnly = true) //TODO: Refactor else Nil newLinesOpt() val noParams = tparams.isEmpty && vparamss.isEmpty diff --git a/tests/neg/_TypeInterweaving/ab.scala b/tests/neg/_TypeInterweaving/ab.scala new file mode 100644 index 000000000000..4f18dc4102b0 --- /dev/null +++ b/tests/neg/_TypeInterweaving/ab.scala @@ -0,0 +1,8 @@ + +given String = "" +given Double = 0 + +def ab[A][B](x: A)(using B): B = summon[B] + +def test = + ab[Int](0: Int) \ No newline at end of file diff --git a/tests/neg/_TypeInterweaving/nameCollision.scala b/tests/neg/_TypeInterweaving/nameCollision.scala new file mode 100644 index 000000000000..bf9d04d7e742 --- /dev/null +++ b/tests/neg/_TypeInterweaving/nameCollision.scala @@ -0,0 +1,2 @@ +def f[T](x: T)[U](y: U) = (x,y) +def f[T](x: T, y: T) = (x,y) \ No newline at end of file diff --git a/tests/pos/_typeInterweaving/ba.scala b/tests/pos/_typeInterweaving/ba.scala new file mode 100644 index 000000000000..58bffb42bcff --- /dev/null +++ b/tests/pos/_typeInterweaving/ba.scala @@ -0,0 +1,8 @@ + +given String = "" +given Double = 0 + +def ba[B][A](x: A)(using B): B = summon[B] + +def test = + ba[String](0) \ No newline at end of file diff --git a/tests/pos/_typeInterweaving/chainedParams.scala b/tests/pos/_typeInterweaving/chainedParams.scala new file mode 100644 index 000000000000..acbc0d259725 --- /dev/null +++ b/tests/pos/_typeInterweaving/chainedParams.scala @@ -0,0 +1,6 @@ + +class Chain{ + type Tail <: Chain +} + +def f[C1 <: Chain](c1: C1)[C2 <: c1.Tail](c2: C2)[C3 <: c2.Tail](c3: C3): c3.Tail = ??? \ No newline at end of file diff --git a/tests/pos/_typeInterweaving/classless.scala b/tests/pos/_typeInterweaving/classless.scala new file mode 100644 index 000000000000..84fef112e96d --- /dev/null +++ b/tests/pos/_typeInterweaving/classless.scala @@ -0,0 +1,2 @@ +def f1[T][U](x: T, y: U): (T, U) = (x, y) +def f2[T](x: T)[U](y: U): (T, U) = (x, y) \ No newline at end of file diff --git a/tests/pos/_typeInterweaving/functorCurrying.scala b/tests/pos/_typeInterweaving/functorCurrying.scala new file mode 100644 index 000000000000..09867ca79009 --- /dev/null +++ b/tests/pos/_typeInterweaving/functorCurrying.scala @@ -0,0 +1,16 @@ +//taken from https://dotty.epfl.ch/docs/reference/contextual/type-classes.html +//at version 3.1.1-RC1-bin-20210930-01f040b-NIGHTLY +//modified to have type currying +trait Functor[F[_]]: + def map[A][B](x: F[A], f: A => B): F[B] + + +given Functor[List] with + def map[A][B](x: List[A], f: A => B): List[B] = + x.map(f) + +def assertTransformation[F[_]: Functor][A][B](expected: F[B], original: F[A], mapping: A => B): Unit = + assert(expected == summon[Functor[F]].map(original, mapping)) + +@main def test = + assertTransformation(List("a1", "b1"), List("a", "b"), elt => s"${elt}1") diff --git a/tests/pos/_typeInterweaving/functorInterweaving.scala b/tests/pos/_typeInterweaving/functorInterweaving.scala new file mode 100644 index 000000000000..14582788d2c4 --- /dev/null +++ b/tests/pos/_typeInterweaving/functorInterweaving.scala @@ -0,0 +1,16 @@ +//taken from https://dotty.epfl.ch/docs/reference/contextual/type-classes.html +//at version 3.1.1-RC1-bin-20210930-01f040b-NIGHTLY +//modified to have type currying +trait Functor[F[_]]: + def map[A][B](x: F[A], f: A => B): F[B] + + +given Functor[List] with + def map[A](x: List[A])[B](f: A => B): List[B] = + x.map(f) + +def assertTransformation[F[_]: Functor][A][B](expected: F[B], original: F[A], mapping: A => B): Unit = + assert(expected == summon[Functor[F]].map(original, mapping)) + +@main def test = + assertTransformation(List("a1", "b1"), List("a", "b"), elt => s"${elt}1") diff --git a/tests/pos/_typeInterweaving/nameCollision.scala b/tests/pos/_typeInterweaving/nameCollision.scala new file mode 100644 index 000000000000..3724d681b8e2 --- /dev/null +++ b/tests/pos/_typeInterweaving/nameCollision.scala @@ -0,0 +1,3 @@ +import scala.annotation.targetName +def f[T](x: T)[U](y: U) = (x,y) +@targetName("g") def f[T](x: T, y: T) = (x,y) \ No newline at end of file From 56f244874a1e6ad373d1e29e927d67c8b507c5d6 Mon Sep 17 00:00:00 2001 From: Quentin Bernet Date: Tue, 5 Oct 2021 17:55:27 +0200 Subject: [PATCH 03/11] Fix `// error` missing from `neg` tests and other details --- compiler/src/dotty/tools/dotc/parsing/Parsers.scala | 10 ++++------ tests/neg/_TypeInterweaving/ab.scala | 2 +- tests/neg/_TypeInterweaving/nameCollision.scala | 2 +- tests/neg/_TypeInterweaving/unmatched1.scala | 2 ++ tests/neg/_TypeInterweaving/unmatched2.scala | 5 +++++ tests/neg/_TypeInterweaving/unmatched3.scala | 3 +++ tests/pos/_typeInterweaving/functorInterweaving.scala | 4 ++-- 7 files changed, 18 insertions(+), 10 deletions(-) create mode 100644 tests/neg/_TypeInterweaving/unmatched1.scala create mode 100644 tests/neg/_TypeInterweaving/unmatched2.scala create mode 100644 tests/neg/_TypeInterweaving/unmatched3.scala diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 6a4d9ae81352..02d1d64e07ab 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -2898,13 +2898,13 @@ object Parsers { firstClause: Boolean = false, // clause is the first in regular list of clauses ownerKind: ParamOwner.Value ): List[TypeDef] | List[ValDef] = - if(in.token == LPAREN){ + if (in.token == LPAREN) paramClause(nparams, ofClass, ofCaseClass, prefix, givenOnly, firstClause) - }else if(in.token == LBRACKET){ + else if (in.token == LBRACKET) typeParamClause(ownerKind) - }else{ + else Nil - } + end typeOrTermParamClause def typeOrTermParamClauses( @@ -2935,8 +2935,6 @@ object Parsers { else Nil end recur - //recur(firstClause = true, numLeadParams) - recur(firstClause = true, nparams = numLeadParams) end typeOrTermParamClauses diff --git a/tests/neg/_TypeInterweaving/ab.scala b/tests/neg/_TypeInterweaving/ab.scala index 4f18dc4102b0..fa4335e4b858 100644 --- a/tests/neg/_TypeInterweaving/ab.scala +++ b/tests/neg/_TypeInterweaving/ab.scala @@ -5,4 +5,4 @@ given Double = 0 def ab[A][B](x: A)(using B): B = summon[B] def test = - ab[Int](0: Int) \ No newline at end of file + ab[Int](0: Int) // error \ No newline at end of file diff --git a/tests/neg/_TypeInterweaving/nameCollision.scala b/tests/neg/_TypeInterweaving/nameCollision.scala index bf9d04d7e742..c85bca1d9c78 100644 --- a/tests/neg/_TypeInterweaving/nameCollision.scala +++ b/tests/neg/_TypeInterweaving/nameCollision.scala @@ -1,2 +1,2 @@ def f[T](x: T)[U](y: U) = (x,y) -def f[T](x: T, y: T) = (x,y) \ No newline at end of file +def f[T](x: T, y: T) = (x,y) // error \ No newline at end of file diff --git a/tests/neg/_TypeInterweaving/unmatched1.scala b/tests/neg/_TypeInterweaving/unmatched1.scala new file mode 100644 index 000000000000..a7fa95595a72 --- /dev/null +++ b/tests/neg/_TypeInterweaving/unmatched1.scala @@ -0,0 +1,2 @@ + +def f1[T (x: T)] = ??? // error diff --git a/tests/neg/_TypeInterweaving/unmatched2.scala b/tests/neg/_TypeInterweaving/unmatched2.scala new file mode 100644 index 000000000000..ca47f7ffbac0 --- /dev/null +++ b/tests/neg/_TypeInterweaving/unmatched2.scala @@ -0,0 +1,5 @@ + + + + +def f2[T(x: T) = ??? // error diff --git a/tests/neg/_TypeInterweaving/unmatched3.scala b/tests/neg/_TypeInterweaving/unmatched3.scala new file mode 100644 index 000000000000..4449ea0b7d48 --- /dev/null +++ b/tests/neg/_TypeInterweaving/unmatched3.scala @@ -0,0 +1,3 @@ + + +def f3(x: Any[)T] = ??? // error diff --git a/tests/pos/_typeInterweaving/functorInterweaving.scala b/tests/pos/_typeInterweaving/functorInterweaving.scala index 14582788d2c4..3e942b5b3704 100644 --- a/tests/pos/_typeInterweaving/functorInterweaving.scala +++ b/tests/pos/_typeInterweaving/functorInterweaving.scala @@ -1,8 +1,8 @@ //taken from https://dotty.epfl.ch/docs/reference/contextual/type-classes.html //at version 3.1.1-RC1-bin-20210930-01f040b-NIGHTLY -//modified to have type currying +//modified to have type interveawing trait Functor[F[_]]: - def map[A][B](x: F[A], f: A => B): F[B] + def map[A](x: F[A])[B](f: A => B): F[B] given Functor[List] with From da7b35c738d140697a505a41b99bac7728ef9bc6 Mon Sep 17 00:00:00 2001 From: Quentin Bernet Date: Tue, 12 Oct 2021 18:44:38 +0200 Subject: [PATCH 04/11] Fix application with multiple type params --- .../dotty/tools/dotc/typer/Applications.scala | 4 ++-- .../higherKindedReturn.scala | 21 +++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 tests/pos/_typeInterweaving/higherKindedReturn.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index ab7187f6f4d4..84f8501273c3 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -1085,8 +1085,8 @@ trait Applications extends Compatibility { val typedArgs = if (isNamed) typedNamedArgs(tree.args) else tree.args.mapconserve(typedType(_)) record("typedTypeApply") typedExpr(tree.fun, PolyProto(typedArgs, pt)) match { - case _: TypeApply if !ctx.isAfterTyper => - errorTree(tree, "illegal repeated type application") + /* case _: TypeApply if !ctx.isAfterTyper => //TODO: assess removing this is okay + errorTree(tree, "illegal repeated type application") */ case typedFn => typedFn.tpe.widen match { case pt: PolyType => diff --git a/tests/pos/_typeInterweaving/higherKindedReturn.scala b/tests/pos/_typeInterweaving/higherKindedReturn.scala new file mode 100644 index 000000000000..3b86cc7ea2d8 --- /dev/null +++ b/tests/pos/_typeInterweaving/higherKindedReturn.scala @@ -0,0 +1,21 @@ +def f_4[T]: [U] => T => T = ??? +def f_3[T][U]: T => T = ??? +def f_2[T][U](): T => T = ??? +def f_1[T <: Int][U <: String](): T => T = ??? +def f0[T <: Int][U <: String]: T => T = ??? +def f1[T <: Int][U <: String]: [X <: Unit] => X => X = ??? +def f2[T <: Int][U <: String](): [X <: Unit] => X => X = ??? +def f3[T <: Int][U <: String]()[X <: Unit]: X => X = ??? + +@main def test = { + f_4[Int][String] //only one that works when lines 1088 to 1089 of Applications.scala are uncommented + f_3[Int][String] + f_2[Int][String]() + f_1[Int][String]() + f0[Int][String] + f1[Int][String] + f1[Int][Unit] + f1[Int][String][Unit] + f2[Int]()[Unit] + f3[Int]()[Unit] +} \ No newline at end of file From 7827971d0b414e8cd1945ae29a4dd371052901e0 Mon Sep 17 00:00:00 2001 From: Quentin Bernet Date: Tue, 12 Oct 2021 18:53:33 +0200 Subject: [PATCH 05/11] Add todo.scala --- tests/pos/_typeInterweaving/todo.scala | 66 ++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 tests/pos/_typeInterweaving/todo.scala diff --git a/tests/pos/_typeInterweaving/todo.scala b/tests/pos/_typeInterweaving/todo.scala new file mode 100644 index 000000000000..cd097ae0d244 --- /dev/null +++ b/tests/pos/_typeInterweaving/todo.scala @@ -0,0 +1,66 @@ + + +def f1[T][U](x: T, y: U): (T, U) = (x, y) +def f2[T](x: T)[U](y: U): (T, U) = (x, y) + + +def foo[T, U][V](x: T): U = ??? + +@main def test = foo[Int] // should probably not work (and doesn't) + +// check ce qui se passe quand appelée +// def f3[T][U]: [X] => F[X] +// done: voir higherKindedReturn.scala + +// reflechir quoi changer dans la spe pour rendre le currying/interweaving dans la doc +// https://www.scala-lang.org/files/archive/spec/2.13/06-expressions.html +// +// Only need to change definitions, as applications can also be of that form, see higherKindedReturn.scala:11 +/* + * in https://www.scala-lang.org/files/archive/spec/2.13/04-basic-declarations-and-definitions.html#function-declarations-and-definitions + * Change: + * + * FunSig ::= id ParamClauses + * ParamClauses ::= ParamClause {ParamClause} + * ParamClause ::= TermParamClause | TypeParamClause | UsingParamClause + * TermParamClause ::= [nl] ‘(’ [TermParams] ‘)’ //note: allows () + * TypeParamClause ::= [nl] ‘[’ TypeParams ‘]’ + * UsingParamClause ::= [nl] ‘(’ ‘using’ TermParams ‘)’ + * + * (slightly simpler but should be equivalent to changes made in Parser.scla) + */ +// same for classes, je suis un peu confus par la syntaxe ci-dessous, notament Annotation et AccessModifiers, ils sont pas là en scala 3, non ? +// https://www.scala-lang.org/files/archive/spec/2.13/05-classes-and-objects.html#class-definitions + +// impl param de classe, déjà Parser + + +// Que faire de TypeDcl ::= id [TypeParamClause] {FunParamClause} TypeBounds [‘=’ Type] //TODO: change to {ParamClauses} ? + + +/* Endroits à changer: (toujour creation et application) + function definition Done + function application Already works + class definition In Progress + class instantiation Might already work + given definition Todo + given application(?) Doesn't exist ? or add multiple params to usings ? + type declarations To be determined + type instantiation Doesn't exist ? + extension definition Todo + extension application Todo + */ + + + +// étapes pour "convaincre" +// 1) exemples simples, et exemples d'utilité +// 2) expliquer intuitivement +// 3) update la doc +// 4) PR et tout le tralala + + +//potentiellement cette feature en experimental + +// eta expension: +val f = foo //should work and doesn't preserve type params yet \ No newline at end of file From 0eb264f65c514acdb58caa5e2759dff40c783309 Mon Sep 17 00:00:00 2001 From: Quentin Bernet Date: Tue, 19 Oct 2021 16:46:02 +0200 Subject: [PATCH 06/11] Remove erroneously added Infer.scala --- Infer.scala | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 Infer.scala diff --git a/Infer.scala b/Infer.scala deleted file mode 100644 index 27ac557029a0..000000000000 --- a/Infer.scala +++ /dev/null @@ -1,18 +0,0 @@ -object Infer{ - def r2_[F,G,H](in1: F => (G => H))(in2: F => G )(x: F): H = { - val t1: G => H = in1(x) - val t2: G = in2(x) - val t3: H = t1(t2) - t3 - } - - - given r1[F,G]: ( F => (G => F) ) = x: F => (_ => x) - given r2[F,G,H]: ( (F => (G => H)) => ((F => G) => (F => H)) ) = r2_ - given r3[F,G](using imp: F => G, t: F): G = imp(t) - - def concl[A]: A => A = - summon[A => A] - - @main def main = concl[Int] -} \ No newline at end of file From 3d2318177ae87e13e9f2960e2328a9c5993cab37 Mon Sep 17 00:00:00 2001 From: Quentin Bernet Date: Tue, 19 Oct 2021 16:53:30 +0200 Subject: [PATCH 07/11] Add test for application with multiple type params --- tests/pos/_typeInterweaving/classless.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/pos/_typeInterweaving/classless.scala b/tests/pos/_typeInterweaving/classless.scala index 84fef112e96d..48f1a8e4d788 100644 --- a/tests/pos/_typeInterweaving/classless.scala +++ b/tests/pos/_typeInterweaving/classless.scala @@ -1,2 +1,4 @@ def f1[T][U](x: T, y: U): (T, U) = (x, y) -def f2[T](x: T)[U](y: U): (T, U) = (x, y) \ No newline at end of file +def f2[T](x: T)[U](y: U): (T, U) = (x, y) + +@main def test = f2(0)[String]("Hello") \ No newline at end of file From ce0ef2318f293647405cdce385dcf6f934c1e196 Mon Sep 17 00:00:00 2001 From: Quentin Bernet Date: Tue, 19 Oct 2021 16:54:30 +0200 Subject: [PATCH 08/11] Refactor functorInterveawing to be more interesting --- tests/pos/_typeInterweaving/functorInterweaving.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/pos/_typeInterweaving/functorInterweaving.scala b/tests/pos/_typeInterweaving/functorInterweaving.scala index 3e942b5b3704..b3daee73d4f7 100644 --- a/tests/pos/_typeInterweaving/functorInterweaving.scala +++ b/tests/pos/_typeInterweaving/functorInterweaving.scala @@ -9,8 +9,8 @@ given Functor[List] with def map[A](x: List[A])[B](f: A => B): List[B] = x.map(f) -def assertTransformation[F[_]: Functor][A][B](expected: F[B], original: F[A], mapping: A => B): Unit = - assert(expected == summon[Functor[F]].map(original, mapping)) +def assertTransformation[F[_]: Functor][A](original: F[A])[B](expected: F[B])(mapping: A => B): Unit = + assert(expected == summon[Functor[F]].map(original)(mapping)) @main def test = - assertTransformation(List("a1", "b1"), List("a", "b"), elt => s"${elt}1") + assertTransformation(List("a", "b"))(List("a1", "b1")){elt => s"${elt}1"} From f324436ec4897f04923748a81a4b8f0da8315531 Mon Sep 17 00:00:00 2001 From: Quentin Bernet Date: Wed, 27 Oct 2021 13:50:30 +0200 Subject: [PATCH 09/11] Refactor `typeOrTermParamClauses` --- .../src/dotty/tools/dotc/parsing/Parsers.scala | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 02d1d64e07ab..96ff73059da6 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -2908,16 +2908,16 @@ object Parsers { end typeOrTermParamClause def typeOrTermParamClauses( + ownerKind: ParamOwner.Value, ofClass: Boolean = false, ofCaseClass: Boolean = false, givenOnly: Boolean = false, - numLeadParams: Int = 0, - ownerKind: ParamOwner.Value + numLeadParams: Int = 0 ): List[List[TypeDef] | List[ValDef]] = def recur(firstClause: Boolean, nparams: Int): List[List[TypeDef] | List[ValDef]] = newLineOptWhenFollowedBy(LPAREN) - newLineOptWhenFollowedBy(LBRACKET) //I have doubts this works + newLineOptWhenFollowedBy(LBRACKET) //I have doubts this works //TODO: test this if in.token == LPAREN then val paramsStart = in.offset val params = paramClause( @@ -3397,7 +3397,7 @@ object Parsers { val mods1 = addFlag(mods, Method) val ident = termIdent() var name = ident.name.asTermName - val paramss = typeOrTermParamClauses(numLeadParams = numLeadParams, ownerKind = ParamOwner.Def) + val paramss = typeOrTermParamClauses(ParamOwner.Def, numLeadParams = numLeadParams) //val tparams = typeParamClauseOpt(ParamOwner.Def) //val vparamss = paramClauses(numLeadParams = numLeadParams) var tpt = fromWithinReturnType { typedOpt() } @@ -3447,7 +3447,7 @@ object Parsers { argumentExprss(mkApply(Ident(nme.CONSTRUCTOR), argumentExprs())) } - /** TypeDcl ::= id [TypeParamClause] {FunParamClause} TypeBounds [‘=’ Type] + /** TypeDcl ::= id [TypeParamClause] {FunParamClause} TypeBounds [‘=’ Type] //TODO: change to {ParamClauses} ? */ def typeDefOrDcl(start: Offset, mods: Modifiers): Tree = { newLinesOpt() @@ -3629,7 +3629,7 @@ object Parsers { } /** GivenDef ::= [GivenSig] (AnnotType [‘=’ Expr] | StructuralInstance) - * GivenSig ::= [id] [DefTypeParamClause] {UsingParamClauses} ‘:’ + * GivenSig ::= [id] [DefTypeParamClause] {UsingParamClauses} ‘:’ //TODO: Change to {Params} */ def givenDef(start: Offset, mods: Modifiers, givenMod: Mod) = atSpan(start, nameStart) { var mods1 = addMod(mods, givenMod) @@ -3641,7 +3641,7 @@ object Parsers { newLineOpt() val vparamss = if in.token == LPAREN && in.lookahead.isIdent(nme.using) - then paramClauses(givenOnly = true) //TODO: Refactor + then paramClauses(givenOnly = true) else Nil newLinesOpt() val noParams = tparams.isEmpty && vparamss.isEmpty @@ -3677,7 +3677,7 @@ object Parsers { } /** Extension ::= ‘extension’ [DefTypeParamClause] {UsingParamClause} ‘(’ DefParam ‘)’ - * {UsingParamClause} ExtMethods + * {UsingParamClause} ExtMethods //TODO: Change to {Params} ? */ def extension(): ExtMethods = val start = in.skipToken() From 785f107f47ee514c1c9650028ab6b7ed6e72909a Mon Sep 17 00:00:00 2001 From: Quentin Bernet Date: Wed, 27 Oct 2021 13:51:14 +0200 Subject: [PATCH 10/11] Update todo.scala and Add examples to debug --- tests/pos/_typeInterweaving/class.scala | 6 ++++ tests/pos/_typeInterweaving/overload.scala | 8 +++++ tests/pos/_typeInterweaving/todo.scala | 38 +++++++++++++++++++--- 3 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 tests/pos/_typeInterweaving/class.scala create mode 100644 tests/pos/_typeInterweaving/overload.scala diff --git a/tests/pos/_typeInterweaving/class.scala b/tests/pos/_typeInterweaving/class.scala new file mode 100644 index 000000000000..84d0a4f3d712 --- /dev/null +++ b/tests/pos/_typeInterweaving/class.scala @@ -0,0 +1,6 @@ + +class C[T](x: T)[U](y: U){ + def pair: (T,U) = (x,y) + def first = x + def second = y +} \ No newline at end of file diff --git a/tests/pos/_typeInterweaving/overload.scala b/tests/pos/_typeInterweaving/overload.scala new file mode 100644 index 000000000000..4a37da5eab4b --- /dev/null +++ b/tests/pos/_typeInterweaving/overload.scala @@ -0,0 +1,8 @@ + +class A{ + def f0[T][U](x: Any) = ??? + def f0[T][U](x: Int) = ??? + + f0(1) + +} \ No newline at end of file diff --git a/tests/pos/_typeInterweaving/todo.scala b/tests/pos/_typeInterweaving/todo.scala index cd097ae0d244..afb8a02a73b2 100644 --- a/tests/pos/_typeInterweaving/todo.scala +++ b/tests/pos/_typeInterweaving/todo.scala @@ -24,15 +24,20 @@ def foo[T, U][V](x: T): U = ??? * ParamClauses ::= ParamClause {ParamClause} * ParamClause ::= TermParamClause | TypeParamClause | UsingParamClause * TermParamClause ::= [nl] ‘(’ [TermParams] ‘)’ //note: allows () - * TypeParamClause ::= [nl] ‘[’ TypeParams ‘]’ + * TypeParamClause ::= [nl] ‘[’ TypeParams ‘]’ * UsingParamClause ::= [nl] ‘(’ ‘using’ TermParams ‘)’ * * (slightly simpler but should be equivalent to changes made in Parser.scla) */ // same for classes, je suis un peu confus par la syntaxe ci-dessous, notament Annotation et AccessModifiers, ils sont pas là en scala 3, non ? // https://www.scala-lang.org/files/archive/spec/2.13/05-classes-and-objects.html#class-definitions +// +// change text to explain application notably when only passed one clause of type params when multiple type clauses expected -// impl param de classe, déjà Parser +// impl param de classe, déjà Parser: Done + + +//add function call to chainedParams // Que faire de TypeDcl ::= id [TypeParamClause] {FunParamClause} TypeBounds [‘=’ Type] //TODO: change to {ParamClauses} ? @@ -42,7 +47,9 @@ def foo[T, U][V](x: T): U = ??? function definition Done function application Already works class definition In Progress - class instantiation Might already work + primary constr In Progress + auxiliary constr In Progress + class instantiation Might already work // see new given definition Todo given application(?) Doesn't exist ? or add multiple params to usings ? type declarations To be determined @@ -63,4 +70,27 @@ def foo[T, U][V](x: T): U = ??? //potentiellement cette feature en experimental // eta expension: -val f = foo //should work and doesn't preserve type params yet \ No newline at end of file +val f = foo //should work and doesn't preserve type params yet + + + + + +//new: +// mettre de coté la partie sur les classes +// fork le repo de la doc est faire changements appropriés +// check overloading resolution +// Applications.scala resolveMapped +// methType +// ProtoTypes.scala + +// check ne passer aucun arguments à une fonction +// voir fichier overload dans pos/interweaving_ +// voir methType +// check occurances de PolyType et PolyProto pour être sûr que ça fonctionne bien avec les [T][U] +// testCompilation + + + +// should we allow fun[L <: List[T]][T] as alias for something like fun[F[_] <: List[]][T][L <: F[T]] +// I'm not sure it's useful \ No newline at end of file From 7b3498dd42fa9034096c9e046acc13d3ab8bf5b7 Mon Sep 17 00:00:00 2001 From: Quentin Bernet Date: Tue, 23 Nov 2021 17:28:59 +0100 Subject: [PATCH 11/11] Add tests --- tests/neg/_TypeInterweaving/params.scala | 5 + tests/pos/_typeInterweaving/newline.scala | 9 ++ tests/pos/_typeInterweaving/overload.scala | 23 ++++- tests/pos/_typeInterweaving/params.scala | 6 ++ tests/pos/_typeInterweaving/todo.scala | 111 ++++++++++++++++----- 5 files changed, 126 insertions(+), 28 deletions(-) create mode 100644 tests/neg/_TypeInterweaving/params.scala create mode 100644 tests/pos/_typeInterweaving/newline.scala create mode 100644 tests/pos/_typeInterweaving/params.scala diff --git a/tests/neg/_TypeInterweaving/params.scala b/tests/neg/_TypeInterweaving/params.scala new file mode 100644 index 000000000000..4ad3a8e2a255 --- /dev/null +++ b/tests/neg/_TypeInterweaving/params.scala @@ -0,0 +1,5 @@ +class Params{ + def bar[T](x: T)[T]: String = ??? // error + def zoo(x: Int)[T, U](x: U): T = ??? // error + def bbb[T <: U](x: U)[U]: U = ??? // error // error +} \ No newline at end of file diff --git a/tests/pos/_typeInterweaving/newline.scala b/tests/pos/_typeInterweaving/newline.scala new file mode 100644 index 000000000000..baddb246fb1e --- /dev/null +++ b/tests/pos/_typeInterweaving/newline.scala @@ -0,0 +1,9 @@ +class Newline { + def multipleLines + [T] + (x: T) + [U] + (using (T,U)) + (y: U) + = ??? +} diff --git a/tests/pos/_typeInterweaving/overload.scala b/tests/pos/_typeInterweaving/overload.scala index 4a37da5eab4b..567ff8b6d9d6 100644 --- a/tests/pos/_typeInterweaving/overload.scala +++ b/tests/pos/_typeInterweaving/overload.scala @@ -1,8 +1,25 @@ class A{ - def f0[T][U](x: Any) = ??? - def f0[T][U](x: Int) = ??? + /* + def f0[T](x: Any) = ??? + def f0[T](x: Int) = ??? + */ - f0(1) + def f1[T][U](x: Any) = ??? + def f1[T][U](x: Int) = ??? + + //f0(1) + f1(1) + f1("hello") + + case class B[U](x: Int) + def b[U](x: Int) = B[U](x) + + def f2[T]: [U] => Int => B[U] = [U] => (x: Int) => b[U](x) + + + f2(1) + f2[Any](1) + f2[Any][Any](1) } \ No newline at end of file diff --git a/tests/pos/_typeInterweaving/params.scala b/tests/pos/_typeInterweaving/params.scala new file mode 100644 index 000000000000..fb55d451b2bd --- /dev/null +++ b/tests/pos/_typeInterweaving/params.scala @@ -0,0 +1,6 @@ +class Params{ + type U + def foo[T](x: T)[U >: x.type <: T][L <: List[U]](l: L): L = ??? + def aaa(x: U): U = ??? + def bbb[T <: U](x: U)[U]: U = ??? +} \ No newline at end of file diff --git a/tests/pos/_typeInterweaving/todo.scala b/tests/pos/_typeInterweaving/todo.scala index afb8a02a73b2..102caa096b4a 100644 --- a/tests/pos/_typeInterweaving/todo.scala +++ b/tests/pos/_typeInterweaving/todo.scala @@ -39,32 +39,28 @@ def foo[T, U][V](x: T): U = ??? //add function call to chainedParams - -// Que faire de TypeDcl ::= id [TypeParamClause] {FunParamClause} TypeBounds [‘=’ Type] //TODO: change to {ParamClauses} ? - - -/* Endroits à changer: (toujour creation et application) +/* Endroits à changer: (toujour creation et application ?) function definition Done function application Already works - class definition In Progress - primary constr In Progress - auxiliary constr In Progress - class instantiation Might already work // see new - given definition Todo - given application(?) Doesn't exist ? or add multiple params to usings ? - type declarations To be determined + class definition Standby + primary constr Standby + auxiliary constr Standby + class instantiation Standby (Might already work // see new) + given definition Todo //yes if given alias, Standby otherwise given name[](using ...)[](using ...) : Classe[Params] + given application(?) Already works ?/standby Doesn't exist ? or add multiple params to usings ? (using name: Class[T]{val x}[U]) + type declarations Standby: because no transformation from F[X,Y] <-> F[X][Y] //is [X,Y] =>> F[X][Y] valid ? type instantiation Doesn't exist ? - extension definition Todo - extension application Todo + extension definition Todo // probably only on right side, since classes do not keep info about params + extension application Todo: tester */ // étapes pour "convaincre" -// 1) exemples simples, et exemples d'utilité -// 2) expliquer intuitivement -// 3) update la doc -// 4) PR et tout le tralala +// 1) exemples simples, et exemples d'utilité TODO +// 2) expliquer intuitivement TODO +// 3) update la doc Done +// 4) PR et tout le tralala TODO //potentiellement cette feature en experimental @@ -77,20 +73,85 @@ val f = foo //should work and doesn't preserve type params yet //new: -// mettre de coté la partie sur les classes -// fork le repo de la doc est faire changements appropriés +// mettre de coté la partie sur les classes: Done +// fork le repo de la doc est faire changements appropriés: Done: https://github.com/scala/scala/pull/9792 // check overloading resolution -// Applications.scala resolveMapped +// Applications.scala resolveMapped //What to do here? // methType // ProtoTypes.scala -// check ne passer aucun arguments à une fonction -// voir fichier overload dans pos/interweaving_ -// voir methType +// check ne passer aucun arguments à une fonction // Je me rappelle pas ce que c'était ... +// voir fichier overload dans pos/interweaving_ // Done +// voir methType // Done ? // check occurances de PolyType et PolyProto pour être sûr que ça fonctionne bien avec les [T][U] +// PolyType: Done in Application.scala +// PolyProto: Done in Application.scala // testCompilation +// Pas eu le temps, mais la PR a lancer des tests, donc 5 qui ont ratés dans une phase +// check def foo[T][T] +// +// is def foo[T](using T)(x: Int) valid ? +/* + * check: done see newline.scala + * def foo + * [T] + * (x: T) + * [U] + * + * and similar + * +*/ // should we allow fun[L <: List[T]][T] as alias for something like fun[F[_] <: List[]][T][L <: F[T]] -// I'm not sure it's useful \ No newline at end of file +// I'm not sure it's useful + + + +// dans docu check "method type" et "poly(morphic) type/method" pour voir si suppositions fausses +// + +// tryApply: +// si f pas fonction, essaie f.apply(...) + + + +// next: +// Relire toute docu: Done +// voir eta expension dans la doc, pour voir comment changer pour polymorphique, ajouter texte qui explique que passe parfois param de type si besoin +// mettre un peu au propre texte PR -> trouver exemples +// essayer given def: Paused + + +/** + * A few comments: + Should handle and test for extension definitions as well. + Should test of overriding and signature check and proper report when signature does not match. + I suggest opening a thread on https://contributors.scala-lang.org/ to discuss this language change. + * + * + * + * + */ + + +// type Z = X =>> F[X] +// def name: [X] => (X, X) => (U) + + +// def foo[T](x: T): T +// val bar = foo + + +// check overload: (should fail) +// def foo(x: Int)(y: String) +// def foo(x: Int)[T](y: String) +// def foo[T](x: Int)(y: String) + + + +// next +// adaptations faitent dans Typer.scala adapt (regarder la fin ou il y a le "vrai" body de la fonction) +// pour rajouter le cas valId3 qui typecheck (les autres cas ce sera pour après) +// https://github.com/lampepfl/dotty/pull/4672