Skip to content

Commit 6beb2f4

Browse files
authored
Merge pull request #8283 from dotty-staging/change-given-as
Drop outdated syntax for given instances
2 parents a29178c + 6b676fc commit 6beb2f4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+185
-215
lines changed

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 37 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -910,28 +910,6 @@ object Parsers {
910910
followedByToken(LARROW) // `<-` comes before possible statement starts
911911
}
912912

913-
/** Are the next tokens a prefix of a formal parameter or given type?
914-
* @pre: current token is LPAREN
915-
* TODO: Drop once syntax has stabilized
916-
*/
917-
def followingIsParamOrGivenType() =
918-
val lookahead = in.LookaheadScanner()
919-
lookahead.nextToken()
920-
if startParamTokens.contains(lookahead.token)
921-
|| lookahead.isIdent(nme.using)
922-
then true
923-
else if lookahead.token == IDENTIFIER then
924-
if lookahead.name == nme.inline then
925-
lookahead.nextToken()
926-
if lookahead.token == IDENTIFIER then
927-
lookahead.nextToken()
928-
if lookahead.token == COLON then
929-
lookahead.nextToken()
930-
!lookahead.isAfterLineEnd
931-
else false
932-
else false
933-
else false
934-
935913
/** Are the next token the "GivenSig" part of a given definition,
936914
* i.e. an identifier followed by type and value parameters, followed by `:`?
937915
* @pre The current token is an identifier
@@ -940,14 +918,15 @@ object Parsers {
940918
val lookahead = in.LookaheadScanner()
941919
if lookahead.isIdent then
942920
lookahead.nextToken()
943-
while lookahead.token == LPAREN || lookahead.token == LBRACKET do
944-
lookahead.skipParens()
945-
if lookahead.token == COLON then // TODO: remove
946-
lookahead.nextToken()
947-
!lookahead.isAfterLineEnd
948-
else
949-
lookahead.token == SUBTYPE // TODO: remove
950-
|| lookahead.isIdent(nme.as)
921+
def skipParams(): Unit =
922+
if lookahead.token == LPAREN || lookahead.token == LBRACKET then
923+
lookahead.skipParens()
924+
skipParams()
925+
else if lookahead.isNewLine then
926+
lookahead.nextToken()
927+
skipParams()
928+
skipParams()
929+
lookahead.isIdent(nme.as)
951930

952931
def followingIsExtension() =
953932
val lookahead = in.LookaheadScanner()
@@ -3502,57 +3481,44 @@ object Parsers {
35023481
* | [GivenSig] ConstrApps [TemplateBody]
35033482
* GivenSig ::= [id] [DefTypeParamClause] {UsingParamClauses} ‘as’
35043483
*/
3505-
def givenDef(start: Offset, mods: Modifiers, instanceMod: Mod) = atSpan(start, nameStart) {
3506-
var mods1 = addMod(mods, instanceMod)
3484+
def givenDef(start: Offset, mods: Modifiers, givenMod: Mod) = atSpan(start, nameStart) {
3485+
var mods1 = addMod(mods, givenMod)
35073486
val hasGivenSig = followingIsGivenSig()
35083487
val nameStart = in.offset
35093488
val name = if isIdent && hasGivenSig then ident() else EmptyTermName
35103489

35113490
val gdef = in.endMarkerScope(if name.isEmpty then GIVEN else name) {
3512-
val hasLabel = !name.isEmpty && in.token == COLON || isIdent(nme.as)
3513-
if hasLabel then in.nextToken()
35143491
val tparams = typeParamClauseOpt(ParamOwner.Def)
3515-
val paramsStart = in.offset
3492+
newLineOpt()
35163493
val vparamss =
3517-
if in.token == LPAREN && followingIsParamOrGivenType()
3518-
then paramClauses()
3494+
if in.token == LPAREN && in.lookaheadIn(nme.using)
3495+
then paramClauses(givenOnly = true)
35193496
else Nil
3520-
def checkAllGivens(vparamss: List[List[ValDef]], what: String) =
3521-
vparamss.foreach(_.foreach(vparam =>
3522-
if !vparam.mods.is(Given) then syntaxError(em"$what must be preceded by `using`", vparam.span)))
3523-
checkAllGivens(vparamss, "parameter of given instance")
3524-
val parents =
3525-
if in.token == SUBTYPE && !hasLabel then
3526-
if !mods.is(Inline) then
3527-
syntaxError("`<:` is only allowed for given with `inline` modifier")
3528-
in.nextToken()
3529-
TypeBoundsTree(EmptyTree, toplevelTyp()) :: Nil
3530-
else
3531-
if !hasLabel && !(name.isEmpty && tparams.isEmpty && vparamss.isEmpty) then
3532-
if in.token == COLON then in.nextToken()
3533-
else accept(nme.as)
3534-
if in.token == USCORE then
3535-
in.nextToken()
3536-
accept(SUBTYPE)
3537-
TypeBoundsTree(EmptyTree, toplevelTyp()) :: Nil
3538-
else
3539-
constrApps(commaOK = true, templateCanFollow = true)
3540-
3541-
if in.token == EQUALS && parents.length == 1 && parents.head.isType then
3542-
in.nextToken()
3497+
newLinesOpt()
3498+
if isIdent(nme.as) || !name.isEmpty || !tparams.isEmpty || !vparamss.isEmpty then
3499+
accept(nme.as)
3500+
def givenAlias(tpt: Tree) =
3501+
accept(EQUALS)
35433502
mods1 |= Final
3544-
DefDef(name, tparams, vparamss, parents.head, subExpr())
3503+
DefDef(name, tparams, vparamss, tpt, subExpr())
3504+
if in.token == USCORE then
3505+
if !mods.is(Inline) then
3506+
syntaxError("`_ <:` is only allowed for given with `inline` modifier")
3507+
in.nextToken()
3508+
accept(SUBTYPE)
3509+
givenAlias(TypeBoundsTree(EmptyTree, toplevelTyp()))
35453510
else
3546-
parents match
3547-
case (_: TypeBoundsTree) :: _ => syntaxError("`=` expected")
3548-
case _ =>
3549-
possibleTemplateStart()
3550-
val tparams1 = tparams.map(tparam => tparam.withMods(tparam.mods | PrivateLocal))
3551-
val vparamss1 = vparamss.map(_.map(vparam =>
3552-
vparam.withMods(vparam.mods &~ Param | ParamAccessor | PrivateLocal)))
3553-
val templ = templateBodyOpt(makeConstructor(tparams1, vparamss1), parents, Nil)
3554-
if tparams.isEmpty && vparamss.isEmpty then ModuleDef(name, templ)
3555-
else TypeDef(name.toTypeName, templ)
3511+
val parents = constrApps(commaOK = true, templateCanFollow = true)
3512+
if in.token == EQUALS && parents.length == 1 && parents.head.isType then
3513+
givenAlias(parents.head)
3514+
else
3515+
possibleTemplateStart()
3516+
val tparams1 = tparams.map(tparam => tparam.withMods(tparam.mods | PrivateLocal))
3517+
val vparamss1 = vparamss.map(_.map(vparam =>
3518+
vparam.withMods(vparam.mods &~ Param | ParamAccessor | PrivateLocal)))
3519+
val templ = templateBodyOpt(makeConstructor(tparams1, vparamss1), parents, Nil)
3520+
if tparams.isEmpty && vparamss.isEmpty then ModuleDef(name, templ)
3521+
else TypeDef(name.toTypeName, templ)
35563522
}
35573523
finalizeDef(gdef, mods1, start)
35583524
}

compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ object Scala3 with
212212
// end RangeOps
213213

214214
/** Sort symbol occurrences by their start position. */
215-
given OccurrenceOrdering: Ordering[SymbolOccurrence] = (x, y) =>
215+
given OccurrenceOrdering as Ordering[SymbolOccurrence] = (x, y) =>
216216
x.range -> y.range match
217217
case None -> _ | _ -> None => 0
218218
case Some(a) -> Some(b) =>

compiler/src/dotty/tools/dotc/typer/Applications.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1412,7 +1412,7 @@ trait Applications extends Compatibility {
14121412
/** Widen the result type of synthetic given methods from the implementation class to the
14131413
* type that's implemented. Example
14141414
*
1415-
* given I[X] : T { ... }
1415+
* given I[X] as T { ... }
14161416
*
14171417
* This desugars to
14181418
*
@@ -1422,7 +1422,7 @@ trait Applications extends Compatibility {
14221422
* To compare specificity we should compare with `T`, not with its implementation `I[X]`.
14231423
* No such widening is performed for given aliases, which are not synthetic. E.g.
14241424
*
1425-
* given J[X] : T = rhs
1425+
* given J[X] as T = rhs
14261426
*
14271427
* already has the right result type `T`. Neither is widening performed for given
14281428
* objects, since these are anyway taken to be more specific than methods

compiler/src/dotty/tools/dotc/typer/Deriving.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,11 @@ trait Deriving {
122122
//
123123
// ADT: C[A, B] (A, B have same kinds at T, U)
124124
//
125-
// given derived$TC : TC[ C ] // a "natural" instance
125+
// given derived$TC as TC[ C ] // a "natural" instance
126126
//
127127
// ADT: C[A] (A has same kind as U)
128128
//
129-
// given derived$TC : TC[[t, u] =>> C[ u]]
129+
// given derived$TC as TC[[t, u] =>> C[ u]]
130130
//
131131
// (b) The type class and all ADT type parameters are of kind *
132132
//

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1302,7 +1302,7 @@ class Typer extends Namer
13021302
}
13031303

13041304
def typedWhileDo(tree: untpd.WhileDo)(implicit ctx: Context): Tree = {
1305-
given whileCtx: Context = Nullables.whileContext(tree.span)(using ctx)
1305+
given whileCtx as Context = Nullables.whileContext(tree.span)(using ctx)
13061306
val cond1 =
13071307
if (tree.cond eq EmptyTree) EmptyTree
13081308
else typed(tree.cond, defn.BooleanType)

compiler/test/dotty/tools/repl/ReplCompilerTests.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ class ReplCompilerTests extends ReplTest {
151151
| def (x: T) > (y: T) = compare(x, y) > 0
152152
|}
153153
|
154-
|given IntOrd : Ord[Int] {
154+
|given IntOrd as Ord[Int] {
155155
| def compare(x: Int, y: Int) =
156156
| if (x < y) -1 else if (x > y) +1 else 0
157157
|}

docs/docs/contributing/debugging.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ But you can also do:
8888
assertPositioned(tree.reporting(s"Tree is: $result"))
8989
```
9090

91-
`def (a: A).reporting(f: given WrappedResult[T] => String, p: Printer = Printers.default): A` is defined on all types. The function `f` can be written without the argument since the argument is `given`. The `result` variable is a part of the `WrapperResult` – a tiny framework powering the `reporting` function. Basically, whenever you are using `reporting` on an object `A`, you can use the `result: A` variable from this function and it will be equal to the object you are calling `reporting` on.
91+
`def (a: A).reporting(f: WrappedResult[T] ?=> String, p: Printer = Printers.default): A` is defined on all types. The function `f` can be written without the argument since it is a context function`. The `result` variable is a part of the `WrapperResult` – a tiny framework powering the `reporting` function. Basically, whenever you are using `reporting` on an object `A`, you can use the `result: A` variable from this function and it will be equal to the object you are calling `reporting` on.
9292

9393
## Printing out trees after phases
9494
To print out the trees you are compiling after the FrontEnd (scanner, parser, namer, typer) phases:

0 commit comments

Comments
 (0)