Skip to content

Commit 9136d78

Browse files
authored
Merge pull request #8017 from dotty-staging/change-given-with
Implement `given/with` syntax
2 parents 347c242 + 744ab30 commit 9136d78

File tree

598 files changed

+3657
-1901
lines changed

Some content is hidden

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

598 files changed

+3657
-1901
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

+2-1
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,8 @@ object desugar {
222222
val epbuf = ListBuffer[ValDef]()
223223
def desugarContextBounds(rhs: Tree): Tree = rhs match {
224224
case ContextBounds(tbounds, cxbounds) =>
225-
epbuf ++= makeImplicitParameters(cxbounds, Implicit, forPrimaryConstructor = isPrimaryConstructor)
225+
val iflag = if ctx.settings.strict.value then Given else Implicit
226+
epbuf ++= makeImplicitParameters(cxbounds, iflag, forPrimaryConstructor = isPrimaryConstructor)
226227
tbounds
227228
case LambdaTypeTree(tparams, body) =>
228229
cpy.LambdaTypeTree(rhs)(tparams, desugarContextBounds(body))

compiler/src/dotty/tools/dotc/ast/untpd.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
471471
def makeAndType(left: Tree, right: Tree)(implicit ctx: Context): AppliedTypeTree =
472472
AppliedTypeTree(ref(defn.andType.typeRef), left :: right :: Nil)
473473

474-
def makeParameter(pname: TermName, tpe: Tree, mods: Modifiers = EmptyModifiers, isBackquoted: Boolean = false)(implicit ctx: Context): ValDef = {
474+
def makeParameter(pname: TermName, tpe: Tree, mods: Modifiers, isBackquoted: Boolean = false)(implicit ctx: Context): ValDef = {
475475
val vdef = ValDef(pname, tpe, EmptyTree)
476476
if (isBackquoted) vdef.pushAttachment(Backquoted, ())
477477
vdef.withMods(mods | Param)

compiler/src/dotty/tools/dotc/core/StdNames.scala

+1
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,7 @@ object StdNames {
412412
val array_length : N = "array_length"
413413
val array_update : N = "array_update"
414414
val arraycopy: N = "arraycopy"
415+
val as: N = "as"
415416
val asTerm: N = "asTerm"
416417
val asModule: N = "asModule"
417418
val asMethod: N = "asMethod"

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

+127-120
Large diffs are not rendered by default.

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

+11-3
Original file line numberDiff line numberDiff line change
@@ -593,7 +593,11 @@ object Scanners {
593593
this.copyFrom(prev)
594594
}
595595

596-
/** - Join CASE + CLASS => CASECLASS, CASE + OBJECT => CASEOBJECT, SEMI + ELSE => ELSE, COLON + <EOL> => COLONEOL
596+
/** - Join CASE + CLASS => CASECLASS,
597+
* CASE + OBJECT => CASEOBJECT,
598+
* SEMI + ELSE => ELSE,
599+
* COLON + <EOL> => COLONEOL
600+
* DOT + WITH => DOTWITH
597601
* - Insert missing OUTDENTs at EOF
598602
*/
599603
def postProcessToken(): Unit = {
@@ -619,6 +623,10 @@ object Scanners {
619623
} else if (token == EOF) { // e.g. when the REPL is parsing "val List(x, y, _*,"
620624
/* skip the trailing comma */
621625
} else reset()
626+
case DOT =>
627+
lookahead()
628+
if token == WITH then fuse(DOTWITH)
629+
else reset()
622630
case COLON =>
623631
if colonSyntax then observeColonEOL()
624632
case EOF | RBRACE =>
@@ -1301,8 +1309,8 @@ object Scanners {
13011309

13021310
override def toString: String =
13031311
showTokenDetailed(token) + {
1304-
if identifierTokens.contains(token) then name
1305-
else if literalTokens.contains(token) then strVal
1312+
if identifierTokens.contains(token) then s" $name"
1313+
else if literalTokens.contains(token) then s" $strVal"
13061314
else ""
13071315
}
13081316

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

+6-3
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,6 @@ object Tokens extends TokensCommon {
189189
/** special symbols */
190190
final val NEWLINE = 78; enter(NEWLINE, "end of statement", "new line")
191191
final val NEWLINES = 79; enter(NEWLINES, "end of statement", "new lines")
192-
final val COLONEOL = 88; enter(COLONEOL, ":", ": at eol")
193192

194193
/** special keywords */
195194
final val USCORE = 73; enter(USCORE, "_")
@@ -200,14 +199,18 @@ object Tokens extends TokensCommon {
200199
final val HASH = 82; enter(HASH, "#")
201200
final val VIEWBOUND = 84; enter(VIEWBOUND, "<%")
202201
final val TLARROW = 85; enter(TLARROW, "=>>")
202+
final val CTXARROW = 86; enter(CTXARROW, "?=>")
203+
204+
final val QUOTE = 87; enter(QUOTE, "'")
203205

204-
final val QUOTE = 86; enter(QUOTE, "'")
206+
final val COLONEOL = 88; enter(COLONEOL, ":", ": at eol")
207+
final val DOTWITH = 89; enter(DOTWITH, ".with")
205208

206209
/** XML mode */
207210
final val XMLSTART = 98; enter(XMLSTART, "$XMLSTART$<") // TODO: deprecate
208211

209212
final val alphaKeywords: TokenSet = tokenRange(IF, MACRO)
210-
final val symbolicKeywords: TokenSet = tokenRange(USCORE, TLARROW)
213+
final val symbolicKeywords: TokenSet = tokenRange(USCORE, CTXARROW)
211214
final val keywords: TokenSet = alphaKeywords | symbolicKeywords
212215

213216
final val allTokens: TokenSet = tokenRange(minToken, maxToken)

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

+11-11
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,9 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
131131
else simpleNameString(tsym)
132132
}
133133

134+
private def arrow(isGiven: Boolean): String =
135+
if isGiven then "?=>" else "=>"
136+
134137
override def toText(tp: Type): Text = controlled {
135138
def toTextTuple(args: List[Type]): Text =
136139
"(" ~ argsText(args) ~ ")"
@@ -145,19 +148,19 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
145148
atPrec(InfixPrec) { argText(args.head) }
146149
else
147150
"("
148-
~ keywordText("given ").provided(isGiven)
149151
~ keywordText("erased ").provided(isErased)
150152
~ argsText(args.init)
151153
~ ")"
152-
argStr ~ " => " ~ argText(args.last)
154+
argStr ~ " " ~ arrow(isGiven) ~ " " ~ argText(args.last)
153155
}
154156

155157
def toTextDependentFunction(appType: MethodType): Text =
156158
"("
157-
~ keywordText("given ").provided(appType.isImplicitMethod)
158159
~ keywordText("erased ").provided(appType.isErasedMethod)
159160
~ paramsText(appType)
160-
~ ") => "
161+
~ ") "
162+
~ arrow(appType.isImplicitMethod)
163+
~ " "
161164
~ toText(appType.resultType)
162165

163166
def isInfixType(tp: Type): Boolean = tp match {
@@ -386,8 +389,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
386389
keywordStr("${") ~ toTextGlobal(args, ", ") ~ keywordStr("}")
387390
else
388391
toTextLocal(fun)
392+
~ ("." ~ keywordText("with")).provided(app.isGivenApply && !homogenizedView)
389393
~ "("
390-
~ keywordText("given ").provided(app.isGivenApply && !homogenizedView)
391394
~ toTextGlobal(args, ", ")
392395
~ ")"
393396
case tree: TypeApply =>
@@ -577,12 +580,11 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
577580
case (arg @ ValDef(_, tpt, _)) :: Nil if tpt.isEmpty => argToText(arg)
578581
case _ =>
579582
"("
580-
~ keywordText("given ").provided(isGiven)
581583
~ keywordText("erased ").provided(isErased)
582584
~ Text(args.map(argToText), ", ")
583585
~ ")"
584586
}
585-
argsText ~ " => " ~ toText(body)
587+
argsText ~ " " ~ arrow(isGiven) ~ " " ~ toText(body)
586588
case PolyFunction(targs, body) =>
587589
val targsText = "[" ~ Text(targs.map((arg: Tree) => toText(arg)), ", ") ~ "]"
588590
changePrec(GlobalPrec) {
@@ -770,10 +772,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
770772
}
771773

772774
private def paramsText[T>: Untyped](params: List[ValDef[T]]) =
773-
"("
774-
~ keywordText("given ").provided(params.nonEmpty && params.head.mods.is(Given))
775-
~ toText(params, ", ")
776-
~ ")"
775+
keywordText(" with ").provided(params.nonEmpty && params.head.mods.is(Given))
776+
~ "(" ~ toText(params, ", ") ~ ")"
777777

778778
protected def defDefToText[T >: Untyped](tree: DefDef[T]): Text = {
779779
import untpd.{modsDeco => _}

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

+15-1
Original file line numberDiff line numberDiff line change
@@ -2654,7 +2654,21 @@ class Typer extends Namer
26542654
else
26552655
tree
26562656
else if (wtp.isContextualMethod)
2657-
adaptNoArgs(wtp) // insert arguments implicitly
2657+
def isContextBoundParams = wtp.stripPoly match
2658+
case MethodType(EvidenceParamName(_) :: _) => true
2659+
case _ => false
2660+
if ctx.settings.migration.value && ctx.settings.strict.value
2661+
&& isContextBoundParams
2662+
then // Under 3.1 and -migration, don't infer implicit arguments yet for parameters
2663+
// coming from context bounds. Issue a warning instead and offer a patch.
2664+
ctx.migrationWarning(
2665+
em"""Context bounds will map to context parameters.
2666+
|A `with` clause is needed to pass explicit arguments to them.
2667+
|This code can be rewritten automatically using -rewrite""", tree.sourcePos)
2668+
patch(Span(tree.span.end), ".with")
2669+
tree
2670+
else
2671+
adaptNoArgs(wtp) // insert arguments implicitly
26582672
else if (tree.symbol.isPrimaryConstructor && tree.symbol.info.firstParamTypes.isEmpty)
26592673
readapt(tree.appliedToNone) // insert () to primary constructors
26602674
else

compiler/test-resources/repl/3932

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
scala> def fun[T](x: T): (given List[T]) => Int = ???
2-
def fun[T](x: T): (given List[T]) => Int
2+
def fun[T](x: T): (List[T]) ?=> Int

0 commit comments

Comments
 (0)