Skip to content

Implement given/with syntax #8017

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 22 commits into from
Jan 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
167dbb4
Revert "Convert more conditional given instances to new syntax"
odersky Jan 16, 2020
0e4105c
Revert "Tweak syntax of conditions in given instances"
odersky Jan 16, 2020
0d88349
Revert "Fix #7788: Add new syntax for conditional given instances"
odersky Jan 16, 2020
03d0b42
Go back to `given ... as` for instances
odersky Jan 16, 2020
4a2a28d
Update semanticDb check files
odersky Jan 16, 2020
576e535
Change to ?=> for context functions
odersky Jan 17, 2020
823c816
Use `with` for context parameters
odersky Jan 17, 2020
762c644
Adapt printing of context functions to new syntax
odersky Jan 17, 2020
04095bc
Switch to `with` syntax for context parameters
odersky Jan 23, 2020
3f53520
Specify and describe new indentation rules
odersky Jan 18, 2020
1d2c32c
Adapt printing of context parameters and arguments to new syntax
odersky Jan 18, 2020
a660faf
More indentation doc changes
odersky Jan 18, 2020
79359e9
Restore blog post to original form
odersky Jan 18, 2020
96a7a9b
Restore currently valid doc pages to original form
odersky Jan 18, 2020
8e04361
Update docs to `given` ... `with` syntax
odersky Jan 18, 2020
471b9cd
Update comment on tooling
odersky Jan 18, 2020
0e2a86a
Some doc fixes
odersky Jan 19, 2020
8b8a7ff
Imlement new import seclectors for givens
odersky Jan 19, 2020
3290913
Fix typo
odersky Jan 20, 2020
d8a9235
Allow normal parameter clauses after context parameters.
odersky Jan 20, 2020
cdc785f
Doc fixes
odersky Jan 21, 2020
744ab30
Clarify migration of context bounds
odersky Jan 22, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 2 additions & 1 deletion compiler/src/dotty/tools/dotc/ast/Desugar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,8 @@ object desugar {
val epbuf = ListBuffer[ValDef]()
def desugarContextBounds(rhs: Tree): Tree = rhs match {
case ContextBounds(tbounds, cxbounds) =>
epbuf ++= makeImplicitParameters(cxbounds, Implicit, forPrimaryConstructor = isPrimaryConstructor)
val iflag = if ctx.settings.strict.value then Given else Implicit
epbuf ++= makeImplicitParameters(cxbounds, iflag, forPrimaryConstructor = isPrimaryConstructor)
tbounds
case LambdaTypeTree(tparams, body) =>
cpy.LambdaTypeTree(rhs)(tparams, desugarContextBounds(body))
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/ast/untpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
def makeAndType(left: Tree, right: Tree)(implicit ctx: Context): AppliedTypeTree =
AppliedTypeTree(ref(defn.andType.typeRef), left :: right :: Nil)

def makeParameter(pname: TermName, tpe: Tree, mods: Modifiers = EmptyModifiers, isBackquoted: Boolean = false)(implicit ctx: Context): ValDef = {
def makeParameter(pname: TermName, tpe: Tree, mods: Modifiers, isBackquoted: Boolean = false)(implicit ctx: Context): ValDef = {
val vdef = ValDef(pname, tpe, EmptyTree)
if (isBackquoted) vdef.pushAttachment(Backquoted, ())
vdef.withMods(mods | Param)
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/core/StdNames.scala
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,7 @@ object StdNames {
val array_length : N = "array_length"
val array_update : N = "array_update"
val arraycopy: N = "arraycopy"
val as: N = "as"
val asTerm: N = "asTerm"
val asModule: N = "asModule"
val asMethod: N = "asMethod"
Expand Down
247 changes: 127 additions & 120 deletions compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Large diffs are not rendered by default.

14 changes: 11 additions & 3 deletions compiler/src/dotty/tools/dotc/parsing/Scanners.scala
Original file line number Diff line number Diff line change
Expand Up @@ -593,7 +593,11 @@ object Scanners {
this.copyFrom(prev)
}

/** - Join CASE + CLASS => CASECLASS, CASE + OBJECT => CASEOBJECT, SEMI + ELSE => ELSE, COLON + <EOL> => COLONEOL
/** - Join CASE + CLASS => CASECLASS,
* CASE + OBJECT => CASEOBJECT,
* SEMI + ELSE => ELSE,
* COLON + <EOL> => COLONEOL
* DOT + WITH => DOTWITH
* - Insert missing OUTDENTs at EOF
*/
def postProcessToken(): Unit = {
Expand All @@ -619,6 +623,10 @@ object Scanners {
} else if (token == EOF) { // e.g. when the REPL is parsing "val List(x, y, _*,"
/* skip the trailing comma */
} else reset()
case DOT =>
lookahead()
if token == WITH then fuse(DOTWITH)
else reset()
case COLON =>
if colonSyntax then observeColonEOL()
case EOF | RBRACE =>
Expand Down Expand Up @@ -1301,8 +1309,8 @@ object Scanners {

override def toString: String =
showTokenDetailed(token) + {
if identifierTokens.contains(token) then name
else if literalTokens.contains(token) then strVal
if identifierTokens.contains(token) then s" $name"
else if literalTokens.contains(token) then s" $strVal"
else ""
}

Expand Down
9 changes: 6 additions & 3 deletions compiler/src/dotty/tools/dotc/parsing/Tokens.scala
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,6 @@ object Tokens extends TokensCommon {
/** special symbols */
final val NEWLINE = 78; enter(NEWLINE, "end of statement", "new line")
final val NEWLINES = 79; enter(NEWLINES, "end of statement", "new lines")
final val COLONEOL = 88; enter(COLONEOL, ":", ": at eol")

/** special keywords */
final val USCORE = 73; enter(USCORE, "_")
Expand All @@ -200,14 +199,18 @@ object Tokens extends TokensCommon {
final val HASH = 82; enter(HASH, "#")
final val VIEWBOUND = 84; enter(VIEWBOUND, "<%")
final val TLARROW = 85; enter(TLARROW, "=>>")
final val CTXARROW = 86; enter(CTXARROW, "?=>")

final val QUOTE = 87; enter(QUOTE, "'")

final val QUOTE = 86; enter(QUOTE, "'")
final val COLONEOL = 88; enter(COLONEOL, ":", ": at eol")
final val DOTWITH = 89; enter(DOTWITH, ".with")

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

final val alphaKeywords: TokenSet = tokenRange(IF, MACRO)
final val symbolicKeywords: TokenSet = tokenRange(USCORE, TLARROW)
final val symbolicKeywords: TokenSet = tokenRange(USCORE, CTXARROW)
final val keywords: TokenSet = alphaKeywords | symbolicKeywords

final val allTokens: TokenSet = tokenRange(minToken, maxToken)
Expand Down
22 changes: 11 additions & 11 deletions compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
else simpleNameString(tsym)
}

private def arrow(isGiven: Boolean): String =
if isGiven then "?=>" else "=>"

override def toText(tp: Type): Text = controlled {
def toTextTuple(args: List[Type]): Text =
"(" ~ argsText(args) ~ ")"
Expand All @@ -145,19 +148,19 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
atPrec(InfixPrec) { argText(args.head) }
else
"("
~ keywordText("given ").provided(isGiven)
~ keywordText("erased ").provided(isErased)
~ argsText(args.init)
~ ")"
argStr ~ " => " ~ argText(args.last)
argStr ~ " " ~ arrow(isGiven) ~ " " ~ argText(args.last)
}

def toTextDependentFunction(appType: MethodType): Text =
"("
~ keywordText("given ").provided(appType.isImplicitMethod)
~ keywordText("erased ").provided(appType.isErasedMethod)
~ paramsText(appType)
~ ") => "
~ ") "
~ arrow(appType.isImplicitMethod)
~ " "
~ toText(appType.resultType)

def isInfixType(tp: Type): Boolean = tp match {
Expand Down Expand Up @@ -386,8 +389,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
keywordStr("${") ~ toTextGlobal(args, ", ") ~ keywordStr("}")
else
toTextLocal(fun)
~ ("." ~ keywordText("with")).provided(app.isGivenApply && !homogenizedView)
~ "("
~ keywordText("given ").provided(app.isGivenApply && !homogenizedView)
~ toTextGlobal(args, ", ")
~ ")"
case tree: TypeApply =>
Expand Down Expand Up @@ -577,12 +580,11 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
case (arg @ ValDef(_, tpt, _)) :: Nil if tpt.isEmpty => argToText(arg)
case _ =>
"("
~ keywordText("given ").provided(isGiven)
~ keywordText("erased ").provided(isErased)
~ Text(args.map(argToText), ", ")
~ ")"
}
argsText ~ " => " ~ toText(body)
argsText ~ " " ~ arrow(isGiven) ~ " " ~ toText(body)
case PolyFunction(targs, body) =>
val targsText = "[" ~ Text(targs.map((arg: Tree) => toText(arg)), ", ") ~ "]"
changePrec(GlobalPrec) {
Expand Down Expand Up @@ -770,10 +772,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
}

private def paramsText[T>: Untyped](params: List[ValDef[T]]) =
"("
~ keywordText("given ").provided(params.nonEmpty && params.head.mods.is(Given))
~ toText(params, ", ")
~ ")"
keywordText(" with ").provided(params.nonEmpty && params.head.mods.is(Given))
~ "(" ~ toText(params, ", ") ~ ")"

protected def defDefToText[T >: Untyped](tree: DefDef[T]): Text = {
import untpd.{modsDeco => _}
Expand Down
16 changes: 15 additions & 1 deletion compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2654,7 +2654,21 @@ class Typer extends Namer
else
tree
else if (wtp.isContextualMethod)
adaptNoArgs(wtp) // insert arguments implicitly
def isContextBoundParams = wtp.stripPoly match
case MethodType(EvidenceParamName(_) :: _) => true
case _ => false
if ctx.settings.migration.value && ctx.settings.strict.value
&& isContextBoundParams
then // Under 3.1 and -migration, don't infer implicit arguments yet for parameters
// coming from context bounds. Issue a warning instead and offer a patch.
ctx.migrationWarning(
em"""Context bounds will map to context parameters.
|A `with` clause is needed to pass explicit arguments to them.
|This code can be rewritten automatically using -rewrite""", tree.sourcePos)
patch(Span(tree.span.end), ".with")
tree
else
adaptNoArgs(wtp) // insert arguments implicitly
else if (tree.symbol.isPrimaryConstructor && tree.symbol.info.firstParamTypes.isEmpty)
readapt(tree.appliedToNone) // insert () to primary constructors
else
Expand Down
2 changes: 1 addition & 1 deletion compiler/test-resources/repl/3932
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
scala> def fun[T](x: T): (given List[T]) => Int = ???
def fun[T](x: T): (given List[T]) => Int
def fun[T](x: T): (List[T]) ?=> Int
Loading