Skip to content

Drop given parameter syntax #8270

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 5 commits into from
Feb 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ sealed trait CommunityProject:
/** Is this project running in the test or update mode in the
* context of the given suite? @see `run` for more details.
*/
final def isUpdateMode(given suite: CommunityBuildTest) =
final def isUpdateMode(using suite: CommunityBuildTest) =
suite.isInstanceOf[CommunityBuildUpdate]

/** Depending on the mode of operation, either
Expand All @@ -60,7 +60,7 @@ sealed trait CommunityProject:
* and avoid network overhead. See https://github.com/lampepfl/dotty-drone
* for more infrastructural details.
*/
final def run()(given suite: CommunityBuildTest) =
final def run()(using suite: CommunityBuildTest) =
val runCmd = if isUpdateMode then updateCommand else testCommand
if !isUpdateMode then dependencies.foreach(_.publish())
suite.test(project, binaryName, runCommandsArgs :+ runCmd)
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/core/Flags.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ object Flags {

type Flag = opaques.Flag

given extension (x: FlagSet) with
extension on (x: FlagSet) {

def bits: Long = opaques.toBits(x)

Expand Down Expand Up @@ -150,7 +150,7 @@ object Flags {

/** The string representation of the given flag set */
def flagsString: String = x.flagStrings("").mkString(" ")
end given
}

def termFlagSet(x: Long) = FlagSet(TERMS | x)

Expand Down
110 changes: 46 additions & 64 deletions compiler/src/dotty/tools/dotc/parsing/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -917,7 +917,7 @@ object Parsers {
def followingIsParamOrGivenType() =
val lookahead = in.LookaheadScanner()
lookahead.nextToken()
if startParamOrGivenTypeTokens.contains(lookahead.token)
if startParamTokens.contains(lookahead.token)
|| lookahead.isIdent(nme.using)
then true
else if lookahead.token == IDENTIFIER then
Expand Down Expand Up @@ -1450,8 +1450,6 @@ object Parsers {
case MATCH => matchType(t)
case FORSOME => syntaxError(ExistentialTypesNoLongerSupported()); t
case _ =>
if (imods.isOneOf(GivenOrImplicit) && !t.isInstanceOf[FunctionWithMods])
syntaxError(ImplicitTypesCanOnlyBeFunctionTypes(), implicitKwPos(start))
if (imods.is(Erased) && !t.isInstanceOf[FunctionWithMods])
syntaxError(ErasedTypesCanOnlyBeFunctionTypes(), implicitKwPos(start))
t
Expand Down Expand Up @@ -2299,7 +2297,7 @@ object Parsers {
def parArgumentExprs(): (List[Tree], Boolean) = inParens {
if in.token == RPAREN then
(Nil, false)
else if in.token == GIVEN || isIdent(nme.using) then
else if isIdent(nme.using) then
in.nextToken()
(commaSeparated(argumentExpr), true)
else
Expand Down Expand Up @@ -2786,7 +2784,7 @@ object Parsers {
normalize(loop(start))
}

val funTypeArgMods: BitSet = BitSet(GIVEN, ERASED)
val funTypeArgMods: BitSet = BitSet(ERASED)

/** Wrap annotation or constructor in New(...).<init> */
def wrapNew(tpt: Tree): Select = Select(New(tpt), nme.CONSTRUCTOR)
Expand Down Expand Up @@ -2912,7 +2910,7 @@ object Parsers {
def paramMods() =
if in.token == IMPLICIT then addParamMod(() => Mod.Implicit())
else
if in.token == GIVEN || isIdent(nme.using) then addParamMod(() => Mod.Given())
if isIdent(nme.using) then addParamMod(() => Mod.Given())
if in.token == ERASED then addParamMod(() => Mod.Erased())

def param(): ValDef = {
Expand Down Expand Up @@ -3508,70 +3506,54 @@ object Parsers {
var mods1 = addMod(mods, instanceMod)
val hasGivenSig = followingIsGivenSig()
val nameStart = in.offset
val (name, isOldExtension) =
if isIdent && hasGivenSig then
(ident(), in.token == COLON && in.lookaheadIn(nme.extension))
else
(EmptyTermName, isIdent(nme.extension))
val name = if isIdent && hasGivenSig then ident() else EmptyTermName

val gdef = in.endMarkerScope(if name.isEmpty then GIVEN else name) {
if isOldExtension then
if (in.token == COLON) in.nextToken()
assert(ident() == nme.extension)
val tparams = typeParamClauseOpt(ParamOwner.Def)
val extParams = paramClause(0, prefix = true)
val givenParamss = paramClauses(givenOnly = true)
possibleTemplateStart()
val templ = templateBodyOpt(
makeConstructor(tparams, extParams :: givenParamss), Nil, Nil)
templ.body.foreach(checkExtensionMethod(tparams, _))
ModuleDef(name, templ)
else
val hasLabel = !name.isEmpty && in.token == COLON || isIdent(nme.as)
if hasLabel then in.nextToken()
val tparams = typeParamClauseOpt(ParamOwner.Def)
val paramsStart = in.offset
val vparamss =
if in.token == LPAREN && followingIsParamOrGivenType()
then paramClauses()
else Nil
def checkAllGivens(vparamss: List[List[ValDef]], what: String) =
vparamss.foreach(_.foreach(vparam =>
if !vparam.mods.is(Given) then syntaxError(em"$what must be preceded by `using`", vparam.span)))
checkAllGivens(vparamss, "parameter of given instance")
val parents =
if in.token == SUBTYPE && !hasLabel then
if !mods.is(Inline) then
syntaxError("`<:` is only allowed for given with `inline` modifier")
val hasLabel = !name.isEmpty && in.token == COLON || isIdent(nme.as)
if hasLabel then in.nextToken()
val tparams = typeParamClauseOpt(ParamOwner.Def)
val paramsStart = in.offset
val vparamss =
if in.token == LPAREN && followingIsParamOrGivenType()
then paramClauses()
else Nil
def checkAllGivens(vparamss: List[List[ValDef]], what: String) =
vparamss.foreach(_.foreach(vparam =>
if !vparam.mods.is(Given) then syntaxError(em"$what must be preceded by `using`", vparam.span)))
checkAllGivens(vparamss, "parameter of given instance")
val parents =
if in.token == SUBTYPE && !hasLabel then
if !mods.is(Inline) then
syntaxError("`<:` is only allowed for given with `inline` modifier")
in.nextToken()
TypeBoundsTree(EmptyTree, toplevelTyp()) :: Nil
else
if !hasLabel && !(name.isEmpty && tparams.isEmpty && vparamss.isEmpty) then
if in.token == COLON then in.nextToken()
else accept(nme.as)
if in.token == USCORE then
in.nextToken()
accept(SUBTYPE)
TypeBoundsTree(EmptyTree, toplevelTyp()) :: Nil
else
if !hasLabel && !(name.isEmpty && tparams.isEmpty && vparamss.isEmpty) then
if in.token == COLON then in.nextToken()
else accept(nme.as)
if in.token == USCORE then
in.nextToken()
accept(SUBTYPE)
TypeBoundsTree(EmptyTree, toplevelTyp()) :: Nil
else
constrApps(commaOK = true, templateCanFollow = true)
constrApps(commaOK = true, templateCanFollow = true)

if in.token == EQUALS && parents.length == 1 && parents.head.isType then
in.nextToken()
mods1 |= Final
DefDef(name, tparams, vparamss, parents.head, subExpr())
else
parents match
case (_: TypeBoundsTree) :: _ => syntaxError("`=` expected")
case _ =>
possibleTemplateStart()
val tparams1 = tparams.map(tparam => tparam.withMods(tparam.mods | PrivateLocal))
val vparamss1 = vparamss.map(_.map(vparam =>
vparam.withMods(vparam.mods &~ Param | ParamAccessor | PrivateLocal)))
val templ = templateBodyOpt(makeConstructor(tparams1, vparamss1), parents, Nil)
if tparams.isEmpty && vparamss.isEmpty then ModuleDef(name, templ)
else TypeDef(name.toTypeName, templ)
}
if in.token == EQUALS && parents.length == 1 && parents.head.isType then
in.nextToken()
mods1 |= Final
DefDef(name, tparams, vparamss, parents.head, subExpr())
else
parents match
case (_: TypeBoundsTree) :: _ => syntaxError("`=` expected")
case _ =>
possibleTemplateStart()
val tparams1 = tparams.map(tparam => tparam.withMods(tparam.mods | PrivateLocal))
val vparamss1 = vparamss.map(_.map(vparam =>
vparam.withMods(vparam.mods &~ Param | ParamAccessor | PrivateLocal)))
val templ = templateBodyOpt(makeConstructor(tparams1, vparamss1), parents, Nil)
if tparams.isEmpty && vparamss.isEmpty then ModuleDef(name, templ)
else TypeDef(name.toTypeName, templ)
}
finalizeDef(gdef, mods1, start)
}

Expand Down
8 changes: 1 addition & 7 deletions compiler/src/dotty/tools/dotc/parsing/Tokens.scala
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ object Tokens extends TokensCommon {
AT, CASE)

final val canEndStatTokens: TokenSet = atomicExprTokens | BitSet(
TYPE, GIVEN, RPAREN, RBRACE, RBRACKET, OUTDENT)
TYPE, GIVEN, RPAREN, RBRACE, RBRACKET, OUTDENT) // TODO: remove GIVEN once old import syntax is dropped

/** Tokens that stop a lookahead scan search for a `<-`, `then`, or `do`.
* Used for disambiguating between old and new syntax.
Expand All @@ -280,12 +280,6 @@ object Tokens extends TokensCommon {
*/
final val startParamTokens: BitSet = modifierTokens | BitSet(VAL, VAR, AT)

/** Faced with the choice of a type `(...)` or a parameter or given type list
* in `(...)`, the following tokens after the opening `(` determine it's
* a parameter or given type list.
*/
final val startParamOrGivenTypeTokens: BitSet = startParamTokens | BitSet(GIVEN, ERASED)

final val scala3keywords = BitSet(ENUM, ERASED, GIVEN)

final val softModifierNames = Set(nme.inline, nme.opaque, nme.open)
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ class PlainPrinter(_ctx: Context) extends Printer {
case tp: MethodType =>
changePrec(GlobalPrec) {
"("
~ keywordText("given ").provided(tp.isContextualMethod)
~ keywordText("using ").provided(tp.isContextualMethod)
~ keywordText("erased ").provided(tp.isErasedMethod)
~ keywordText("implicit ").provided(tp.isImplicitMethod && !tp.isContextualMethod)
~ paramsText(tp)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ enum ErrorMessageID extends java.lang.Enum[ErrorMessageID] {
UnknownNamedEnclosingClassOrObjectID,
IllegalCyclicTypeReferenceID,
MissingTypeParameterInTypeAppID,
ImplicitTypesCanOnlyBeFunctionTypesID,
UNUSED_ImplicitTypesCanOnlyBeFunctionTypesID,
ErasedTypesCanOnlyBeFunctionTypesID,
CaseClassMissingNonImplicitParamListID,
EnumerationsShouldNotBeEmptyID,
Expand Down
15 changes: 4 additions & 11 deletions compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2376,17 +2376,10 @@ object messages {
""".stripMargin
}

case class IllegalCyclicTypeReference(sym: Symbol, where: String, lastChecked: Type)(implicit val ctx: Context)
extends Message(IllegalCyclicTypeReferenceID) {
val kind: String = "Cyclic"
val msg: String = i"illegal cyclic type reference: ${where} ${hl(lastChecked.show)} of $sym refers back to the type itself"
val explanation: String = ""
}

case class ImplicitTypesCanOnlyBeFunctionTypes()(implicit val ctx: Context) // TODO remove when (given ...) => is removed
extends Message(ImplicitTypesCanOnlyBeFunctionTypesID) {
val kind: String = "Syntax"
val msg: String = "Types with given keyword can only be function types `(given ...) => ...`"
case class IllegalCyclicTypeReference(sym: Symbol, where: String, lastChecked: Type)(implicit val ctx: Context)
extends Message(IllegalCyclicTypeReferenceID) {
val kind: String = "Cyclic"
val msg: String = i"illegal cyclic type reference: ${where} ${hl(lastChecked.show)} of $sym refers back to the type itself"
val explanation: String = ""
}

Expand Down
11 changes: 5 additions & 6 deletions compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ import java.nio.file.Paths

import PartialFunction.condOpt

import ast.untpd.given
import NameOps.given
import ast.untpd.{given _}
import NameOps.{given _}

import scala.annotation.{ threadUnsafe => tu, tailrec }

Expand All @@ -28,8 +28,8 @@ import scala.annotation.{ threadUnsafe => tu, tailrec }
* TODO: Also extract type information
*/
class ExtractSemanticDB extends Phase with
import Scala3.{_, given}
import Symbols.given
import Scala3.{_, given _}
import Symbols.{given _}

override val phaseName: String = ExtractSemanticDB.name

Expand Down Expand Up @@ -509,10 +509,9 @@ class ExtractSemanticDB extends Phase with
else limit
Span(start max limit, end)

private given extension (span: Span) with
private extension on (span: Span):
def hasLength: Boolean = span.start != span.end
def zeroLength: Boolean = span.start == span.end
end given

/**Consume head while not an import statement.
* Returns the rest of the list after the first import, or else the empty list
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/Applications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -863,7 +863,7 @@ trait Applications extends Compatibility {
new ApplyToTyped(tree, fun1, funRef, proto.typedArgs(), pt)
else
new ApplyToUntyped(tree, fun1, funRef, proto, pt)(
given fun1.nullableInArgContext(using argCtx(tree)))
using fun1.nullableInArgContext(using argCtx(tree)))
convertNewGenericArray(
postProcessByNameArgs(funRef, app.result).computeNullable())
case _ =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ trait ImportSuggestions with
try
timer.schedule(task, testOneImplicitTimeOut)
typedImplicit(candidate, expectedType, argument, span)(
given ctx.fresh.setExploreTyperState()).isSuccess
using ctx.fresh.setExploreTyperState()).isSuccess
finally
if task.cancel() then // timer task has not run yet
assert(!ctx.run.isCancelled)
Expand Down
6 changes: 3 additions & 3 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1232,8 +1232,8 @@ class Typer extends Namer

val pat1 = typedPattern(tree.pat, wideSelType)(gadtCtx)
caseRest(pat1)(
given Nullables.caseContext(sel, pat1)(
given gadtCtx.fresh.setNewScope))
using Nullables.caseContext(sel, pat1)(
using gadtCtx.fresh.setNewScope))
}

def typedLabeled(tree: untpd.Labeled)(implicit ctx: Context): Labeled = {
Expand Down Expand Up @@ -2345,7 +2345,7 @@ class Typer extends Namer
// in preceding statements (unless the DefTree is completed ahead of time,
// then it is impossible).
sym.info = Completer(completer.original)(
given completer.creationContext.withNotNullInfos(ctx.notNullInfos))
using completer.creationContext.withNotNullInfos(ctx.notNullInfos))
true
case _ =>
// If it has been completed, then it must be because there is a forward reference
Expand Down
4 changes: 2 additions & 2 deletions compiler/test-resources/repl/defs
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ scala> def id(x: 4): 4 = x
def id(x: 4): 4
scala> id(4)
val res0: Int = 4
scala> def f(given Int) = 1
def f(given x$1: Int): Int
scala> def f(using Int) = 1
def f(using x$1: Int): Int
4 changes: 2 additions & 2 deletions compiler/test-resources/repl/erased-implicit
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
scala> def f(given erased a: Int): Int = ???
def f(given erased a: Int): Int
scala> def f(using erased a: Int): Int = ???
def f(using erased a: Int): Int
17 changes: 2 additions & 15 deletions compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1685,23 +1685,10 @@ class ErrorMessagesTests extends ErrorMessagesTest {
assertEquals("List[X]", lastChecked.show)
}

@Test def implicitTypesCanOnlyBeFunctionTypesSuccess() =
checkMessagesAfter(RefChecks.name) ("def foo(f: (given Int) => Int): Int = 1")
.expectNoErrors

@Test def erasedTypesCanOnlyBeFunctionTypesSuccess() =
checkMessagesAfter(FrontEnd.name) ("def foo(f: (erased Int) => Int): Int = 1")
.expectNoErrors

@Test def implicitTypesCanOnlyBeFunctionTypesFailed() =
checkMessagesAfter(FrontEnd.name) ("def foo(f: (given Int)): Int = 1")
.expect { (ictx, messages) =>
implicit val ctx: Context = ictx
assertMessageCount(1, messages)
val ImplicitTypesCanOnlyBeFunctionTypes() :: Nil = messages
assertEquals("Types with given keyword can only be function types `(given ...) => ...`", messages.head.msg)
}

@Test def erasedTypesCanOnlyBeFunctionTypesFailed() =
checkMessagesAfter(FrontEnd.name) ("def foo(f: (erased Int)): Int = 1")
.expect { (ictx, messages) =>
Expand All @@ -1726,11 +1713,11 @@ class ErrorMessagesTests extends ErrorMessagesTest {
}

@Test def caseClassMissingNonImplicitParamListSuccessful =
checkMessagesAfter(FrontEnd.name) ("case class Test()(given foo: String)")
checkMessagesAfter(FrontEnd.name) ("case class Test()(using foo: String)")
.expectNoErrors

@Test def caseClassMissingNonImplicitParamListFailed =
checkMessagesAfter(FrontEnd.name) ("case class Test(given foo: String)")
checkMessagesAfter(FrontEnd.name) ("case class Test(using foo: String)")
.expect {
(ictx, messages) =>
implicit val ctx: Context = ictx
Expand Down
Loading