diff --git a/compiler/src/dotty/tools/dotc/ast/untpd.scala b/compiler/src/dotty/tools/dotc/ast/untpd.scala index 428c74c85960..61098a28d6e1 100644 --- a/compiler/src/dotty/tools/dotc/ast/untpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/untpd.scala @@ -132,6 +132,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { case class Implicit()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.ImplicitCommon) + case class Given()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.ImplicitCommon | Flags.Contextual) + case class Erased()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.Erased) case class Final()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.Final) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 6f63373f064c..a031bb98a068 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -100,7 +100,7 @@ class Definitions { * ImplicitFunctionN traits follow this template: * * trait ImplicitFunctionN[T0,...,T{N-1}, R] extends Object { - * def apply with ($x0: T0, ..., $x{N_1}: T{N-1}): R + * def apply given ($x0: T0, ..., $x{N_1}: T{N-1}): R * } * * ErasedFunctionN traits follow this template: @@ -112,7 +112,7 @@ class Definitions { * ErasedImplicitFunctionN traits follow this template: * * trait ErasedImplicitFunctionN[T0,...,T{N-1}, R] extends Object { - * def apply with (erased $x0: T0, ..., $x{N_1}: T{N-1}): R + * def apply given (erased $x0: T0, ..., $x{N_1}: T{N-1}): R * } * * ErasedFunctionN and ErasedImplicitFunctionN erase to Function0. diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index e246bc74f358..b6dab96c1583 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -3879,11 +3879,11 @@ object Types { def selfType(implicit ctx: Context): Type = { if (selfTypeCache == null) selfTypeCache = { - val given = cls.givenSelfType - if (!given.isValueType) appliedRef - else if (cls is Module) given + val givenSelf = cls.givenSelfType + if (!givenSelf.isValueType) appliedRef + else if (cls is Module) givenSelf else if (ctx.erasedTypes) appliedRef - else AndType(given, appliedRef) + else AndType(givenSelf, appliedRef) } selfTypeCache } diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 468e09204434..d23b65909224 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -364,22 +364,22 @@ object Parsers { /** Convert tree to formal parameter list */ - def convertToParams(tree: Tree, mods: Modifiers): List[ValDef] = tree match { - case Parens(t) => convertToParam(t, mods) :: Nil - case Tuple(ts) => ts map (convertToParam(_, mods)) - case t => convertToParam(t, mods) :: Nil + def convertToParams(tree: Tree): List[ValDef] = tree match { + case Parens(t) => convertToParam(t) :: Nil + case Tuple(ts) => ts map (convertToParam(_)) + case t => convertToParam(t) :: Nil } /** Convert tree to formal parameter */ - def convertToParam(tree: Tree, mods: Modifiers, expected: String = "formal parameter"): ValDef = tree match { + def convertToParam(tree: Tree, expected: String = "formal parameter"): ValDef = tree match { case Ident(name) => - makeParameter(name.asTermName, TypeTree(), mods).withSpan(tree.span) + makeParameter(name.asTermName, TypeTree()).withSpan(tree.span) case Typed(Ident(name), tpt) => - makeParameter(name.asTermName, tpt, mods).withSpan(tree.span) + makeParameter(name.asTermName, tpt).withSpan(tree.span) case _ => syntaxError(s"not a legal $expected", tree.span) - makeParameter(nme.ERROR, tree, mods) + makeParameter(nme.ERROR, tree) } /** Convert (qual)ident to type identifier @@ -535,7 +535,7 @@ object Parsers { } else recur(operand()) } - else if (in.token == WITH) { + else if (in.token == GIVEN) { val top1 = reduceStack(base, top, minInfixPrec, leftAssoc = true, nme.WITHkw, isType) assert(opStack `eq` base) val app = atSpan(startOffset(top1), in.offset) { @@ -770,7 +770,7 @@ object Parsers { */ def toplevelTyp(): Tree = checkWildcard(typ()) - /** Type ::= [‘erased’] FunArgTypes (‘=>’ | ‘|=>’) Type + /** Type ::= FunTypeMods FunArgTypes `=>' Type * | HkTypeParamClause `->' Type * | InfixType * FunArgTypes ::= InfixType @@ -779,20 +779,11 @@ object Parsers { */ def typ(): Tree = { val start = in.offset - val imods = modifiers(BitSet(ERASED)) + val imods = modifiers(funTypeMods) def functionRest(params: List[Tree]): Tree = - atSpan(start, in.offset) { - val pmods = - if (in.token == CARROW) { - in.nextToken() - imods | (Contextual | Implicit) - } - else { - accept(ARROW) - imods - } + atSpan(start, accept(ARROW)) { val t = typ() - if (pmods.flags.is(Implicit | Contextual | Erased)) new FunctionWithMods(params, t, pmods) + if (imods.is(Implicit | Contextual | Erased)) new FunctionWithMods(params, t, imods) else Function(params, t) } def funArgTypesRest(first: Tree, following: () => Tree) = { @@ -826,7 +817,7 @@ object Parsers { } openParens.change(LPAREN, -1) accept(RPAREN) - if (imods.is(Implicit) || isValParamList || in.token == ARROW || in.token == CARROW) + if (imods.is(Implicit) || isValParamList || in.token == ARROW) functionRest(ts) else { val ts1 = @@ -858,7 +849,7 @@ object Parsers { else infixType() in.token match { - case ARROW | CARROW => functionRest(t :: Nil) + case ARROW => functionRest(t :: Nil) case MATCH => matchType(EmptyTree, t) case FORSOME => syntaxError(ExistentialTypesNoLongerSupported()); t case _ => @@ -1134,15 +1125,14 @@ object Parsers { } } - /** Expr ::= [FunArgMods] FunParams =>' Expr - * | [‘erased’] FunParams ‘|=>’ Expr + /** Expr ::= [ClosureMods] FunParams =>' Expr * | Expr1 * FunParams ::= Bindings * | id * | `_' * ExprInParens ::= PostfixExpr `:' Type * | Expr - * BlockResult ::= [FunArgMods] FunParams =>' Block + * BlockResult ::= [ClosureMods] FunParams =>' Block * | Expr1 * Expr1 ::= [‘inline’] `if' `(' Expr `)' {nl} Expr [[semi] else Expr] * | [‘inline’] `if' Expr `then' Expr [[semi] else Expr] @@ -1171,8 +1161,8 @@ object Parsers { def expr(location: Location.Value): Tree = { val start = in.offset - if (in.token == IMPLICIT || in.token == ERASED) { - val imods = modifiers(funArgMods) + if (in.token == IMPLICIT || in.token == ERASED || in.token == GIVEN) { + val imods = modifiers(closureMods) if (in.token == MATCH) implicitMatch(start, imods) else implicitClosure(start, location, imods) } else { @@ -1185,11 +1175,9 @@ object Parsers { finally placeholderParams = saved val t = expr1(location) - if (in.token == ARROW || in.token == CARROW) { + if (in.token == ARROW) { placeholderParams = Nil // don't interpret `_' to the left of `=>` as placeholder - val impliedMods = - if (in.token == CARROW) Modifiers(Implicit | Contextual) else EmptyModifiers - wrapPlaceholders(closureRest(start, location, convertToParams(t, impliedMods))) + wrapPlaceholders(closureRest(start, location, convertToParams(t))) } else if (isWildcard(t)) { placeholderParams = placeholderParams ::: saved @@ -1407,8 +1395,7 @@ object Parsers { } else ident() - /** Expr ::= FunArgMods FunParams `=>' Expr - * | [‘erased’] FunParams ‘|=>’ Expr + /** Expr ::= ClosureMods FunParams `=>' Expr * BlockResult ::= implicit id [`:' InfixType] `=>' Block // Scala2 only */ def implicitClosure(start: Int, location: Location.Value, implicitMods: Modifiers): Tree = @@ -1416,19 +1403,8 @@ object Parsers { def closureRest(start: Int, location: Location.Value, params: List[Tree]): Tree = atSpan(start, in.offset) { - val params1 = - if (in.token == CARROW) { - in.nextToken() - params.map { - case param: ValDef => param.withMods(param.mods | (Implicit | Contextual)) - case param => param - } - } - else { - accept(ARROW) - params - } - Function(params1, if (location == Location.InBlock) block() else expr()) + accept(ARROW) + Function(params, if (location == Location.InBlock) block() else expr()) } /** PostfixExpr ::= InfixExpr [id [nl]] @@ -1853,6 +1829,7 @@ object Parsers { case ABSTRACT => Mod.Abstract() case FINAL => Mod.Final() case IMPLICIT => Mod.Implicit() + case GIVEN => Mod.Given() case ERASED => Mod.Erased() case LAZY => Mod.Lazy() case OVERRIDE => Mod.Override() @@ -1949,9 +1926,13 @@ object Parsers { normalize(loop(start)) } - /** FunArgMods ::= { `implicit` | `erased` } + /** FunArgMods ::= { `implicit` | `erased` } + * ClosureMods ::= { ‘implicit’ | ‘erased’ | ‘given’} + * FunTypeMods ::= { ‘erased’ | ‘given’} */ - def funArgMods: BitSet = BitSet(IMPLICIT, ERASED) + val funArgMods: BitSet = BitSet(IMPLICIT, ERASED) + val closureMods: BitSet = BitSet(GIVEN, IMPLICIT, ERASED) + val funTypeMods: BitSet = BitSet(GIVEN, ERASED) /** Wrap annotation or constructor in New(...). */ def wrapNew(tpt: Tree): Select = Select(New(tpt), nme.CONSTRUCTOR) @@ -2038,7 +2019,7 @@ object Parsers { * ClsParams ::= ClsParam {`' ClsParam} * ClsParam ::= {Annotation} [{Modifier} (`val' | `var') | `inline'] Param * DefParamClause ::= [nl] `(' [FunArgMods] [DefParams] ')' | InstParamClause - * InstParamClause ::= ‘with’ (‘(’ [DefParams] ‘)’ | ContextTypes) + * InstParamClause ::= ‘given’ (‘(’ DefParams ‘)’ | ContextTypes) * ContextTypes ::= RefinedType {`,' RefinedType} * DefParams ::= DefParam {`,' DefParam} * DefParam ::= {Annotation} [`inline'] Param @@ -2109,10 +2090,11 @@ object Parsers { // begin paramClause inParens { - if (in.token == RPAREN && !prefix) Nil + val isContextual = impliedMods.is(Contextual) + if (in.token == RPAREN && !prefix && !isContextual) Nil else { def funArgMods(mods: Modifiers): Modifiers = - if (in.token == IMPLICIT && !mods.is(Contextual)) + if (in.token == IMPLICIT && !isContextual) funArgMods(addMod(mods, atSpan(accept(IMPLICIT)) { Mod.Implicit() })) else if (in.token == ERASED) funArgMods(addMod(mods, atSpan(accept(ERASED)) { Mod.Erased() })) @@ -2139,7 +2121,7 @@ object Parsers { ofInstance: Boolean = false): List[List[ValDef]] = { def recur(firstClause: Boolean, nparams: Int): List[List[ValDef]] = { val initialMods = - if (in.token == WITH) { + if (in.token == GIVEN) { in.nextToken() Modifiers(Contextual | Implicit) } @@ -2148,7 +2130,7 @@ object Parsers { newLineOptWhenFollowedBy(LPAREN) if (in.token == LPAREN) { if (ofInstance && !isContextual) - syntaxError(em"parameters of instance definitions must come after `with'") + syntaxError(em"parameters of instance definitions must come after `given'") val params = paramClause( ofClass = ofClass, ofCaseClass = ofCaseClass, @@ -2747,7 +2729,7 @@ object Parsers { case Typed(tree @ This(EmptyTypeIdent), tpt) => self = makeSelfDef(nme.WILDCARD, tpt).withSpan(first.span) case _ => - val ValDef(name, tpt, _) = convertToParam(first, EmptyModifiers, "self type clause") + val ValDef(name, tpt, _) = convertToParam(first, "self type clause") if (name != nme.ERROR) self = makeSelfDef(name, tpt).withSpan(first.span) } @@ -2836,10 +2818,10 @@ object Parsers { stats ++= importClause() else if (isExprIntro) stats += expr(Location.InBlock) - else if (isDefIntro(localModifierTokens)) - if (in.token == IMPLICIT || in.token == ERASED) { + else if (isDefIntro(localModifierTokens) || in.token == GIVEN) // !!!! + if (in.token == IMPLICIT || in.token == ERASED || in.token == GIVEN) { val start = in.offset - var imods = modifiers(funArgMods) + var imods = modifiers(closureMods) if (isBindingIntro) stats += implicitClosure(start, Location.InBlock, imods) else if (in.token == MATCH) diff --git a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala index ec5f0bcf4181..28da40700013 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala @@ -407,6 +407,7 @@ object Scanners { */ protected final def fetchToken(): Unit = { offset = charOffset - 1 + name = null (ch: @switch) match { case ' ' | '\t' | CR | LF | FF => nextChar() diff --git a/compiler/src/dotty/tools/dotc/parsing/Tokens.scala b/compiler/src/dotty/tools/dotc/parsing/Tokens.scala index 06e0118daf59..a11dbec4bea8 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Tokens.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Tokens.scala @@ -112,8 +112,7 @@ abstract class TokensCommon { //final val SUPERTYPE = 81; enter(SUPERTYPE, ">:") //final val HASH = 82; enter(HASH, "#") final val AT = 83; enter(AT, "@") - //final val CARROW = 84; - //final val VIEWBOUND = 85; enter(VIEWBOUND, "<%") // TODO: deprecate + //final val VIEWBOUND = 84; enter(VIEWBOUND, "<%") // TODO: deprecate val keywords: TokenSet @@ -180,6 +179,7 @@ object Tokens extends TokensCommon { final val ENUM = 62; enter(ENUM, "enum") final val ERASED = 63; enter(ERASED, "erased") final val INSTANCE = 64; enter(INSTANCE, "instance") + final val GIVEN = 65; enter(GIVEN, "given") /** special symbols */ final val NEWLINE = 78; enter(NEWLINE, "end of statement", "new line") @@ -192,16 +192,15 @@ object Tokens extends TokensCommon { final val SUBTYPE = 80; enter(SUBTYPE, "<:") final val SUPERTYPE = 81; enter(SUPERTYPE, ">:") final val HASH = 82; enter(HASH, "#") - final val CARROW = 84; enter(CARROW, "|=>") - final val VIEWBOUND = 85; enter(VIEWBOUND, "<%") // TODO: deprecate - final val QPAREN = 86; enter(QPAREN, "'(") - final val QBRACE = 87; enter(QBRACE, "'{") - final val QBRACKET = 88; enter(QBRACKET, "'[") + final val VIEWBOUND = 84; enter(VIEWBOUND, "<%") // TODO: deprecate + final val QPAREN = 85; enter(QPAREN, "'(") + final val QBRACE = 86; enter(QBRACE, "'{") + final val QBRACKET = 87; enter(QBRACKET, "'[") /** XML mode */ final val XMLSTART = 96; enter(XMLSTART, "$XMLSTART$<") // TODO: deprecate - final val alphaKeywords: TokenSet = tokenRange(IF, INSTANCE) + final val alphaKeywords: TokenSet = tokenRange(IF, GIVEN) final val symbolicKeywords: TokenSet = tokenRange(USCORE, VIEWBOUND) final val symbolicTokens: TokenSet = tokenRange(COMMA, VIEWBOUND) final val keywords: TokenSet = alphaKeywords | symbolicKeywords diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index c5d338cd1553..8d977fea1d1c 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -125,13 +125,11 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { else simpleNameString(tsym) } - protected def arrowText(contextual: Boolean): Text = if (contextual) " |=> " else " => " - override def toText(tp: Type): Text = controlled { def toTextTuple(args: List[Type]): Text = "(" ~ argsText(args) ~ ")" - def toTextFunction(args: List[Type], contextual: Boolean, isErased: Boolean): Text = + def toTextFunction(args: List[Type], isContextual: Boolean, isErased: Boolean): Text = changePrec(GlobalPrec) { val argStr: Text = if (args.length == 2 && !defn.isTupleType(args.head)) @@ -139,11 +137,13 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { else toTextTuple(args.init) (keywordText("erased ") provided isErased) ~ - argStr ~ arrowText(contextual) ~ argText(args.last) + (keywordText("given ") provided isContextual) ~ + argStr ~ " => " ~ argText(args.last) } - def toTextDependentFunction(appType: MethodType): Text = - "(" ~ paramsText(appType) ~ ")" ~ arrowText(appType.isContextual) ~ toText(appType.resultType) + def toTextDependentFunction(appType: MethodType): Text = // !!!! + (keywordText("given ") provided appType.isImplicitMethod) ~ + "(" ~ paramsText(appType) ~ ") => " ~ toText(appType.resultType) def isInfixType(tp: Type): Boolean = tp match { case AppliedType(tycon, args) => @@ -530,7 +530,10 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { case (arg @ ValDef(_, tpt, _)) :: Nil if tpt.isEmpty => argToText(arg) case _ => "(" ~ Text(args map argToText, ", ") ~ ")" } - changePrec(GlobalPrec) { argsText ~ arrowText(contextual) ~ toText(body) } + changePrec(GlobalPrec) { + (keywordText("given ") provided contextual) ~ + argsText ~ " => " ~ toText(body) + } case InfixOp(l, op, r) => val opPrec = parsing.precedence(op.name) changePrec(opPrec) { toText(l) ~ " " ~ toText(op) ~ " " ~ toText(r) } diff --git a/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala b/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala index 54c3a8ada151..70e89d5d7ab7 100644 --- a/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala +++ b/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala @@ -178,10 +178,10 @@ object EtaExpansion extends LiftImpure { * { val xs = es; (x1: T1, ..., xn: Tn) => expr(x1, ..., xn) _ } * * where `T1, ..., Tn` are the paremeter types of the expanded method. - * If `expr` has a contectual function type, the arguments are passed with `with`. + * If `expr` has implicit function type, the arguments are passed with `given`. * E.g. for (1): * - * { val xs = es; (x1, ..., xn) => expr with (x1, ..., xn) } + * { val xs = es; (x1, ..., xn) => expr given (x1, ..., xn) } * * Case (3) applies if the method is curried, i.e. its result type is again a method * type. Case (2) applies if the expected arity of the function type `xarity` differs diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index aaf0f2147559..092969fe43ee 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -118,9 +118,9 @@ trait NamerContextOps { this: Context => /** The given type, unless `sym` is a constructor, in which case the * type of the constructed instance is returned */ - def effectiveResultType(sym: Symbol, typeParams: List[Symbol], given: Type): Type = + def effectiveResultType(sym: Symbol, typeParams: List[Symbol], givenTp: Type): Type = if (sym.name == nme.CONSTRUCTOR) sym.owner.typeRef.appliedTo(typeParams.map(_.typeRef)) - else given + else givenTp /** if isConstructor, make sure it has one non-implicit parameter list */ def normalizeIfConstructor(termParamss: List[List[Symbol]], isConstructor: Boolean): List[List[Symbol]] = @@ -131,12 +131,11 @@ trait NamerContextOps { this: Context => termParamss /** The method type corresponding to given parameters and result type */ - def methodType(typeParams: List[Symbol], valueParamss: List[List[Symbol]], resultType: Type, - isJava: Boolean = false, isInstance: Boolean = false)(implicit ctx: Context): Type = { + def methodType(typeParams: List[Symbol], valueParamss: List[List[Symbol]], resultType: Type, isJava: Boolean = false)(implicit ctx: Context): Type = { val monotpe = (valueParamss :\ resultType) { (params, resultType) => val (isImplicit, isErased, isContextual) = - if (params.isEmpty) (isInstance, false, false) + if (params.isEmpty) (false, false, false) else (params.head is Implicit, params.head is Erased, params.head.is(Contextual)) val make = MethodType.maker(isJava = isJava, isImplicit = isImplicit, isErased = isErased, isContextual = isContextual) if (isJava) @@ -1301,8 +1300,7 @@ class Namer { typer: Typer => val termParamss = ctx.normalizeIfConstructor(vparamss.nestedMap(symbolOfTree), isConstructor) def wrapMethType(restpe: Type): Type = { instantiateDependent(restpe, typeParams, termParamss) - ctx.methodType(tparams map symbolOfTree, termParamss, restpe, - isJava = ddef.mods is JavaDefined, isInstance = ddef.mods.hasMod(classOf[Mod.Instance])) + ctx.methodType(tparams map symbolOfTree, termParamss, restpe, isJava = ddef.mods is JavaDefined) } if (isConstructor) { // set result type tree to unit, but take the current class as result type of the symbol diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index c792f939aaf4..118518cf8faf 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -2536,8 +2536,9 @@ class Typer extends Namer ctx.warning(ex"${tree.symbol} is eta-expanded even though $pt does not have the @FunctionalInterface annotation.", tree.sourcePos) case _ => } - simplify(typed(etaExpand(tree, wtp, arity), pt), pt, locked) - } else if (wtp.paramInfos.isEmpty && isAutoApplied(tree.symbol)) + simplify(typed(etaExpand(tree, wtp, arity), pt), pt, locked) + } + else if (wtp.paramInfos.isEmpty && isAutoApplied(tree.symbol)) readaptSimplified(tpd.Apply(tree, Nil)) else if (wtp.isImplicitMethod) err.typeMismatch(tree, pt) diff --git a/compiler/test-resources/repl/3932 b/compiler/test-resources/repl/3932 index 4a3e16000756..2751fa1fee7f 100644 --- a/compiler/test-resources/repl/3932 +++ b/compiler/test-resources/repl/3932 @@ -1,2 +1,2 @@ -scala> def fun[T](x: T): List[T] |=> Int = ??? -def fun[T](x: T): List[T] |=> Int +scala> def fun[T](x: T): given List[T] => Int = ??? +def fun[T](x: T): given List[T] => Int diff --git a/docs/docs/internals/syntax.md b/docs/docs/internals/syntax.md index b399d22cc476..07bc05822dd8 100644 --- a/docs/docs/internals/syntax.md +++ b/docs/docs/internals/syntax.md @@ -92,10 +92,11 @@ semi ::= ‘;’ | nl {nl} ``` abstract case catch class def do else enum -erased extends false final finally for if implicit -import lazy match new null object package private -protected override return super sealed then throw trait -true try type val var while with yield +erased extends false final finally for given if +implicit import instance lazy match new null object +package private protected override return super sealed then +throw trait true try type val var while +with yield : = <- => <: :> # @ ``` @@ -136,11 +137,10 @@ ClassQualifier ::= ‘[’ id ‘]’ ### Types ```ebnf -Type ::= [‘erased’] FunArgTypes (‘=>’ | ‘|=>’) Type Function(ts, t) +Type ::= { ‘erased’ | ‘given’} FunArgTypes ‘=>’ Type Function(ts, t) | HkTypeParamClause ‘=>’ Type TypeLambda(ps, t) | MatchType | InfixType -FunArgMods ::= { ‘implicit’ | ‘erased’ } FunArgTypes ::= InfixType | ‘(’ [ FunArgType {‘,’ FunArgType } ] ‘)’ | ‘(’ TypedFunParam {‘,’ TypedFunParam } ‘)’ @@ -175,10 +175,9 @@ TypeParamBounds ::= TypeBounds {‘<%’ Type} {‘:’ Type} ### Expressions ```ebnf -Expr ::= [FunArgMods] FunParams ‘=>’ Expr Function(args, expr), Function(ValDef([implicit], id, TypeTree(), EmptyTree), expr) - | [‘erased’] FunParams ‘|=>’ Expr +Expr ::= [ClosureMods] FunParams ‘=>’ Expr Function(args, expr), Function(ValDef([implicit], id, TypeTree(), EmptyTree), expr) | Expr1 -BlockResult ::= [FunArgMods] FunParams ‘=>’ Block +BlockResult ::= [ClosureMods] FunParams ‘=>’ Block | Expr1 FunParams ::= Bindings | id @@ -205,7 +204,7 @@ Catches ::= ‘catch’ Expr PostfixExpr ::= InfixExpr [id] PostfixOp(expr, op) InfixExpr ::= PrefixExpr | InfixExpr id [nl] InfixExpr InfixOp(expr, op, expr) - | InfixExpr ‘with’ (InfixExpr | ParArgumentExprs) + | InfixExpr ‘given’ (InfixExpr | ParArgumentExprs) PrefixExpr ::= [‘-’ | ‘+’ | ‘~’ | ‘!’] SimpleExpr PrefixOp(expr, op) SimpleExpr ::= ‘new’ (ConstrApp [TemplateBody] | TemplateBody) New(constr | templ) | BlockExpr @@ -290,7 +289,7 @@ HkTypeParam ::= {Annotation} [‘+’ | ‘-’] (Id[HkTypeParamClause] | ClsParamClauses ::= {ClsParamClause} ClsParamClause ::= [nl] ‘(’ [[FunArgMods] ClsParams] ‘)’ - | ‘with’ (‘(’ ([[FunArgMods] ClsParams] ‘)’ | ContextTypes) + | ‘given’ (‘(’ ([[FunArgMods] ClsParams] ‘)’ | ContextTypes) ClsParams ::= ClsParam {‘,’ ClsParam} ClsParam ::= {Annotation} ValDef(mods, id, tpe, expr) -- point of mods on val/var [{Modifier} (‘val’ | ‘var’) | ‘inline’] Param @@ -299,10 +298,12 @@ Param ::= id ‘:’ ParamType [‘=’ Expr] DefParamClauses ::= {DefParamClause} [[nl] ‘(’ [FunArgMods] DefParams ‘)’] DefParamClause ::= [nl] ‘(’ [DefParams] ‘)’ | InstParamClause -InstParamClause ::= ‘with’ (‘(’ [DefParams] ‘)’ | ContextTypes) +InstParamClause ::= ‘given’ (‘(’ [DefParams] ‘)’ | ContextTypes) DefParams ::= DefParam {‘,’ DefParam} DefParam ::= {Annotation} [‘inline’] Param ValDef(mods, id, tpe, expr) -- point of mods at id. ContextTypes ::= RefinedType {‘,’ RefinedType} +FunArgMods ::= { ‘implicit’ | ‘erased’ } +ClosureMods ::= { ‘implicit’ | ‘erased’ | ‘given’} ``` ### Bindings and Imports diff --git a/docs/docs/reference/instances/context-params.md b/docs/docs/reference/instances/context-params.md index ef58b3d82ece..471c6081b86f 100644 --- a/docs/docs/reference/instances/context-params.md +++ b/docs/docs/reference/instances/context-params.md @@ -1,69 +1,68 @@ --- layout: doc-page -title: "Context Parameters and Arguments" +title: "Implicit Parameters and Arguments" --- -Context parameters are the name of a new syntax for implicit parameters that aligns definition and call syntax. Parameter definitions -and method arguments both follow a `with` connective. On the definition side, the old syntax +A new syntax for implicit parameters aligns definition and call syntax. Parameter definitions and method arguments both follow a `given` keyword. On the definition side, the old syntax ```scala def f(a: A)(implicit b: B) ``` is now expressed as ```scala -def f(a: A) with (b: B) +def f(a: A) given (b: B) ``` or, leaving out the parameter name, ```scala -def f(a: A) with B +def f(a: A) given B ``` Implicit parameters defined with the new syntax are also called _context parameters_. -They come with a matching syntax for applications: explicit arguments for context parameters are also given after a `with`. +They come with a matching syntax for applications: explicit arguments for context parameters are also written after a `given`. The following example shows shows three methods that each have a context parameter for `Ord[T]`. ```scala -def maximum[T](xs: List[T]) with Ord[T]: T = +def maximum[T](xs: List[T]) given Ord[T]: T = xs.reduceLeft((x, y) => if (x < y) y else x) -def descending[T] with (asc: Ord[T]): Ord[T] = new Ord[T] { +def descending[T] given (asc: Ord[T]): Ord[T] = new Ord[T] { def (x: T) compareTo (y: T) = asc.compareTo(y)(x) } -def minimum[T](xs: List[T]) with Ord[T] = - maximum(xs) with descending +def minimum[T](xs: List[T]) given Ord[T] = + maximum(xs) given descending ``` The `minimum` method's right hand side passes `descending` as an explicit argument to `maximum(xs)`. But usually, explicit arguments for context parameters are be left out. For instance, given `xs: List[Int]`, the following calls are all possible (and they all normalize to the last one:) ```scala maximum(xs) -maximum(xs) with descending -maximum(xs) with (descending with IntOrd) +maximum(xs) given descending +maximum(xs) given (descending given IntOrd) ``` -Arguments for context parameters must be given using the `with` syntax. So the expression `maximum(xs)(descending)` would give a type error. +Arguments for context parameters must use the `given` syntax. So the expression `maximum(xs)(descending)` would produce a type error. -The `with` connective is treated like an infix operator with the same precedence as other operators that start with a letter. The expression following a `with` may also be an argument list consisting of several implicit arguments separated by commas. If a tuple should be passed as a single implicit argument (probably an uncommon case), it has to be put in a pair of extra parentheses: +The `given` connective is treated like an infix operator with the same precedence as other operators that start with a letter. The expression following a `given` may also be an argument list consisting of several implicit arguments separated by commas. If a tuple should be passed as a single implicit argument (probably an uncommon case), it has to be put in a pair of extra parentheses: ```scala -def f with (x: A, y: B) -f with (a, b) +def f given (x: A, y: B) +f given (a, b) -def g with (xy: (A, B)) -g with ((a, b)) +def g given (xy: (A, B)) +g given ((a, b)) ``` Unlike existing implicit parameters, context parameters can be freely mixed with normal parameter lists. A context parameter may be followed by a normal parameter and _vice versa_. There can be several context parameter lists in a definition. Example: ```scala -def f with (u: Universe) (x: u.T) with Context = ... +def f given (u: Universe) (x: u.T) given Context = ... -instance global for Universe { type T = String ... } -instance ctx for Context { ... } +instance global of Universe { type T = String ... } +instance ctx of Context { ... } ``` Then the following calls are all valid (and normalize to the last one) ```scala f("abc") -(f with global)("abc") -f("abc") with ctx -(f with global)("abc") with ctx +(f given global)("abc") +f("abc") given ctx +(f given global)("abc") given ctx ``` Context parameters may be given either as a normal parameter list `(...)` or as a sequence of types. To distinguish the two, a leading `(` always indicates a parameter list. @@ -81,9 +80,9 @@ def summon[T] with (x: T) = x Here is the new syntax of parameters and arguments seen as a delta from the [standard context free syntax of Scala 3](http://dotty.epfl.ch/docs/internals/syntax.html). ``` ClsParamClause ::= ... - | ‘with’ (‘(’ [ClsParams] ‘)’ | ContextTypes) + | ‘given’ (‘(’ [ClsParams] ‘)’ | ContextTypes) DefParamClause ::= ... | InstParamClause InfixExpr ::= ... - | InfixExpr ‘with’ (InfixExpr | ParArgumentExprs) + | InfixExpr ‘given’ (InfixExpr | ParArgumentExprs) ``` diff --git a/docs/docs/reference/instances/discussion/motivation.md b/docs/docs/reference/instances/discussion/motivation.md index 8df60ed25258..9fc239406404 100644 --- a/docs/docs/reference/instances/discussion/motivation.md +++ b/docs/docs/reference/instances/discussion/motivation.md @@ -33,13 +33,16 @@ Can implicit function types help? Implicit function types allow to abstract over ### Alternative Design -`implicit` is a modifier that gets attached to various constructs. I.e. we talk about implicit vals, defs, objects, parameters, or arguments. This conveys mechanism rather than intent. What _is_ the intent that we want to convey? Ultimately it's "trade types for terms". The programmer specifies a type and the compiler fills in the term matching that type automatically. So the concept we are after would serve to express definitions that provide the canonical _instances_ for certain types. - -The next sections elaborate such an alternative design. It consists of three proposals: - - - A proposal to replace implicit _definitions_ by [instance definitions](./instance-defs.html). - - A proposal for a [new syntax](./context-params.html) of implicit _parameters_ and their _arguments_. - - A proposal to [replace all remaining usages](./replacing-implicits.html) of `implicit` in the language. - -The first two proposals are independent of each other. The last one would work only if the first two are adopted. -A [discussion page](./discussion.html) summarizes and evaluates the proposal. +`implicit` is a modifier that gets attached to various constructs. +I.e. we talk about implicit vals, defs, objects, parameters, or arguments. +This conveys mechanism rather than intent. What _is_ the intent that we want to convey? +Ultimately it's "trade types for terms". The programmer specifies a type and the compiler +fills in the term matching that type automatically. So the concept we are after would +serve to express definitions that provide the canonical _instances_ for certain types. + +The next sections elaborate this alternative design. It consists of the following pages: + + - a proposal to replace implicit _definitions_ by [instance definitions](./instance-defs.md), + - a proposal for a [new syntax](./context-params.md) of implicit _parameters_ and their _arguments_, + - updates to the syntax for [implicit function types and closures](./implicit-function-types.md), + - a new way to express [implicit conversions](./implicit-conversions.md) as instances of a special trait, diff --git a/docs/docs/reference/instances/implicit-conversions.md b/docs/docs/reference/instances/implicit-conversions.md new file mode 100644 index 000000000000..b41bc675ec34 --- /dev/null +++ b/docs/docs/reference/instances/implicit-conversions.md @@ -0,0 +1,78 @@ +--- +layout: doc-page +title: "Implicit Conversions" +--- + +Implicit conversions are defined by instances of the `scala.Conversion` class. +This class is defined in package `scala` as follows: +```scala +abstract class Conversion[-T, +U] extends (T => U) +``` +For example, here is an implicit conversion from `String` to `Token`: +```scala +instance of Conversion[String, Token] { + def apply(str: String): Token = new KeyWord(str) +} +``` +An implicit conversion is applied automatically by the compiler in three situations: + +1. If an expression `e` has type `T`, and `T` does not conform to the expression's expected type `S`. +2. In a selection `e.m` with `e` of type `T`, but `T` defines no member `m`. +3. In an application `e.m(args)` with `e` of type `T`, if ``T` does define + some member(s) named `m`, but none of these members can be applied to the arguments `args`. + +In the first case, the compiler looks in the implicit scope for a an instance of +`scala.Conversion` that maps an argument of type `T` to type `S`. In the second and third +case, it looks for an instance of `scala.Conversion` that maps an argument of type `T` +to a type that defines a member `m` which can be applied to `args` if present. +If such an instance `C` is found, the expression `e` is replaced by `C.apply(e)`. + +## Examples + +1. The `Predef` package contains "auto-boxing" conversions that map +primitive number types to subclasses of `java.lang.Number`. For instance, the +conversion from `Int` to `java.lang.Integer` can be defined as follows: +```scala +instance int2Integer of Conversion[Int, java.lang.Integer] { + def apply(x: Int) = new java.lang.Integer(x) +} +``` + +2. The "magnet" pattern is sometimes used to express many variants of a method. Instead of defining overloaded versions of the method, one can also let the method take one or more arguments of specially defined "magnet" types, into which various argument types can be converted. E.g. +```scala +object Completions { + + // The argument "magnet" type + enum CompletionArg { + case Error(s: String) + case Response(f: Future[HttpResponse]) + case Status(code: Future[StatusCode]) + } + object CompletionArg { + + // conversions defining the possible arguments to pass to `complete` + // these always come with CompletionArg + // They can be invoked explicitly, e.g. + // + // CompletionArg.from(statusCode) + + instance from of Conversion[String, CompletionArg] { + def apply(s: String) = CompletionArg.Error(s) + } + instance from of Conversion[Future[HttpResponse], CompletionArg] { + def apply(f: Future[HttpResponse]) = CompletionArg.Response(f) + } + instance from of Conversion[Future[StatusCode], CompletionArg] { + def apply(code: Future[StatusCode]) = CompletionArg.Status(code) + } + } + import CompletionArg._ + + def complete[T](arg: CompletionArg) = arg match { + case Error(s) => ... + case Response(f) => ... + case Status(code) => ... + } +} +``` +This setup is more complicated than simple overloading of `complete`, but it can still be useful if normal overloading is not available (as in the case above, since we cannot have two overloaded methods that take `Future[...]` arguments), or if normal overloading would lead to a combinatorial explosion of variants. diff --git a/docs/docs/reference/instances/implicit-function-types-spec.md b/docs/docs/reference/instances/implicit-function-types-spec.md index 80f50964e586..f70a128baa73 100644 --- a/docs/docs/reference/instances/implicit-function-types-spec.md +++ b/docs/docs/reference/instances/implicit-function-types-spec.md @@ -8,12 +8,12 @@ Initial implementation in (#1775)[https://github.com/lampepfl/dotty/pull/1775]. ## Syntax Type ::= ... - | FunArgTypes `|=>' Type + | `given' FunArgTypes `=>' Type Expr ::= ... - | FunParams `|=>' Expr + | `given' FunParams `=>' Expr Implicit function types associate to the right, e.g. -`S |=> T => U` is the same as `S => (T => U)`. +`given S => given T => U` is the same as `given S => (given T => U)`. ## Implementation @@ -31,7 +31,7 @@ trait ImplicitFunctionN[-T1 , ... , -TN, +R] { Implicit function types erase to normal function types, so these classes are generated on the fly for typechecking, but not realized in actual code. -Anonymous implicit function values `(x1: T1, ..., xn: Tn) |=> e` map +Anonymous implicit function values `given (x1: T1, ..., xn: Tn) => e` map implicit parameters `xi` of types `Ti` to a result given by expression `e`. The scope of each implicit parameter `xi` is `e`. Implicit parameters must have pairwise distinct names. @@ -53,8 +53,8 @@ expression: def apply with (x1: T1, ..., xn: Tn): T = e } -In the case of a single untyped implicit parameter, `(x) |=> e` can be -abbreviated to `x |=> e`. +In the case of a single untyped implicit parameter, `given (x) => e` can be +abbreviated to `given x => e`. A implicit parameter may also be a wildcard represented by an underscore `_`. In that case, a fresh name for the parameter is chosen arbitrarily. @@ -64,7 +64,7 @@ Note: The closing paragraph of the [Anonymous Functions section](https://www functions) of the Scala 2.12 is subsumed by implicit function types and should be removed. -Anonymous implicit functions `(x1: T1, ..., xn: Tn) |=> e` are +Anonymous implicit functions `given (x1: T1, ..., xn: Tn) => e` are automatically inserted around any expression `e` whose expected type is `scala.ImplicitFunctionN[T1, ..., Tn, R]`, unless `e` is itself a function literal. This is analogous to the automatic diff --git a/docs/docs/reference/instances/implicit-function-types.md b/docs/docs/reference/instances/implicit-function-types.md index 4474711990bd..ab2373cbae1e 100644 --- a/docs/docs/reference/instances/implicit-function-types.md +++ b/docs/docs/reference/instances/implicit-function-types.md @@ -4,106 +4,106 @@ title: "Implicit Function Types and Closures" --- An implicit function type describes functions with implicit (context) parameters. Example: - - type Contextual[T] = Context |=> T - +```scala +type Contextual[T] = given Context => T +``` A value of implicit function type is applied to context arguments, in the same way a method with context parameters is applied. For instance: +```scala + implicit val ctx: Context = ... - implicit val ctx: Context = ... - - def f(x: Int): Contextual[Int] = ... - - f(2) with ctx // explicit argument - f(2) // argument left implicit + def f(x: Int): Contextual[Int] = ... + f(2) given ctx // explicit argument + f(2) // argument left implicit +``` Conversely, if the expected type of an expression `E` is an implicit -function type `(T_1, ..., T_n) |=> U` and `E` is not already an +function type `given (T_1, ..., T_n) => U` and `E` is not already an implicit function value, `E` is converted to an implicit function value by rewriting to - - (x_1: T1, ..., x_n: Tn) |=> E - +```scala + given (x_1: T1, ..., x_n: Tn) => E +``` where the names `x_1`, ..., `x_n` are arbitrary. Implicit closures are written -with a `|=>` connective instead of `=>` for normal closures. They differ from normal closures in two ways: +with a `given` prefix. They differ from normal closures in two ways: 1. Their parameters are implicit context parameters 2. Their types are implicit function types. For example, continuing with the previous definitions, +```scala + def g(arg: Contextual[Int]) = ... - def g(arg: Contextual[Int]) = ... - - g(22) // is expanded to g(ctx |=> 22) + g(22) // is expanded to g(given ctx => 22) - g(f(2)) // is expanded to g(ctx |=> f(2) with ctx) - - g(ctx |=> f(22) with ctx) // is left as it is + g(f(2)) // is expanded to g(given ctx => f(2) given ctx) + g(given ctx => f(22) given ctx) // is left as it is +``` Implicit function types have considerable expressive power. For instance, here is how they can support the "builder pattern", where the aim is to construct tables like this: - - table { - row { - cell("top left") - cell("top right") - } - row { - cell("bottom left") - cell("bottom right") - } +```scala + table { + row { + cell("top left") + cell("top right") } - + row { + cell("bottom left") + cell("bottom right") + } + } +``` The idea is to define classes for `Table` and `Row` that allow addition of elements via `add`: - - class Table { - val rows = new ArrayBuffer[Row] - def add(r: Row): Unit = rows += r - override def toString = rows.mkString("Table(", ", ", ")") - } - - class Row { - val cells = new ArrayBuffer[Cell] - def add(c: Cell): Unit = cells += c - override def toString = cells.mkString("Row(", ", ", ")") - } - - case class Cell(elem: String) - +```scala + class Table { + val rows = new ArrayBuffer[Row] + def add(r: Row): Unit = rows += r + override def toString = rows.mkString("Table(", ", ", ")") + } + + class Row { + val cells = new ArrayBuffer[Cell] + def add(c: Cell): Unit = cells += c + override def toString = cells.mkString("Row(", ", ", ")") + } + + case class Cell(elem: String) +``` Then, the `table`, `row` and `cell` constructor methods can be defined in terms of implicit function types to avoid the plumbing boilerplate that would otherwise be necessary. - - def table(init: Table |=> Unit) = { - instance t of Table - init - t - } - - def row(init: Row |=> Unit) with (t: Table) = { - instance r of Row - init - t.add(r) - } - - def cell(str: String) with (r: Row) = - r.add(new Cell(str)) - +```scala + def table(init: given Table => Unit) = { + instance t of Table + init + t + } + + def row(init: given Row => Unit) given (t: Table) = { + instance r of Row + init + t.add(r) + } + + def cell(str: String) given (r: Row) = + r.add(new Cell(str)) +``` With that setup, the table construction code above compiles and expands to: - - table { $t: Table |=> - row { $r: Row |=> - cell("top left") with $r - cell("top right") with $r - } with $t - row { $r: Row |=> - cell("bottom left") with $r - cell("bottom right") with $r - } with $t - } - +```scala + table { given $t: Table => + row { given $r: Row => + cell("top left") given $r + cell("top right") given $r + } given $t + row { given $r: Row => + cell("bottom left") given $r + cell("bottom right") given $r + } given $t + } +``` ### Reference For more info, see the [blog article](https://www.scala-lang.org/blog/2016/12/07/implicit-function-types.html), diff --git a/docs/docs/reference/instances/instance-defs.md b/docs/docs/reference/instances/instance-defs.md index 17436a508ca6..8b1c70636601 100644 --- a/docs/docs/reference/instances/instance-defs.md +++ b/docs/docs/reference/instances/instance-defs.md @@ -29,7 +29,7 @@ instance ListOrd[T: Ord] of Ord[List[T]] { } ``` Instance definitions can be seen as shorthands for what is currently expressed with implicit object and method definitions. -For instance, the definition of instance `IntOrd` above defines an implicit value of type `Ord[Int]`. It is hence equivalent +For example, the definition of instance `IntOrd` above defines an implicit value of type `Ord[Int]`. It is hence equivalent to the following implicit object definition: ```scala implicit object IntOrd extends Ord[Int] { @@ -83,7 +83,15 @@ If the name of an instance is missing, the compiler will synthesize a name from the type in the of clause, or, if that is missing, from the first defined extension method. -## Conditional Instances +**Aside: ** Why anonymous instances? + + - It avoids clutter, relieving the programmer from having to invent names that are never referred to. + Usually the invented names are either meaning less (e.g. `ev1`), or they just rephrase the implemented type. + - It gives a systematic foundation for synthesized instance definitions, such as those coming from a `derives` clause. + - It achieves a uniform principle that the name of an implicit is always optional, no matter + whether the implicit is an instance definition or an implicit parameter. + +## Conditional Implicits An instance definition can depend on another instance being defined. Example: ```scala @@ -91,20 +99,23 @@ trait Conversion[-From, +To] { def apply(x: From): To } -instance [S, T] with (c: Conversion[S, T]) of Conversion[List[S], List[T]] { +instance [S, T] given (c: Conversion[S, T]) of Conversion[List[S], List[T]] { def convert(x: List[From]): List[To] = x.map(c.apply) } ``` This defines an implicit conversion from `List[S]` to `List[T]` provided there is an implicit conversion from `S` to `T`. -The `with` clause instance defines required instances. The instance of `Conversion[List[From], List[To]]` above is defined only if an instance of `Conversion[From, To]` exists. +The `given` clause defines required instances. The `Conversion[List[From], List[To]]` instance above +is defined only if a `Conversion[From, To]` instance exists. -Context bounds in instance definitions also translate to implicit parameters, and therefore they can be represented alternatively as with clauses. For instance, here is an equivalent definition of the `ListOrd` instance: +Context bounds in instance definitions also translate to implicit parameters, +and therefore they can be represented alternatively as with clauses. For example, +here is an equivalent definition of the `ListOrd` instance: ```scala -instance ListOrd[T] with (ord: Ord[T]) of List[Ord[T]] { ... } +instance ListOrd[T] given (ord: Ord[T]) of List[Ord[T]] { ... } ``` -The name of a parameter in a `with` clause can also be left out, as shown in the following variant of `ListOrd`: +The name of a parameter in a `given` clause can also be left out, as shown in the following variant of `ListOrd`: ```scala -instance ListOrd[T] with Ord[T] of List[Ord[T]] { ... } +instance ListOrd[T] given Ord[T] of List[Ord[T]] { ... } ``` As usual one can then infer to implicit parameter only indirectly, by passing it as implicit argument to another function. @@ -187,9 +198,10 @@ TmplDef ::= ... | ‘instance’ InstanceDef InstanceDef ::= [id] InstanceParams InstanceBody InstanceParams ::= [DefTypeParamClause] {InstParamClause} -InstParamClause ::= ‘with’ (‘(’ [DefParams] ‘)’ | ContextTypes) +InstParamClause ::= ‘given’ (‘(’ [DefParams] ‘)’ | ContextTypes) InstanceBody ::= [‘of’ ConstrApp {‘,’ ConstrApp }] [TemplateBody] | ‘of’ Type ‘=’ Expr ContextTypes ::= RefinedType {‘,’ RefinedType} ``` -The identifier `id` can be omitted only if either the `of` part or the template body is present. If the `of` part is missing, the template body must define at least one extension method. +The identifier `id` can be omitted only if either the `of` part or the template body is present. +If the `of` part is missing, the template body must define at least one extension method. diff --git a/docs/docs/reference/instances/replacing-implicits.md b/docs/docs/reference/instances/replacing-implicits.md index 93bf50c1b75f..8f80b77a17a8 100644 --- a/docs/docs/reference/instances/replacing-implicits.md +++ b/docs/docs/reference/instances/replacing-implicits.md @@ -3,68 +3,54 @@ layout: doc-page title: "Replacing Implicits" --- -The previous pages describe a new, high-level syntax for implicit definitions, parameters, function literals, and function types. With the exception of context parameters - -These idioms can by-and-large be mapped to existing implicits. The only exception concerns context parameters which give genuinely more freedom in the way parameters can be organized. The new idioms are preferable to existing implicits since they are both more concise and better behaved. The better expressiveness comes at a price, however, since it leaves us with two related constructs: new style instance definitions and context parameters and traditional implicits. This page discusses what would be needed to get rid of `implicit` entirely. - -The contents of this page are more tentative than the ones of the previous pages. The concepts described in the previous pages are useful independently whether the changes on this page are adopted. +The previous pages describe a new, high-level syntax for implicit definitions, parameters, function literals, and function types. +These idioms can by-and-large be mapped to existing implicits. The only exception concerns context parameters which give genuinely more freedom in the way parameters can be organized. The new idioms are preferable to existing implicits since they are both more concise and better behaved. The better expressiveness comes at a price, however, since it leaves us with both the new and the old way to express implicits. This page discusses what would be needed to get rid of all existing uses of `implicit` as a modifier. The current Dotty implementation implements the new concepts described on this page (alias instances and the summon method), but it does not remove any of the old-style implicit constructs. It cannot do this since support for old-style implicits is an essential part of the common language subset of Scala 2 and Scala 3.0. Any deprecation and subsequent removal of these constructs would have to come later, in a version following 3.0. The `implicit` modifier can be removed from the language at the end of this development, if it happens. -## Alias Instances +## Add: Alias Instances -An alias instance creates an instance that is equal to some expression. -``` -instance ctx of ExecutionContext = currentThreadPool().context -``` -Here, we create an instance `ctx` of type `ExecutionContext` that resolves to the -right hand side `currentThreadPool().context`. Each time an instance of `ExecutionContext` -is demanded, the result of evaluating the right-hand side expression is returned. The instance definition is equivalent to the following implicit definition: +To replace implicit vals and defs (both abstract and concrete), we need one way to +"lift" an existing value to become an implicit instance for a type. This is achieved +by an alias instance, which creates an instance that is equal to some expression. +```scala +implicit ctx for ExecutionContext = currentThreadPool().context ``` +Here, we create an implicit `ctx` of type `ExecutionContext` that resolves to the +right hand side `currentThreadPool().context`. Each time an implicit of `ExecutionContext` +is demanded, the result of evaluating the right-hand side expression is returned. The definition is equivalent to the following implicit definition in Scala 2: +```scala final implicit def ctx: ExecutionContext = currentThreadPool().context ``` -Alias instances may be anonymous, e.g. -``` -instance of Position = enclosingTree.position +Implicit aliases may be anonymous, e.g. +```scala +implicit for Position = enclosingTree.position ``` -An alias instance can have type and context parameters just like any other instance definition, but it can only implement a single type. +An implicit alias can have type and context parameters just like any other implicit definition, but it can only implement a single type. -## Replaced: Implicit Conversions +## Drop: Implicit Conversions Implicit conversions using the `implicit def` syntax are no longer needed, since they -can be expressed as instances of the `scala.Conversion` class: This class is defined in package `scala` as follows: -```scala -abstract class Conversion[-T, +U] extends (T => U) -``` -For example, here is an implicit conversion from `String` to `Token`: -```scala -instance of Conversion[String, Token] { - def apply(str: String): Token = new KeyWord(str) -} -``` -The fact that this syntax is more verbose than simple implicit defs could be a welcome side effect since it might dampen any over-enthusiasm for defining implicit conversions. +can be expressed as instances of the `scala.Conversion` class. -## Dropped: Implicit Classes +## Drop: Implicit Classes Most use cases of implicit classes are already covered by extension methods. For the others, one can always fall back to a pair of a regular class and a `Conversion` instance. -## Summoning an Instance +## Drop: Implicit As A Modifier -Besides `implicit`, there is also `implicitly`, a method defined in `Predef` that computes an implicit value for a given type. We propose to rename this operation to `summon`. So `summon[T]` summons an instance of `T`, in the same way as `implicitly[T]` did. The definition of `summon` is straightforward: -```scala -def summon[T] with (x: T) = x -``` + - Old-style implicit parameters are replaced by `given` parameters. + - Implicit function types `implicit T => U` are written `given T => U` + - Implicit closures `implicit x => e` are written `given x => e` + - All remaining implicit `val` and `def` definition are replaced by normal + `val` or `def` definitions and implicit aliases.= ## Syntax The syntax changes for this page are summarized as follows: ``` InstanceBody ::= ... - | ‘of’ Type ‘=’ Expr + | ‘for’ Type ‘=’ Expr ``` In addition, the `implicit` modifier is removed together with all [productions]((http://dotty.epfl.ch/docs/internals/syntax.html) that reference it. - -## Further Reading - -Here is the [original proposal](./discussion/motivation.html) that makes the case for the changes described in these pages. diff --git a/docs/sidebar.yml b/docs/sidebar.yml index 6672df319fc3..895beb889a1c 100644 --- a/docs/sidebar.yml +++ b/docs/sidebar.yml @@ -77,10 +77,8 @@ sidebar: url: docs/reference/instances/implicit-function-types.html - title: Implicit Conversions url: docs/reference/instances/implicit-conversions.html - - title: Replacing Implicits + - title: ReplacedImplicits url: docs/reference/instances/replacing-implicits.html - - title: Discussion - url: docs/reference/instances/discussion.html - title: Other Changed Features subsection: - title: Volatile Lazy Vals diff --git a/language-server/test/dotty/tools/languageserver/DiagnosticsTest.scala b/language-server/test/dotty/tools/languageserver/DiagnosticsTest.scala index 4f9b8f47a232..85a3895189e9 100644 --- a/language-server/test/dotty/tools/languageserver/DiagnosticsTest.scala +++ b/language-server/test/dotty/tools/languageserver/DiagnosticsTest.scala @@ -18,10 +18,10 @@ class DiagnosticsTest { @Test def diagnosticMissingLambdaBody: Unit = code"""object Test { - | Nil.map(x => x).filter(x$m1 =>$m2) - |$m3}""".withSource + | Nil.map(x => x).filter(x$m1 =>$m2)$m3 + |}""".withSource .diagnostics(m1, - (m2 to m3, "expression expected", Error, Some(IllegalStartSimpleExprID)), + (m2 to m2, "expression expected", Error, Some(IllegalStartSimpleExprID)), (m1 to m1, """Found: Null |Required: Boolean""".stripMargin, Error, Some(TypeMismatchID)) ) diff --git a/language-server/test/dotty/tools/languageserver/util/CodeTester.scala b/language-server/test/dotty/tools/languageserver/util/CodeTester.scala index 20bf80a3d543..44f553832e89 100644 --- a/language-server/test/dotty/tools/languageserver/util/CodeTester.scala +++ b/language-server/test/dotty/tools/languageserver/util/CodeTester.scala @@ -237,7 +237,7 @@ class CodeTester(projects: List[Project]) { private def doAction(action: Action): this.type = { try { - action.execute() with (testServer, testServer.client, positions) + action.execute() given (testServer, testServer.client, positions) } catch { case ex: AssertionError => val sourcesStr = @@ -252,7 +252,7 @@ class CodeTester(projects: List[Project]) { | |$sourcesStr | - |while executing action: ${action.show with positions} + |while executing action: ${action.show given positions} | """.stripMargin val assertionError = new AssertionError(msg + ex.getMessage) diff --git a/language-server/test/dotty/tools/languageserver/util/PositionContext.scala b/language-server/test/dotty/tools/languageserver/util/PositionContext.scala index 1697e68eb2d1..b892cd978181 100644 --- a/language-server/test/dotty/tools/languageserver/util/PositionContext.scala +++ b/language-server/test/dotty/tools/languageserver/util/PositionContext.scala @@ -24,5 +24,5 @@ class PositionContext(positionMap: Map[CodeMarker, (TestFile, Int, Int)]) { } object PositionContext { - type PosCtx[T] = PositionContext |=> T + type PosCtx[T] = given PositionContext => T } diff --git a/language-server/test/dotty/tools/languageserver/util/actions/Action.scala b/language-server/test/dotty/tools/languageserver/util/actions/Action.scala index 209960902d91..2549a15c40a4 100644 --- a/language-server/test/dotty/tools/languageserver/util/actions/Action.scala +++ b/language-server/test/dotty/tools/languageserver/util/actions/Action.scala @@ -11,7 +11,7 @@ import PositionContext._ * definition, etc.) */ trait Action { - type Exec[T] = (TestServer, TestClient, PositionContext) |=> T + type Exec[T] = given (TestServer, TestClient, PositionContext) => T /** Execute the action. */ def execute(): Exec[Unit] diff --git a/tests/neg/contextual-params.scala b/tests/neg/contextual-params.scala deleted file mode 100644 index 2d44284955d0..000000000000 --- a/tests/neg/contextual-params.scala +++ /dev/null @@ -1,22 +0,0 @@ -object Test { - - case class C(x: Int) - - def f(x: Int) with (c: C) = x + c.x - - def g(x: Int) with (c: C) (y: Int) = x + c.x + y - - implicit object C extends C(11) - - f(1) - f(1) with C - f with 2 // error - f(1)(C) // error - - g(1)(2) // OK - (g(1) with C)(2) // OK - g(1) with 2 // error - g(1) with C with 2 // error - g(1)(C)(2) // error - g(1)(C) with 2 // error -} \ No newline at end of file diff --git a/tests/neg/i2006.scala b/tests/neg/i2006.scala index 7142da89619a..11740777ab9c 100644 --- a/tests/neg/i2006.scala +++ b/tests/neg/i2006.scala @@ -4,7 +4,7 @@ object Test { inline def bar(f: ImplicitFunction1[Int, Int]) = f // error def main(args: Array[String]) = { - foo(thisTransaction |=> 43) - bar(thisTransaction |=> 44) + foo(given thisTransaction => 43) + bar(given thisTransaction => 44) } } diff --git a/tests/neg/i2146.scala b/tests/neg/i2146.scala index 32be8734efde..05086d78dc58 100644 --- a/tests/neg/i2146.scala +++ b/tests/neg/i2146.scala @@ -2,7 +2,7 @@ object Test { case class A() case class B() - def foo[A, B]: A |=> B |=> Int = { b: B |=> - 42 // error: found Int, required: A |=> B |=> Int + def foo[A, B]: given A => given B => Int = { given b: B => + 42 // error: found Int, required: given A => given B => Int } } diff --git a/tests/neg/i2514.scala b/tests/neg/i2514.scala index c05c4b434f42..e1d58a87d20f 100644 --- a/tests/neg/i2514.scala +++ b/tests/neg/i2514.scala @@ -1,7 +1,7 @@ object Foo { def foo(): Int = { val f: implicit Int => Int = (implicit x: Int) => 2 * x // error // error - f with 2 + f given 2 } val f = (implicit x: Int) => x // error // error diff --git a/tests/neg/i2514a.scala b/tests/neg/i2514a.scala index 59c954f31a25..96de78aabc01 100644 --- a/tests/neg/i2514a.scala +++ b/tests/neg/i2514a.scala @@ -1,10 +1,10 @@ object Foo { def foo(): Int = { - val f: Int |=> Int = (x: Int) |=> 2 * x - f with 2 + val f: given Int => Int = given (x: Int) => 2 * x + f given 2 } val f = implicit (x: Int) => x - ((x: Int) |=> x): (Int |=> Int) // error: no implicit argument found + (given (x: Int) => x): (given Int => Int) // error: no implicit argument found } diff --git a/tests/neg/i2642.scala b/tests/neg/i2642.scala index bb52d06c0c3e..8a441dc0276c 100644 --- a/tests/neg/i2642.scala +++ b/tests/neg/i2642.scala @@ -1,10 +1,10 @@ object Foo { - type X = () |=> Int // now ok, used to be: implicit function needs parameters + type X = given () => Int // now ok, used to be: implicit function needs parameters def ff: X = () // error: found: Unit, expected: Int type Y = erased () => Int // error: empty function may not be erased def gg: Y = () // error: found: Unit, expected: Y - type Z = erased () |=> Int // error: empty function may not be erased + type Z = erased given () => Int // error: empty function may not be erased def hh: Z = () // error: found: Unit, expected: Int } diff --git a/tests/neg/i2960.scala b/tests/neg/i2960.scala index a134d3721350..f7c1dbe4f6f2 100644 --- a/tests/neg/i2960.scala +++ b/tests/neg/i2960.scala @@ -22,9 +22,9 @@ class Tag(val name: String, this } - def apply[U](f: Tag |=> U)(implicit t: Tag = null): this.type = { + def apply[U](f: given Tag => U)(implicit t: Tag = null): this.type = { if(t != null) t.children += this - f with this + f given this this } } diff --git a/tests/neg/i4196.scala b/tests/neg/i4196.scala index 1eea1e565d15..0930d3102903 100644 --- a/tests/neg/i4196.scala +++ b/tests/neg/i4196.scala @@ -1,6 +1,6 @@ object Test { @annotation.tailrec - def foo(i: Unit |=> Int): Unit |=> Int = + def foo(i: given Unit => Int): given Unit => Int = if (i == 0) 0 else diff --git a/tests/neg/i4611a.scala b/tests/neg/i4611a.scala index 31a210ad63fa..7527a0cb113b 100644 --- a/tests/neg/i4611a.scala +++ b/tests/neg/i4611a.scala @@ -1,6 +1,6 @@ // Don't qualify as SAM type because result type is an implicit function type trait Foo { - def foo(x: Int): Int |=> Int + def foo(x: Int): given Int => Int } trait Bar[T] { @@ -12,10 +12,10 @@ class Test { def foo(x: Int) = 1 } - val good2 = new Bar[Int |=> Int] { + val good2 = new Bar[given Int => Int] { def bar(x: Int) = 1 } val bad1: Foo = (x: Int) => 1 // error - val bad2: Bar[implicit Int => Int] = (x: Int) => 1 // error + val bad2: Bar[given Int => Int] = (x: Int) => 1 // error } diff --git a/tests/neg/i4611b.scala b/tests/neg/i4611b.scala index dc53e0fd74cb..d25710a466d1 100644 --- a/tests/neg/i4611b.scala +++ b/tests/neg/i4611b.scala @@ -3,7 +3,7 @@ import scala.concurrent.Future class Response class Request object Request { - type To[T] = Request |=> T + type To[T] = given Request => T } // Don't qualify as SAM type because result type is an implicit function type diff --git a/tests/neg/implicit-params.scala b/tests/neg/implicit-params.scala new file mode 100644 index 000000000000..ec38f07fa2aa --- /dev/null +++ b/tests/neg/implicit-params.scala @@ -0,0 +1,24 @@ +object Test { + + case class C(x: Int) + + def f(x: Int) given (c: C) = x + c.x + + def g(x: Int) given (c: C) (y: Int) = x + c.x + y + + def h(x: Int) given () = x // error + + implicit object C extends C(11) + + f(1) + f(1) given C + f given 2 // error + f(1)(C) // error + + g(1)(2) // OK + (g(1) given C)(2) // OK + g(1) given 2 // error + g(1) given C given 2 // error + g(1)(C)(2) // error + g(1)(C) given 2 // error +} \ No newline at end of file diff --git a/tests/neg/implicit-shadowing.scala b/tests/neg/implicit-shadowing.scala index f263b3f81761..0ecba452841f 100644 --- a/tests/neg/implicit-shadowing.scala +++ b/tests/neg/implicit-shadowing.scala @@ -20,8 +20,8 @@ object Test { } } - def h[T]: C1[T] |=> Unit = { - def g[U]: C2[U] |=> Unit = { + def h[T]: given C1[T] => Unit = { + def g[U]: given C2[U] => Unit = { implicitly[C1[T]] // OK: no shadowing for evidence parameters implicitly[C2[U]] } diff --git a/tests/neg/trailingCommas.scala b/tests/neg/trailingCommas.scala index 356f735ce656..ad5a0f3ea942 100644 --- a/tests/neg/trailingCommas.scala +++ b/tests/neg/trailingCommas.scala @@ -18,7 +18,7 @@ trait SimpleExpr { (23, "bar", ) } // error trait TypeArgs { def f: ValidGeneric[Int, String, ] } // error trait TypeParamClause { type C[A, B, ] } // error -trait FunTypeParamClause { def f[A, B, ] } // error +trait FunTypeParamClause { def f[A, B, ] } // error // error trait SimpleType { def f: (Int, String, ) } // error trait FunctionArgTypes { def f: (Int, String, ) => Boolean } // error diff --git a/tests/pos/Orderings.scala b/tests/pos/Orderings.scala index ec5aa60a745b..64dd7fa7eded 100644 --- a/tests/pos/Orderings.scala +++ b/tests/pos/Orderings.scala @@ -15,6 +15,6 @@ object Orderings { else ev.less(xs.head, ys.head) } - def isLess[T]: T => T => Ord[T] |=> Boolean = + def isLess[T]: T => T => given Ord[T] => Boolean = x => y => implicitly[Ord[T]].less(x, y) } diff --git a/tests/pos/case-getters.scala b/tests/pos/case-getters.scala index dc6476e10674..aac0f194bc99 100644 --- a/tests/pos/case-getters.scala +++ b/tests/pos/case-getters.scala @@ -1,8 +1,8 @@ -case class Foo(x: 1, y: Int |=> Int) +case class Foo(x: 1, y: given Int => Int) object Test { - val f = Foo(1, (i: Int) |=> i) + val f = Foo(1, given (i: Int) => i) val fx1: 1 = f.x val fx2: 1 = f._1 - val fy1: Int = f.y with 1 - val fy2: Int = f._2 with 1 + val fy1: Int = f.y given 1 + val fy2: Int = f._2 given 1 } diff --git a/tests/pos/depfuntype.scala b/tests/pos/depfuntype.scala index c31978af8536..eef9f86ac5b3 100644 --- a/tests/pos/depfuntype.scala +++ b/tests/pos/depfuntype.scala @@ -19,15 +19,15 @@ object Test { // Reproduced here because the one from DottyPredef is lacking a parameter dependency of the return type `ev.type` inline final def implicitly[T](implicit ev: T): ev.type = ev - type IDF = (x: C) |=> x.M + type IDF = given (x: C) => x.M implicit val ic: C = ??? val ifun: IDF = implicitly[C].m - val u = ifun with c + val u = ifun given c val u1: Int = u - val v = ifun with d + val v = ifun given d val v1: d.M = v } diff --git a/tests/pos/eff-compose.scala b/tests/pos/eff-compose.scala index 80e43b70d199..9165ae215d77 100644 --- a/tests/pos/eff-compose.scala +++ b/tests/pos/eff-compose.scala @@ -5,7 +5,7 @@ object Test { // Type X => Y abstract class Fun[-X, Y] { type Eff <: Effect - def apply(x: X): Eff |=> Y + def apply(x: X): given Eff => Y } // Type X -> Y @@ -13,7 +13,7 @@ object Test { // def map(f: A => B)(xs: List[A]): List[B] def map[A, B, E <: Effect](f: Fun[A, B] { type Eff = E})(xs: List[A]) - : E |=> List[B] = + : given E => List[B] = xs.map(f.apply) // def mapFn[A, B]: (A => B) -> List[A] -> List[B] @@ -31,19 +31,19 @@ object Test { def apply(f: Fun[A, B] { type Eff = E}) = new Fun[List[A], List[B]] { type Eff = E - def apply(xs: List[A]): Eff |=> List[B] = + def apply(xs: List[A]): given Eff => List[B] = map(f)(xs) } } - implicit def combine[E1 <: Effect, E2 <: Effect] with (x: E1, y: E2): E1 & E2 = ??? + implicit def combine[E1 <: Effect, E2 <: Effect] given (x: E1, y: E2): E1 & E2 = ??? // def compose(f: A => B)(g: B => C)(x: A): C def compose[A, B, C, E1 <: Effect, E2 <: Effect] (f: Fun[A, B] { type Eff = E1}) (g: Fun[B, C] { type Eff = E2}) (x: A): - E1 & E2 |=> C = g(f(x)) + given E1 & E2 => C = g(f(x)) // def composeFn: (A => B) -> (B => C) -> A -> C def composeFn[A, B, C, E1 <: Effect, E2 <: Effect]: diff --git a/tests/pos/assumeIn.scala b/tests/pos/givenIn.scala similarity index 82% rename from tests/pos/assumeIn.scala rename to tests/pos/givenIn.scala index 6c367f826b2c..c7f446077b8b 100644 --- a/tests/pos/assumeIn.scala +++ b/tests/pos/givenIn.scala @@ -2,15 +2,15 @@ object Test { import scala.compiletime.constValue class Context { - inline def assumeIn[T](op: => Context |=> T) = { + inline def givenIn[T](op: => given Context => T) = { instance of Context = this op } } def ctx: Context = new Context - def g with Context = () - ctx.assumeIn(g) + def g given Context = () + ctx.givenIn(g) /* The last three statements shoudl generate the following code: diff --git a/tests/pos/ho-implicits.scala b/tests/pos/ho-implicits.scala index 4dbb2a2e47a3..957926ee380c 100644 --- a/tests/pos/ho-implicits.scala +++ b/tests/pos/ho-implicits.scala @@ -1,9 +1,9 @@ object Test2 { - implicit def __1: Int |=> String = s"implicit: ${implicitly[Int]}" + implicit def __1: given Int => String = s"implicit: ${implicitly[Int]}" implicit def __2: Int = 42 - def f: String |=> Int = implicitly[String].length + def f: given String => Int = implicitly[String].length f: Int } \ No newline at end of file diff --git a/tests/pos/i2146.scala b/tests/pos/i2146.scala index 674094e9914b..98816b2c2269 100644 --- a/tests/pos/i2146.scala +++ b/tests/pos/i2146.scala @@ -2,12 +2,12 @@ object Test { case class A() case class B() - def simple[A]: A |=> A = implicitly[A] + def simple[A]: given A => A = implicitly[A] - def foo[A, B]: A |=> B |=> (A, B) = + def foo[A, B]: given A => given B => (A, B) = (implicitly[A], implicitly[B]) - def bar[A, B]: A |=> B |=> (A, B) = { a: A |=> + def bar[A, B]: given A => given B => (A, B) = { given (a: A) => (implicitly[A], implicitly[B]) } @@ -16,17 +16,17 @@ object Test { def main(args: Array[String]) = { println(foo[A, B]) - println(foo[A, B] with a) - println(foo with a with b) - val s: A |=> A = simple[A] + println(foo[A, B] given a) + println(foo given a given b) + val s: given A => A = simple[A] println(s) - val x0: A |=> B |=> (A, B) = foo[A, B] + val x0: given A => given B => (A, B) = foo[A, B] println(x0) - val x1: B |=> (A, B) = foo[A, B] + val x1: given B => (A, B) = foo[A, B] println(x1) println(bar[A, B]) - println(bar[A, B] with a) - println(bar with a with b) + println(bar[A, B] given a) + println(bar given a given b) } } diff --git a/tests/pos/i2278.scala b/tests/pos/i2278.scala index 13b7d9dddc7c..2f3a4d3e3a25 100644 --- a/tests/pos/i2278.scala +++ b/tests/pos/i2278.scala @@ -4,7 +4,7 @@ object Fluent { } trait CC[T] - type Context[Alg[x[_]] <: Foo[x], E] = Alg[CC] |=> CC[E] + type Context[Alg[x[_]] <: Foo[x], E] = given Alg[CC] => CC[E] def meth1[T]() : Context[Foo, T] = { implicitly[Foo[CC]].meth1() diff --git a/tests/pos/i2671.scala b/tests/pos/i2671.scala index 90ec7c91bb9e..e187b98a1ced 100644 --- a/tests/pos/i2671.scala +++ b/tests/pos/i2671.scala @@ -1,10 +1,10 @@ object Foo { - def map[E](f: E |=> Int): (E |=> Int) = ??? + def map[E](f: given E => Int): (given E => Int) = ??? implicit def i: Int = ??? - def f: Int |=> Int = ??? + def f: given Int => Int = ??? val a: Int = map(f) diff --git a/tests/pos/i2749.scala b/tests/pos/i2749.scala index 0897f8a386e0..959ce858a9b1 100644 --- a/tests/pos/i2749.scala +++ b/tests/pos/i2749.scala @@ -1,23 +1,23 @@ object Test { - val f: (Int |=> Char) |=> Boolean = ??? + val f: given (given Int => Char) => Boolean = ??? implicit val n: Int = 3 - implicit val g: Int |=> Char = ??? + implicit val g: given Int => Char = ??? f : Boolean } object Test2 { - val f: (Int |=> Char) |=> Boolean = ??? + val f: given (given Int => Char) => Boolean = ??? implicit val s: String = null - implicit val g: Int |=> String |=> Char = ??? + implicit val g: given Int => given String => Char = ??? f : Boolean } object Test3 { - val f: (Int |=> String |=> Char) |=> Boolean = ??? + val f: given (given Int => given String => Char) => Boolean = ??? implicit val n: Int = 3 - implicit val g: Int |=> Char = ??? + implicit val g: given Int => Char = ??? f : Boolean } diff --git a/tests/pos/i3692.scala b/tests/pos/i3692.scala index 2911f548f56f..cf799d4de02b 100644 --- a/tests/pos/i3692.scala +++ b/tests/pos/i3692.scala @@ -6,9 +6,9 @@ object Main { //val b: Int => Int = a def main(args: Array[String]): Unit = { - val choose: (c: C) |=> Set[Int] = Set.empty - val b0: (C) => Set[Int] = choose with _ - val b1: (c: C) => Set[Int] = choose with _ + val choose: given (c: C) => Set[Int] = Set.empty + val b0: (C) => Set[Int] = choose given _ + val b1: (c: C) => Set[Int] = choose given _ def applyF(f: (c: C) => Set[Int]) = f(new C{type T=Int}) //applyF(choose) } diff --git a/tests/pos/i4125.scala b/tests/pos/i4125.scala index 61310f14b246..49ca8fd8daf3 100644 --- a/tests/pos/i4125.scala +++ b/tests/pos/i4125.scala @@ -1,4 +1,4 @@ object Test { def foo: (erased (x: Int, y: Int) => Int) = erased (x, y) => 1 - def bar: (erased (x: Int, y: Int) |=> Int) = erased (x, y) |=> 1 + def bar: (erased given (x: Int, y: Int) => Int) = erased given (x, y) => 1 } diff --git a/tests/pos/i4196.scala b/tests/pos/i4196.scala index e880f01cd7a4..669ac0bc935c 100644 --- a/tests/pos/i4196.scala +++ b/tests/pos/i4196.scala @@ -1,6 +1,6 @@ object Test { @annotation.tailrec - def foo(i: Unit |=> Int): Unit |=> Int = + def foo(i: given Unit => Int): given Unit => Int = if (i == 0) 0 else diff --git a/tests/pos/i4203.scala b/tests/pos/i4203.scala index 3c75e7dee3df..4577d1709dbe 100644 --- a/tests/pos/i4203.scala +++ b/tests/pos/i4203.scala @@ -1,7 +1,7 @@ case class Box[Z](unbox: Z) object Test { - def foo(b: Box[Int |=> Int]): Int = b match { + def foo(b: Box[given Int => Int]): Int = b match { case Box(f) => implicit val i: Int = 1 f diff --git a/tests/pos/i4725.scala b/tests/pos/i4725.scala index 46a9a7ecaee8..1ccd34d3a328 100644 --- a/tests/pos/i4725.scala +++ b/tests/pos/i4725.scala @@ -1,8 +1,8 @@ object Test1 { trait T[A] - def foo[S[_], A] with (ev: T[A] |=> T[S[A]]): Unit = () - implicit def bar[A] with (ev: T[A]): T[List[A]] = ??? + def foo[S[_], A] given (ev: given T[A] => T[S[A]]): Unit = () + implicit def bar[A] given (ev: T[A]): T[List[A]] = ??? foo[List, Int] } @@ -11,8 +11,8 @@ object Test2 { trait T trait S - def foo with (ev: T |=> S): Unit = () - implicit def bar with (ev: T): S = ??? + def foo given (ev: given T => S): Unit = () + implicit def bar given (ev: T): S = ??? foo } diff --git a/tests/pos/i4753.scala b/tests/pos/i4753.scala index bc83d980a6b6..dc5999506a8a 100644 --- a/tests/pos/i4753.scala +++ b/tests/pos/i4753.scala @@ -1,13 +1,13 @@ class A trait Foo { - def foo: A |=> Int + def foo: given A => Int } class Test { - println(new FooI{}) + new FooI{} } class FooI extends Foo { - def foo: A |=> Int = 3 + def foo: given A => Int = 3 } \ No newline at end of file diff --git a/tests/pos/i4753b.scala b/tests/pos/i4753b.scala index 606986f2ddbc..a6a2ce0103d9 100644 --- a/tests/pos/i4753b.scala +++ b/tests/pos/i4753b.scala @@ -1,7 +1,7 @@ class Foo1 { - def foo: String |=> Int = 1 + def foo: given String => Int = 1 } class Foo2 extends Foo1 { - override def foo: String |=> Int = 2 + override def foo: given String => Int = 2 } diff --git a/tests/pos/implicit-dep.scala b/tests/pos/implicit-dep.scala index f6fe80cc43c1..620b95e96a7d 100644 --- a/tests/pos/implicit-dep.scala +++ b/tests/pos/implicit-dep.scala @@ -5,5 +5,5 @@ trait HasT { object Test { - def foo: Int |=> (g: HasT) |=> g.T = ??? + def foo: given Int => given (g: HasT) => g.T = ??? } diff --git a/tests/pos/implicitFuns.scala b/tests/pos/implicitFuns.scala index 555acf7310d0..7eb2ca40f58b 100644 --- a/tests/pos/implicitFuns.scala +++ b/tests/pos/implicitFuns.scala @@ -10,7 +10,7 @@ class ConfManagement(papers: List[Paper], realScore: Map[Paper, Int]) extends Ap private def hasConflict(ps1: Set[Person], ps2: Iterable[Person]) = ps2.exists(ps1 contains _) - type Viewable[T] = Viewers |=> T + type Viewable[T] = given Viewers => T def vs: Viewable[Viewers] = implicitly @@ -52,7 +52,7 @@ object Orderings extends App { x => y => x < y } - implicit def __2[T]: Ord[T] |=> Ord[List[T]] = new Ord[List[T]] { + implicit def __2[T]: given Ord[T] => Ord[List[T]] = new Ord[List[T]] { def less: List[T] => List[T] => Boolean = xs => ys => if ys.isEmpty then false @@ -61,7 +61,7 @@ object Orderings extends App { else isLess(xs.head)(ys.head) } - def isLess[T]: T => T => Ord[T] |=> Boolean = + def isLess[T]: T => T => given Ord[T] => Boolean = x => y => implicitly[Ord[T]].less(x)(y) println(isLess(Nil)(List(1, 2, 3))) diff --git a/tests/pos/inline-apply.scala b/tests/pos/inline-apply.scala index 60c024af2227..358b89abcd92 100644 --- a/tests/pos/inline-apply.scala +++ b/tests/pos/inline-apply.scala @@ -3,9 +3,9 @@ class Context object Test { def transform()(implicit ctx: Context) = { - inline def withLocalOwner[T](op: Context |=> T) = op with ctx + inline def withLocalOwner[T](op: given Context => T) = op given ctx - withLocalOwner { ctx |=> () } + withLocalOwner { given ctx => } } } diff --git a/tests/pos/reference/instances.scala b/tests/pos/reference/instances.scala index 3618b5a257a9..a4e05e1b3564 100644 --- a/tests/pos/reference/instances.scala +++ b/tests/pos/reference/instances.scala @@ -37,7 +37,7 @@ object Instances extends Common { if (x < y) -1 else if (x > y) +1 else 0 } - instance ListOrd[T] with Ord[T] of Ord[List[T]] { + instance ListOrd[T] given Ord[T] of Ord[List[T]] { def (xs: List[T]) compareTo (ys: List[T]): Int = (xs, ys) match { case (Nil, Nil) => 0 case (Nil, _) => -1 @@ -73,31 +73,31 @@ object Instances extends Common { ctx => x } - def maximum[T](xs: List[T]) with Ord[T]: T = + def maximum[T](xs: List[T]) given Ord[T]: T = xs.reduceLeft((x, y) => if (x < y) y else x) - def descending[T] with (asc: Ord[T]): Ord[T] = new Ord[T] { + def descending[T] given (asc: Ord[T]): Ord[T] = new Ord[T] { def (x: T) compareTo (y: T) = asc.compareTo(y)(x) } - def minimum[T](xs: List[T]) with Ord[T] = - maximum(xs) with descending + def minimum[T](xs: List[T]) given Ord[T] = + maximum(xs) given descending def test(): Unit = { val xs = List(1, 2, 3) println(maximum(xs)) - println(maximum(xs) with descending) - println(maximum(xs) with (descending with IntOrd)) + println(maximum(xs) given descending) + println(maximum(xs) given (descending given IntOrd)) println(minimum(xs)) } case class Context(value: String) - val c0: Context |=> String = ctx |=> ctx.value - val c1: (Context |=> String) = (ctx: Context) |=> ctx.value + val c0: given Context => String = given ctx => ctx.value + val c1: (given Context => String) = given (ctx: Context) => ctx.value class A class B - val ab: (x: A, y: B) |=> Int = (a: A, b: B) |=> 22 + val ab: given (x: A, y: B) => Int = given (a: A, b: B) => 22 trait TastyAPI { type Symbol @@ -116,7 +116,7 @@ object Instances extends Common { class D[T] - class C with (ctx: Context) { + class C given (ctx: Context) { def f() = { locally { instance of Context = this.ctx @@ -132,7 +132,7 @@ object Instances extends Common { println(summon[D[Int]]) } locally { - instance with Context of D[Int] + instance given Context of D[Int] println(summon[D[Int]]) } } @@ -155,11 +155,11 @@ object PostConditions { def (x: WrappedResult[T]) unwrap[T]: T = x } - def result[T] with (wrapped: WrappedResult[T]): T = wrapped.unwrap + def result[T] given (wrapped: WrappedResult[T]): T = wrapped.unwrap instance { - def (x: T) ensuring[T] (condition: WrappedResult[T] |=> Boolean): T = { - assert(condition with WrappedResult(x)) + def (x: T) ensuring[T] (condition: given WrappedResult[T] => Boolean): T = { + assert(condition given WrappedResult(x)) x } } @@ -193,7 +193,7 @@ object AnonymousInstances extends Common { def (xs: List[T]) second[T] = xs.tail.head } - instance [From, To] with (c: Convertible[From, To]) of Convertible[List[From], List[To]] { + instance [From, To] given (c: Convertible[From, To]) of Convertible[List[From], List[To]] { def (x: List[From]) convert: List[To] = x.map(c.convert) } diff --git a/tests/run-with-compiler-custom-args/tasty-interpreter/interpreter/TastyInterpreter.scala b/tests/run-with-compiler-custom-args/tasty-interpreter/interpreter/TastyInterpreter.scala index ba0c87ce5191..bb389a21cd0b 100644 --- a/tests/run-with-compiler-custom-args/tasty-interpreter/interpreter/TastyInterpreter.scala +++ b/tests/run-with-compiler-custom-args/tasty-interpreter/interpreter/TastyInterpreter.scala @@ -14,7 +14,7 @@ class TastyInterpreter extends TastyConsumer { case DefDef("main", _, _, _, Some(rhs)) => val interpreter = new jvm.Interpreter(reflect) - interpreter.eval(rhs) with Map.empty + interpreter.eval(rhs) given Map.empty // TODO: recurse only for PackageDef, ClassDef case tree => super.traverseTree(tree) diff --git a/tests/run-with-compiler-custom-args/tasty-interpreter/interpreter/TreeInterpreter.scala b/tests/run-with-compiler-custom-args/tasty-interpreter/interpreter/TreeInterpreter.scala index 3ce4283ff4f6..bd96c338677a 100644 --- a/tests/run-with-compiler-custom-args/tasty-interpreter/interpreter/TreeInterpreter.scala +++ b/tests/run-with-compiler-custom-args/tasty-interpreter/interpreter/TreeInterpreter.scala @@ -13,15 +13,15 @@ abstract class TreeInterpreter[R <: Reflection & Singleton](val reflect: R) { /** Representation of objects and values in the interpreter */ type AbstractAny - type Result = Env |=> AbstractAny + type Result = given Env => AbstractAny def localValue(sym: Symbol)(implicit env: Env): LocalValue = env(sym) - def withLocalValue[T](sym: Symbol, value: LocalValue)(in: Env |=> T)(implicit env: Env): T = - in with env.updated(sym, value) + def withLocalValue[T](sym: Symbol, value: LocalValue)(in: given Env => T)(implicit env: Env): T = + in given env.updated(sym, value) - def withLocalValues[T](syms: List[Symbol], values: List[LocalValue])(in: Env |=> T)(implicit env: Env): T = - in with (env ++ syms.zip(values)) + def withLocalValues[T](syms: List[Symbol], values: List[LocalValue])(in: given Env => T)(implicit env: Env): T = + in given (env ++ syms.zip(values)) def interpretCall(inst: AbstractAny, sym: DefSymbol, args: List[AbstractAny]): Result = { // TODO @@ -65,7 +65,7 @@ abstract class TreeInterpreter[R <: Reflection & Singleton](val reflect: R) { def interpretBlock(stats: List[Statement], expr: Term): Result = { val newEnv = stats.foldLeft(implicitly[Env])((accEnv, stat) => stat match { case ValDef(name, tpt, Some(rhs)) => - def evalRhs = eval(rhs) with accEnv + def evalRhs = eval(rhs) given accEnv val evalRef: LocalValue = if (stat.symbol.flags.is(Flags.Lazy)) LocalValue.lazyValFrom(evalRhs) else if (stat.symbol.flags.is(Flags.Mutable)) LocalValue.varFrom(evalRhs) @@ -76,10 +76,10 @@ abstract class TreeInterpreter[R <: Reflection & Singleton](val reflect: R) { // TODO: record the environment for closure purposes accEnv case stat => - eval(stat) with accEnv + eval(stat) given accEnv accEnv }) - eval(expr) with newEnv + eval(expr) given newEnv } def interpretUnit(): AbstractAny diff --git a/tests/run/builder.scala b/tests/run/builder.scala index 436b14ed421f..b9db863ea3bb 100644 --- a/tests/run/builder.scala +++ b/tests/run/builder.scala @@ -16,13 +16,13 @@ case class Cell(elem: String) object Test { - def table(init: Table |=> Unit) = { + def table(init: given Table => Unit) = { implicit val t = new Table init t } - def row(init: Row |=> Unit)(implicit t: Table) = { + def row(init: given Row => Unit)(implicit t: Table) = { implicit val r = new Row init t.add(r) diff --git a/tests/run/config.scala b/tests/run/config.scala index 7d30001be36c..c60731587ca3 100644 --- a/tests/run/config.scala +++ b/tests/run/config.scala @@ -29,13 +29,13 @@ object Imperative { ).onError(None) def main(args: Array[String]) = { - println(readPerson with Config("John Doe", 20)) - println(readPerson with Config("Incognito", 99)) + println(readPerson given Config("John Doe", 20)) + println(readPerson given Config("Incognito", 99)) } } object Configs { - type Configured[T] = Config |=> T + type Configured[T] = given Config => T def config: Configured[Config] = implicitly[Config] } @@ -47,7 +47,7 @@ object Exceptions { private[Exceptions] def throwE() = throw new E } - type Possibly[T] = CanThrow |=> T + type Possibly[T] = given CanThrow => T def require(p: Boolean)(implicit ct: CanThrow): Unit = if (!p) ct.throwE() @@ -56,7 +56,7 @@ object Exceptions { class OnError[T](op: Possibly[T]) { def onError(fallback: => T): T = - try op with (new CanThrow) + try op given (new CanThrow) catch { case ex: E => fallback } } } @@ -85,8 +85,8 @@ object Test extends App { val config1 = Config("John Doe", 20) val config2 = Config("Incognito", 99) - println(readPerson with config1) - println(readPerson with config2) + println(readPerson given config1) + println(readPerson given config2) } object OptionTest extends App { diff --git a/tests/run/eff-dependent.scala b/tests/run/eff-dependent.scala index 5ecfe0a08c8a..59be3c89e4b6 100644 --- a/tests/run/eff-dependent.scala +++ b/tests/run/eff-dependent.scala @@ -5,7 +5,7 @@ object Test extends App { // Type X => Y abstract class Fun[-X, +Y] { type Eff <: Effect - def apply(x: X): Eff |=> Y + def apply(x: X): given Eff => Y } class CanThrow extends Effect @@ -18,18 +18,18 @@ object Test extends App { implicit val ci: CanIO = new CanIO // def map(f: A => B)(xs: List[A]): List[B] - def map[A, B](f: Fun[A, B])(xs: List[A]): f.Eff |=> List[B] = + def map[A, B](f: Fun[A, B])(xs: List[A]): given f.Eff => List[B] = xs.map(f.apply) // def mapFn[A, B]: (A => B) -> List[A] -> List[B] - def mapFn[A, B]: (f: Fun[A, B]) => List[A] => f.Eff |=> List[B] = + def mapFn[A, B]: (f: Fun[A, B]) => List[A] => given f.Eff => List[B] = f => xs => map(f)(xs) // def compose(f: A => B)(g: B => C)(x: A): C - def compose[A, B, C](f: Fun[A, B])(g: Fun[B, C])(x: A): f.Eff |=> g.Eff |=> C = g(f(x)) + def compose[A, B, C](f: Fun[A, B])(g: Fun[B, C])(x: A): given f.Eff => given g.Eff => C = g(f(x)) // def composeFn: (A => B) -> (B => C) -> A -> C - def composeFn[A, B, C]: (f: Fun[A, B]) => (g: Fun[B, C]) => A => f.Eff |=> g.Eff |=> C = + def composeFn[A, B, C]: (f: Fun[A, B]) => (g: Fun[B, C]) => A => given f.Eff => given g.Eff => C = f => g => x => compose(f)(g)(x) assert(mapFn(i2s)(List(1, 2, 3)).mkString == "123") diff --git a/tests/run/erased-23.check b/tests/run/erased-23.check index aac6a431ff8a..efbbe4dddf06 100644 --- a/tests/run/erased-23.check +++ b/tests/run/erased-23.check @@ -1 +1,2 @@ lambda1 +lambda2 diff --git a/tests/run/erased-23.scala b/tests/run/erased-23.scala index e61a0ad4a981..bb5738c349e8 100644 --- a/tests/run/erased-23.scala +++ b/tests/run/erased-23.scala @@ -1,13 +1,22 @@ object Test { def main(args: Array[String]): Unit = { - fun { erased (x: Int) |=> + fun { given erased (x: Int) => println("lambda1") "abc" } + + fun2 { erased given (x: Int) => + println("lambda2") + "abc" + } + } + + def fun(f: given erased Int => String): String = { + f given 35 } - def fun(f: erased Int |=> String): String = { - f with 35 + def fun2(f: erased given Int => String): String = { + f given 35 } } diff --git a/tests/run/i2642.scala b/tests/run/i2642.scala index d0f4bcaf0b00..b3b849f45a2f 100644 --- a/tests/run/i2642.scala +++ b/tests/run/i2642.scala @@ -1,7 +1,7 @@ // Tests nullary implicit function types object Test extends App { class I - type X = () |=> Int + type X = given () => Int def ff: X = 2 assert(ff == 2) } diff --git a/tests/run/i2939.scala b/tests/run/i2939.scala index 1e2937617bde..4046a7fd347c 100644 --- a/tests/run/i2939.scala +++ b/tests/run/i2939.scala @@ -7,8 +7,8 @@ class Tag(val name: String, val buffer: Buffer[Tag] = ArrayBuffer()) { s"${" " * n}" } - def apply[U](f: Tag |=> U)(implicit tag: Tag = null): this.type = { - f with this + def apply[U](f: given Tag => U)(implicit tag: Tag = null): this.type = { + f given this if(tag != null) tag.buffer += this this } diff --git a/tests/run/i3448.scala b/tests/run/i3448.scala index 6905c1cbcdbf..f412ba61f3c8 100644 --- a/tests/run/i3448.scala +++ b/tests/run/i3448.scala @@ -1,13 +1,13 @@ object Test extends App { case class C(x: Int) - type IF[T] = C |=> T + type IF[T] = given C => T val x: IF[Int] = implicitly[C].x - val xs0: List[IF[Int]] = List(_ |=> x) + val xs0: List[IF[Int]] = List(given _ => x) val xs: List[IF[Int]] = List(x) val ys: IF[List[Int]] = xs.map(x => x) - val zs = ys with C(22) + val zs = ys given C(22) assert(zs == List(22)) } diff --git a/tests/run/implicit-shortcut-bridge.scala b/tests/run/implicit-shortcut-bridge.scala index 7ad474ea507f..fed9b9772e96 100644 --- a/tests/run/implicit-shortcut-bridge.scala +++ b/tests/run/implicit-shortcut-bridge.scala @@ -1,17 +1,17 @@ abstract class A[T] { def foo: T } -class B extends A[Int |=> Int] { +class B extends A[given Int => Int] { // No bridge needed for foo$direct - def foo: Int |=> Int = 1 + def foo: given Int => Int = 1 } -abstract class X[T] extends A[T |=> T] { - def foo: T |=> T +abstract class X[T] extends A[given T => T] { + def foo: given T => T } class Y extends X[Int] { - def foo: Int |=> Int = 1 + def foo: given Int => Int = 1 } object Test { diff --git a/tests/run/implicitFunctionXXL.scala b/tests/run/implicitFunctionXXL.scala index 7c3093890e00..0ba6c3ffc089 100644 --- a/tests/run/implicitFunctionXXL.scala +++ b/tests/run/implicitFunctionXXL.scala @@ -5,7 +5,7 @@ object Test { implicit val intWorld: Int = 42 implicit val strWorld: String = "Hello " - val i1 = ( (x1: Int, + val i1 = (given (x1: Int, x2: String, x3: Int, x4: Int, @@ -30,7 +30,7 @@ object Test { x23: Int, x24: Int, x25: Int, - x26: Int) |=> x2 + x1) + x26: Int) => x2 + x1) println(i1) } diff --git a/tests/run/implicitFuns.scala b/tests/run/implicitFuns.scala index 30893ed544c9..508d54c31569 100644 --- a/tests/run/implicitFuns.scala +++ b/tests/run/implicitFuns.scala @@ -3,44 +3,44 @@ object Test { implicit val world: String = "world!" - val i1 = ((s: String) |=> s.length > 2) - val i2 = {(s: String) |=> s.length > 2} + val i1 = (given (s: String) => s.length > 2) + val i2 = {given (s: String) => s.length > 2} assert(i1) assert(i2) - val x: String |=> Boolean = { (s: String) |=> s.length > 2 } + val x: given String => Boolean = { given (s: String) => s.length > 2 } - val xx: (String, Int) |=> Int = (x: String, y: Int) |=> x.length + y + val xx: given (String, Int) => Int = given (x: String, y: Int) => x.length + y - val y: String => Boolean = x with _ + val y: String => Boolean = x given _ object nested { implicit val empty: String = "" assert(!x) } - val yy: (String, Int) => Any = xx with (_, _) + val yy: (String, Int) => Any = xx given (_, _) - val z1: String |=> Boolean = implicitly[String].length >= 2 + val z1: given String => Boolean = implicitly[String].length >= 2 assert(z1) - type StringlyBool = String |=> Boolean + type StringlyBool = given String => Boolean val z2: StringlyBool = implicitly[String].length >= 2 assert(z2) - type Stringly[T] = String |=> T + type Stringly[T] = given String => T val z3: Stringly[Boolean] = implicitly[String].length >= 2 assert(z3) - type GenericImplicit[X] = X |=> Boolean + type GenericImplicit[X] = given X => Boolean val z4: GenericImplicit[String] = implicitly[String].length >= 2 assert(z4) - val b = x with "hello" + val b = x given "hello" val b1: Boolean = b @@ -48,7 +48,7 @@ object Test { val bi1: Boolean = bi - val c = xx with ("hh", 22) + val c = xx given ("hh", 22) val c1: Int = c @@ -56,7 +56,7 @@ object Test { def foo(s: String): Stringly[Int] = 42 - (if ("".isEmpty) foo("") else foo("")).apply with "" + (if ("".isEmpty) foo("") else foo("")).apply given "" } } @@ -76,16 +76,16 @@ object Contextual { val Source = new Key[String] val Options = new Key[List[String]] - type Ctx[T] = Context |=> T + type Ctx[T] = given Context => T def ctx: Ctx[Context] = implicitly[Context] def compile(s: String): Ctx[Boolean] = - (runOn(new java.io.File(s)) with ctx.withBinding(Source, s)) >= 0 + (runOn(new java.io.File(s)) given ctx.withBinding(Source, s)) >= 0 def runOn(f: java.io.File): Ctx[Int] = { val options = List("-verbose", "-explaintypes") - process(f).apply with ctx.withBinding(Options, options) + process(f).apply given ctx.withBinding(Options, options) } def process(f: java.io.File): Ctx[Int] = @@ -151,7 +151,7 @@ object TransactionalExplicit { } object Transactional { - type Transactional[T] = Transaction |=> T + type Transactional[T] = given Transaction => T def transaction[T](op: Transactional[T]) = { implicit val trans: Transaction = new Transaction @@ -216,7 +216,7 @@ object TransactionalExpansion { } object TransactionalAbstracted { - type Transactional[T] = Transaction |=> T + type Transactional[T] = given Transaction => T trait TransOps { def thisTransaction: Transactional[Transaction] diff --git a/tests/run/implicitFuns2.scala b/tests/run/implicitFuns2.scala index 8f59819015a9..e947066bdc67 100644 --- a/tests/run/implicitFuns2.scala +++ b/tests/run/implicitFuns2.scala @@ -2,27 +2,27 @@ class A class B trait Foo { - def foo: A |=> B |=> Int + def foo: given A => given B => Int } class Foo1 extends Foo { - def foo: A |=> B |=> Int = 1 + def foo: given A => given B => Int = 1 } class Foo2 extends Foo1 { - override def foo: A |=> B |=> Int = 2 + override def foo: given A => given B => Int = 2 } trait Foo3 extends Foo { - override def foo: A |=> B |=> Int = 3 + override def foo: given A => given B => Int = 3 } class Bar[T] { - def bar: A |=> T = null.asInstanceOf[T] + def bar: given A => T = null.asInstanceOf[T] } -class Bar1 extends Bar[B |=> Int] { - override def bar: A |=> B |=> Int = 1 +class Bar1 extends Bar[given B => Int] { + override def bar: given A => given B => Int = 1 } object Test { diff --git a/tests/run/implicitShortcut/Base_1.scala b/tests/run/implicitShortcut/Base_1.scala index bbba570bcf38..91db5ee94880 100644 --- a/tests/run/implicitShortcut/Base_1.scala +++ b/tests/run/implicitShortcut/Base_1.scala @@ -3,6 +3,6 @@ package implicitShortcut class C abstract class Base[T] { - def foo(x: T): C |=> T = x + def foo(x: T): given C => T = x } \ No newline at end of file diff --git a/tests/run/implicitShortcut/Derived_2.scala b/tests/run/implicitShortcut/Derived_2.scala index b66bfcc17c02..045fcbc10e6d 100644 --- a/tests/run/implicitShortcut/Derived_2.scala +++ b/tests/run/implicitShortcut/Derived_2.scala @@ -1,5 +1,5 @@ package implicitShortcut class Derived extends Base[Int] { - override def foo(x: Int): C |=> Int = 42 + override def foo(x: Int): given C => Int = 42 } \ No newline at end of file diff --git a/tests/run/returning.scala b/tests/run/returning.scala index 28d65ed7056d..2271bb443016 100644 --- a/tests/run/returning.scala +++ b/tests/run/returning.scala @@ -14,9 +14,9 @@ object NonLocalReturns { def throwReturn[T](result: T)(implicit returner: ReturnThrowable[T]): Nothing = returner.throwReturn(result) - def returning[T](op: ReturnThrowable[T] |=> T): T = { + def returning[T](op: given ReturnThrowable[T] => T): T = { val returner = new ReturnThrowable[T] - try op with returner + try op given returner catch { case ex: ReturnThrowable[_] => if (ex `eq` returner) ex.result.asInstanceOf[T] else throw ex diff --git a/tests/run/tagless.scala b/tests/run/tagless.scala index d59b091b39bb..952aa3e44274 100644 --- a/tests/run/tagless.scala +++ b/tests/run/tagless.scala @@ -24,19 +24,19 @@ object Test extends App { } // An example tree - def tf0[T] with (e: Exp[T]): T = + def tf0[T] given (e: Exp[T]): T = e.add(e.lit(8), e.neg(e.add(e.lit(1), e.lit(2)))) // Typeclass-style Exp syntax object ExpSyntax { - def lit[T](i: Int) with (e: Exp[T]): T = e.lit(i) - def neg[T](t: T) with (e: Exp[T]): T = e.neg(t) - def add[T](l: T, r: T) with (e: Exp[T]): T = e.add(l, r) + def lit[T](i: Int) given (e: Exp[T]): T = e.lit(i) + def neg[T](t: T) given (e: Exp[T]): T = e.neg(t) + def add[T](l: T, r: T) given (e: Exp[T]): T = e.add(l, r) } import ExpSyntax._ // It's safe to always have these in scope // Another tree - def tf1[T] with Exp[T]: T = + def tf1[T] given Exp[T]: T = add(lit(8), neg(add(lit(1), lit(2)))) // Base operations as typeclasses @@ -60,7 +60,7 @@ object Test extends App { def mul(l: T, r: T): T } object MultSyntax { - def mul[T](l: T, r: T) with (e: Mult[T]): T = e.mul(l, r) + def mul[T](l: T, r: T) given (e: Mult[T]): T = e.mul(l, r) } import MultSyntax._ @@ -106,8 +106,8 @@ object Test extends App { object CanThrow { private class Exc(msg: String) extends Exception(msg) - def _throw(msg: String) with CanThrow: Nothing = throw new Exc(msg) - def _try[T](op: CanThrow |=> T)(handler: String => T): T = { + def _throw(msg: String) given CanThrow: Nothing = throw new Exc(msg) + def _try[T](op: Maybe[T])(handler: String => T): T = { instance of CanThrow try op catch { @@ -117,7 +117,7 @@ object Test extends App { } import CanThrow._ - type Maybe[T] = CanThrow |=> T + type Maybe[T] = given CanThrow => T def show[T](op: Maybe[T]): Unit = println(_try(op.toString)(identity)) @@ -138,7 +138,7 @@ object Test extends App { show(readInt("2")) show(readInt("X")) - def fromTree[T](t: Tree) with Exp[T]: Maybe[T] = t match { + def fromTree[T](t: Tree) given Exp[T]: Maybe[T] = t match { case Node("Lit", Leaf(n)) => lit(readInt(n)) case Node("Neg", t) => neg(fromTree(t)) case Node("Add", l , r) => add(fromTree(l), fromTree(r)) @@ -150,18 +150,18 @@ object Test extends App { show(fromTree[Tree](tf1Tree)) trait Wrapped { - def value[T] with Exp[T]: T + def value[T] given Exp[T]: T } instance of Exp[Wrapped] { def lit(i: Int) = new Wrapped { - def value[T] with (e: Exp[T]): T = e.lit(i) + def value[T] given (e: Exp[T]): T = e.lit(i) } def neg(t: Wrapped) = new Wrapped { - def value[T] with (e: Exp[T]): T = e.neg(t.value) + def value[T] given (e: Exp[T]): T = e.neg(t.value) } def add(l: Wrapped, r: Wrapped) = new Wrapped { - def value[T] with (e: Exp[T]): T = e.add(l.value, r.value) + def value[T] given (e: Exp[T]): T = e.add(l.value, r.value) } } @@ -170,7 +170,7 @@ object Test extends App { s"${t.value[Int]}\n${t.value[String]}" } - def fromTreeExt[T](recur: => Tree => Maybe[T]) with Exp[T]: Tree => Maybe[T] = { + def fromTreeExt[T](recur: => Tree => Maybe[T]) given Exp[T]: Tree => Maybe[T] = { case Node("Lit", Leaf(n)) => lit(readInt(n)) case Node("Neg", t) => neg(recur(t)) case Node("Add", l , r) => add(recur(l), recur(r)) @@ -181,7 +181,7 @@ object Test extends App { def fromTree2[T: Exp](t: Tree): Maybe[T] = fix(fromTreeExt[T])(t) - def fromTreeExt2[T](recur: => Tree => Maybe[T]) with Exp[T], Mult[T]: Tree => Maybe[T] = { + def fromTreeExt2[T](recur: => Tree => Maybe[T]) given Exp[T], Mult[T]: Tree => Maybe[T] = { case Node("Mult", l , r) => mul(recur(l), recur(r)) case t => fromTreeExt(recur)(t) } @@ -196,7 +196,7 @@ object Test extends App { // Added operation: negation pushdown enum NCtx { case Pos, Neg } - instance [T] with (e: Exp[T]) of Exp[NCtx => T] { + instance [T] given (e: Exp[T]) of Exp[NCtx => T] { import NCtx._ def lit(i: Int) = { case Pos => e.lit(i) @@ -216,7 +216,7 @@ object Test extends App { println(pushNeg(tf1[NCtx => String])) println(pushNeg(pushNeg(pushNeg(tf1))): String) - instance [T] with (e: Mult[T]) of Mult[NCtx => T] { + instance [T] given (e: Mult[T]) of Mult[NCtx => T] { import NCtx._ def mul(l: NCtx => T, r: NCtx => T): NCtx => T = { case Pos => e.mul(l(Pos), r(Pos)) @@ -237,14 +237,14 @@ object Test extends App { } // Going from ADT encoding to type class encoding - def finalize[T](i: IExp) with (e: Exp[T]): T = i match { + def finalize[T](i: IExp) given (e: Exp[T]): T = i match { case Lit(l) => e.lit(l) case Neg(n) => e.neg(finalize[T](n)) case Add(l, r) => e.add(finalize[T](l), finalize[T](r)) } // Abstracting over multiple typeclasses - type Ring[T] = Exp[T] |=> Mult[T] |=> T + type Ring[T] = given Exp[T] => given Mult[T] => T def tfm1a[T]: Ring[T] = add(lit(7), neg(mul(lit(1), lit(2)))) def tfm2a[T]: Ring[T] = mul(lit(7), tf1) diff --git a/tests/run/tasty-getfile-implicit-fun-context/Macro_1.scala b/tests/run/tasty-getfile-implicit-fun-context/Macro_1.scala index afc84c7e67d3..ae0fef057ab6 100644 --- a/tests/run/tasty-getfile-implicit-fun-context/Macro_1.scala +++ b/tests/run/tasty-getfile-implicit-fun-context/Macro_1.scala @@ -3,7 +3,7 @@ import scala.tasty.Reflection object SourceFiles { - type Macro[X] = Reflection |=> Expr[X] + type Macro[X] = given Reflection => Expr[X] def tastyContext(implicit ctx: Reflection): Reflection = ctx implicit inline def getThisFile: String = diff --git a/tests/run/tasty-implicit-fun-context-2/Macro_1.scala b/tests/run/tasty-implicit-fun-context-2/Macro_1.scala index 170080aab25b..07c838ee6503 100644 --- a/tests/run/tasty-implicit-fun-context-2/Macro_1.scala +++ b/tests/run/tasty-implicit-fun-context-2/Macro_1.scala @@ -3,13 +3,14 @@ import scala.tasty.Reflection object Foo { - type Macro[X] = Reflection |=> Expr[X] - type Tastier[X] = Reflection |=> X + type Macro[X] = given Reflection => Expr[X] + type Tastier[X] = given Reflection => X implicit inline def foo: String = ~fooImpl - def fooImpl(implicit reflect: Reflection): Reflection |=> Tastier[Reflection |=> Macro[String]] = { + def fooImpl(implicit reflect: Reflection): given Reflection => Tastier[given Reflection => Macro[String]] = { '("abc") } + }