diff --git a/compiler/src/dotty/tools/dotc/core/Annotations.scala b/compiler/src/dotty/tools/dotc/core/Annotations.scala index 88542527442b..f140b9c01077 100644 --- a/compiler/src/dotty/tools/dotc/core/Annotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Annotations.scala @@ -124,7 +124,7 @@ object Annotations { object LazyBodyAnnotation { def apply(bodyFn: Context ?=> Tree): LazyBodyAnnotation = new LazyBodyAnnotation: - protected var myTree: Tree | (Context ?=> Tree) = (using ctx) => bodyFn(using ctx) + protected var myTree: Tree | (Context ?=> Tree) = ctx ?=> bodyFn(using ctx) } object Annotation { @@ -155,15 +155,15 @@ object Annotations { /** Create an annotation where the tree is computed lazily. */ def deferred(sym: Symbol)(treeFn: Context ?=> Tree)(using Context): Annotation = new LazyAnnotation { - protected var myTree: Tree | (Context ?=> Tree) = (using ctx) => treeFn(using ctx) + protected var myTree: Tree | (Context ?=> Tree) = ctx ?=> treeFn(using ctx) protected var mySym: Symbol | (Context ?=> Symbol) = sym } /** Create an annotation where the symbol and the tree are computed lazily. */ def deferredSymAndTree(symFn: Context ?=> Symbol)(treeFn: Context ?=> Tree)(using Context): Annotation = new LazyAnnotation { - protected var mySym: Symbol | (Context ?=> Symbol) = (using ctx) => symFn(using ctx) - protected var myTree: Tree | (Context ?=> Tree) = (using ctx) => treeFn(using ctx) + protected var mySym: Symbol | (Context ?=> Symbol) = ctx ?=> symFn(using ctx) + protected var myTree: Tree | (Context ?=> Tree) = ctx ?=> treeFn(using ctx) } /** Extractor for child annotations */ diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index ce1671e0549a..85e08e2ccd45 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -2506,7 +2506,7 @@ object SymDenotations { } object LazyType: - private val NoSymbolFn = (using _: Context) => NoSymbol + private val NoSymbolFn = (_: Context) ?=> NoSymbol /** A subtrait of LazyTypes where completerTypeParams yields a List[TypeSymbol], which * should be completed independently of the info. diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index d8efa3ca8973..f58202d08967 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -5148,7 +5148,7 @@ object Types { derivedSuperType(tp, this(thistp), this(supertp)) case tp: LazyRef => - LazyRef { (using refCtx) => + LazyRef { refCtx ?=> val ref1 = tp.ref if refCtx.runId == mapCtx.runId then this(ref1) else // splice in new run into map context diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala index 6413c47681ae..c01cb342ffde 100644 --- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala +++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala @@ -587,10 +587,10 @@ class ClassfileParser( } protected var mySym: Symbol | (Context ?=> Symbol) = - (using ctx: Context) => annotType.classSymbol + (ctx: Context) ?=> annotType.classSymbol protected var myTree: Tree | (Context ?=> Tree) = - (using ctx: Context) => untpd.resolveConstructor(annotType, args) + (ctx: Context) ?=> untpd.resolveConstructor(annotType, args) def untpdTree(using Context): untpd.Tree = untpd.New(untpd.TypeTree(annotType), List(args)) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index b305560c77b0..deb024b43ea4 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -603,7 +603,7 @@ class TreeUnpickler(reader: TastyReader, forkAt(templateStart).indexTemplateParams()(using localContext(sym)) } else if (sym.isInlineMethod) - sym.addAnnotation(LazyBodyAnnotation { (using ctx0: Context) => + sym.addAnnotation(LazyBodyAnnotation { (ctx0: Context) ?=> val ctx1 = localContext(sym)(using ctx0).addMode(Mode.ReadPositions) inContext(sourceChangeContext(Addr(0))(using ctx1)) { // avoids space leaks by not capturing the current context diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 5fd6545f1f5d..a580f4f9b166 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -1364,6 +1364,7 @@ object Parsers { val start = in.offset var imods = Modifiers() def functionRest(params: List[Tree]): Tree = + val paramSpan = Span(start, in.lastOffset) atSpan(start, in.offset) { if in.token == TLARROW then if !imods.flags.isEmpty || params.isEmpty then @@ -1382,14 +1383,16 @@ object Parsers { accept(ARROW) val t = typ() - if (imods.isOneOf(Given | Erased)) new FunctionWithMods(params, t, imods) - else if (ctx.settings.YkindProjector.value) { + if imods.isOneOf(Given | Erased) then + if imods.is(Given) && params.isEmpty then + syntaxError("context function types require at least one parameter", paramSpan) + new FunctionWithMods(params, t, imods) + else if ctx.settings.YkindProjector.value then val (newParams :+ newT, tparams) = replaceKindProjectorPlaceholders(params :+ t) lambdaAbstract(tparams, Function(newParams, newT)) - } else { + else Function(params, t) - } } def funArgTypesRest(first: Tree, following: () => Tree) = { val buf = new ListBuffer[Tree] += first @@ -1904,10 +1907,7 @@ object Parsers { def expr(location: Location): Tree = { val start = in.offset - def isSpecialClosureStart = - val lookahead = in.LookaheadScanner() - lookahead.nextToken() - lookahead.isIdent(nme.using) || lookahead.token == ERASED + def isSpecialClosureStart = in.lookahead.token == ERASED if in.token == IMPLICIT then closure(start, location, modifiers(BitSet(IMPLICIT))) else if in.token == LPAREN && isSpecialClosureStart then @@ -2137,9 +2137,7 @@ object Parsers { else openParens.change(LPAREN, 1) var mods1 = mods - if mods.flags.isEmpty then - if isIdent(nme.using) then mods1 = addMod(mods1, atSpan(in.skipToken()) { Mod.Given() }) - if in.token == ERASED then mods1 = addModifier(mods1) + if in.token == ERASED then mods1 = addModifier(mods1) try commaSeparated(() => binding(mods1)) finally @@ -2188,7 +2186,12 @@ object Parsers { def closureRest(start: Int, location: Location, params: List[Tree]): Tree = atSpan(start, in.offset) { - if in.token == CTXARROW then in.nextToken() else accept(ARROW) + if in.token == CTXARROW then + if params.isEmpty then + syntaxError("context function literals require at least one formal parameter", Span(start, in.lastOffset)) + in.nextToken() + else + accept(ARROW) Function(params, if (location == Location.InBlock) block() else expr()) } diff --git a/compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala b/compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala index 332b51b31dae..bc2455c5d5d3 100644 --- a/compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala +++ b/compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala @@ -74,7 +74,7 @@ object PickledQuotes { override def transform(tree: tpd.Tree)(using Context): tpd.Tree = tree match { case Hole(isTerm, idx, args) => val reifiedArgs = args.map { arg => - if (arg.isTerm) (using q: Quotes) => new ExprImpl(arg, QuotesImpl.scopeId) + if (arg.isTerm) (q: Quotes) ?=> new ExprImpl(arg, QuotesImpl.scopeId) else new TypeImpl(arg, QuotesImpl.scopeId) } if isTerm then diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 61eb32bb11f5..bdf992a310ee 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -249,7 +249,7 @@ object Implicits: else val candidates = new mutable.ListBuffer[Candidate] def tryCandidate(extensionOnly: Boolean)(ref: ImplicitRef) = - var ckind = exploreInFreshCtx { (using ctx: FreshContext) => + var ckind = exploreInFreshCtx { (ctx: FreshContext) ?=> ctx.setMode(ctx.mode | Mode.TypevarsMissContext) candidateKind(ref.underlyingRef) } diff --git a/tests/neg/context-function-syntax.scala b/tests/neg/context-function-syntax.scala new file mode 100644 index 000000000000..1f9b74cc69a6 --- /dev/null +++ b/tests/neg/context-function-syntax.scala @@ -0,0 +1,10 @@ +val test = + (using x: Int) => x // error // error + +val f = () ?=> 23 // error +val g: ContextFunction0[Int] = ??? // ok +val h: () ?=> Int = ??? // error + +object Example3 extends App { + final case class Foo[A, B](run: () ?=> Int) // error +} diff --git a/tests/pos-macros/i8302.scala b/tests/pos-macros/i8302.scala index ba82894f83c6..ef930c2e9570 100644 --- a/tests/pos-macros/i8302.scala +++ b/tests/pos-macros/i8302.scala @@ -1,8 +1,7 @@ import scala.quoted._ def foo[T](using Quotes, Type[T]): Expr[Any] = - '{ (using q: Quotes) => + '{ (q: Quotes) ?=> type TT = T val t = Type.of[TT] ??? } - diff --git a/tests/pos-macros/splice-with-explicit-context.scala b/tests/pos-macros/splice-with-explicit-context.scala index a44eb2fcbbae..2e4ba6f7497b 100644 --- a/tests/pos-macros/splice-with-explicit-context.scala +++ b/tests/pos-macros/splice-with-explicit-context.scala @@ -2,6 +2,6 @@ import scala.quoted._ def f(a: Expr[Int])(using q: Quotes): Unit = - '{ val x: Int = ${ (using q2) => a } } + '{ val x: Int = ${ (q2) ?=> a } } - '{ val x: Int = ${ (using q2: q.Nested) => a } } + '{ val x: Int = ${ (q2: q.Nested) ?=> a } } diff --git a/tests/pos/i7778.scala b/tests/pos/i7778.scala index cefed289c819..d786faed7d40 100644 --- a/tests/pos/i7778.scala +++ b/tests/pos/i7778.scala @@ -5,8 +5,3 @@ object Example extends App { object Example2 extends App { final case class Foo[A, B](run: (A, B) ?=> Int) } - - -object Example3 extends App { - final case class Foo[A, B](run: () ?=> Int) -} diff --git a/tests/run-staging/multi-staging.scala b/tests/run-staging/multi-staging.scala index 57e916502022..fb60e07d0de5 100644 --- a/tests/run-staging/multi-staging.scala +++ b/tests/run-staging/multi-staging.scala @@ -13,7 +13,7 @@ object Test { println(run(s1)) } def stage1(x: Expr[Int])(using Quotes): Expr[Quotes ?=> Expr[Int]] = - val code = '{ (using q1: Quotes) => + val code = '{ (q1: Quotes) ?=> val x1 = $x '{ 1 + ${Expr(x1)} } } diff --git a/tests/run-staging/quote-nested-4.scala b/tests/run-staging/quote-nested-4.scala index 95c4491dd9e0..2c80fdf3acad 100644 --- a/tests/run-staging/quote-nested-4.scala +++ b/tests/run-staging/quote-nested-4.scala @@ -5,7 +5,7 @@ object Test { given Toolbox = Toolbox.make(getClass.getClassLoader) def main(args: Array[String]): Unit = withQuotes { - val q = '{ (using q: Quotes) => + val q = '{ (q: Quotes) ?=> val t = Type.of[String] t } diff --git a/tests/run/i10016.scala b/tests/run/i10016.scala index 0b64e1eebb49..475cf0898466 100644 --- a/tests/run/i10016.scala +++ b/tests/run/i10016.scala @@ -2,4 +2,4 @@ def f(init: Int ?=> Int) : Int = 1 def f(s: String)(init: Int ?=> Int) : Int = 2 @main def Test() = - assert(f((using x:Int) => x) == 1) + assert(f((x: Int) ?=> x) == 1)