From 91f05016876d7c23a865167ce8c6d55e24cc93b2 Mon Sep 17 00:00:00 2001 From: odersky Date: Sun, 11 Feb 2024 20:10:52 +0100 Subject: [PATCH 1/5] Update syntax.md 1. Add missing soft modifiers 2. Port changes from multiple type parameter sections to reference. Now that multiple type parameter sections are merged, this is the official syntax. This also covers extension method declarations. Fixes #19667 Fixes #19668 [Cherry-picked e06b8318f000a727c9c054801ed8d465a6ee5c29] --- docs/_docs/internals/syntax.md | 42 +++++++++++++++++++++++----------- docs/_docs/reference/syntax.md | 20 ++++++++-------- 2 files changed, 39 insertions(+), 23 deletions(-) diff --git a/docs/_docs/internals/syntax.md b/docs/_docs/internals/syntax.md index 85621a66a366..93011a114482 100644 --- a/docs/_docs/internals/syntax.md +++ b/docs/_docs/internals/syntax.md @@ -20,6 +20,8 @@ productions map to AST nodes. The following description of Scala tokens uses literal characters `‘c’` when referring to the ASCII fragment `\u0000` – `\u007F`. +Informal descriptions are typeset as `“some comment”`. + ## Lexical Syntax The lexical syntax of Scala is given by the following grammar in EBNF form: @@ -99,7 +101,10 @@ semi ::= ‘;’ | nl {nl} ## Optional Braces -The lexical analyzer also inserts `indent` and `outdent` tokens that represent regions of indented code [at certain points](../reference/other-new-features/indentation.md) +The principle of optional braces is that any keyword that can be followed by `{` can also be followed by an indented block, without needing an intervening `:`. +(Allowing an optional `:` would be counterproductive since it would introduce several ways to do the same thing.) + +The lexical analyzer inserts `indent` and `outdent` tokens that represent regions of indented code [at certain points](./other-new-features/indentation.md). In the context-free productions below we use the notation `<<< ts >>>` to indicate a token sequence `ts` that is either enclosed in a pair of braces `{ ts }` or that constitutes an indented region `indent ts outdent`. Analogously, the @@ -181,7 +186,7 @@ FunTypeArgs ::= InfixType | ‘(’ [ FunArgTypes ] ‘)’ | FunParamClause FunParamClause ::= ‘(’ TypedFunParam {‘,’ TypedFunParam } ‘)’ -TypedFunParam ::= [`erased`] id ‘:’ Type +TypedFunParam ::= [`erased`] id ‘:’ IntoType MatchType ::= InfixType `match` <<< TypeCaseClauses >>> InfixType ::= RefinedType {id [nl] RefinedType} InfixOp(t1, op, t2) RefinedType ::= AnnotType {[nl] Refinement} RefinedTypeTree(t, ds) @@ -201,14 +206,17 @@ SimpleType1 ::= id Singleton ::= SimpleRef | SimpleLiteral | Singleton ‘.’ id -FunArgType ::= [`erased`] Type - | [`erased`] ‘=>’ Type PrefixOp(=>, t) +FunArgType ::= IntoType + | ‘=>’ IntoType PrefixOp(=>, t) FunArgTypes ::= FunArgType { ‘,’ FunArgType } ParamType ::= [‘=>’] ParamValueType -ParamValueType ::= [‘into’] ExactParamType Into(t) -ExactParamType ::= ParamValueType [‘*’] PostfixOp(t, "*") +ParamValueType ::= IntoType [‘*’] PostfixOp(t, "*") +IntoType ::= [‘into’] IntoTargetType Into(t) + | ‘(’ ‘into’ IntoTargetType ‘)’ +IntoTargetType ::= Type + | FunTypeArgs (‘=>’ | ‘?=>’) IntoType TypeArgs ::= ‘[’ Types ‘]’ ts -Refinement ::= :<<< [RefineDef] {semi [RefineDef]} >>> ds +Refinement ::= :<<< [RefineDef] {semi [RefineDcl]} >>> ds TypeBounds ::= [‘>:’ Type] [‘<:’ Type] TypeBoundsTree(lo, hi) TypeParamBounds ::= TypeBounds {‘:’ Type} ContextBounds(typeBounds, tps) Types ::= Type {‘,’ Type} @@ -223,7 +231,7 @@ BlockResult ::= FunParams (‘=>’ | ‘?=>’) Block | HkTypeParamClause ‘=>’ Block | Expr1 FunParams ::= Bindings - | [`erased`] id + | id | ‘_’ Expr1 ::= [‘inline’] ‘if’ ‘(’ Expr ‘)’ {nl} Expr [[semi] ‘else’ Expr] If(Parens(cond), thenp, elsep?) | [‘inline’] ‘if’ Expr ‘then’ Expr [[semi] ‘else’ Expr] If(cond, thenp, elsep?) @@ -272,7 +280,7 @@ ColonArgument ::= colon [LambdaStart] LambdaStart ::= FunParams (‘=>’ | ‘?=>’) | HkTypeParamClause ‘=>’ Quoted ::= ‘'’ ‘{’ Block ‘}’ - | ‘'’ ‘[’ Type ‘]’ + | ‘'’ ‘[’ TypeBlock ‘]’ ExprSplice ::= spliceId -- if inside quoted block | ‘$’ ‘{’ Block ‘}’ -- unless inside quoted pattern | ‘$’ ‘{’ Pattern ‘}’ -- when inside quoted pattern @@ -294,6 +302,8 @@ BlockStat ::= Import | Extension | Expr1 | EndMarker +TypeBlock ::= {TypeBlockStat semi} Type +TypeBlockStat ::= ‘type’ {nl} TypeDcl ForExpr ::= ‘for’ ‘(’ Enumerators0 ‘)’ {nl} [‘do‘ | ‘yield’] Expr ForYield(enums, expr) / ForDo(enums, expr) | ‘for’ ‘{’ Enumerators0 ‘}’ {nl} [‘do‘ | ‘yield’] Expr @@ -376,8 +386,8 @@ Param ::= id ‘:’ ParamType [‘=’ Expr] ### Bindings and Imports ```ebnf -Bindings ::= ‘(’[`erased`] [Binding {‘,’ [`erased`] Binding}] ‘)’ -Binding ::= (id | ‘_’) [‘:’ Type] ValDef(_, id, tpe, EmptyTree) +Bindings ::= ‘(’ [Binding {‘,’ Binding}] ‘)’ +Binding ::= [`erased`] (id | ‘_’) [‘:’ Type] ValDef(_, id, tpe, EmptyTree) Modifier ::= LocalModifier | AccessModifier @@ -390,6 +400,10 @@ LocalModifier ::= ‘abstract’ | ‘implicit’ | ‘lazy’ | ‘inline’ + | ‘transparent’ + | ‘infix’ + | ‘erased’ + AccessModifier ::= (‘private’ | ‘protected’) [AccessQualifier] AccessQualifier ::= ‘[’ id ‘]’ @@ -414,9 +428,11 @@ EndMarkerTag ::= id | ‘if’ | ‘while’ | ‘for’ | ‘match’ | ### Definitions ```ebnf -RefineDef ::= ‘val’ ValDef - | ‘def’ DefDef +RefineDcl ::= ‘val’ ValDcl + | ‘def’ DefDcl | ‘type’ {nl} TypeDef +ValDcl ::= ids ‘:’ Type +DefDcl ::= DefSig ‘:’ Type Def ::= ‘val’ PatDef | ‘var’ PatDef diff --git a/docs/_docs/reference/syntax.md b/docs/_docs/reference/syntax.md index 67ebfbe5d3c2..885c30fe9558 100644 --- a/docs/_docs/reference/syntax.md +++ b/docs/_docs/reference/syntax.md @@ -381,6 +381,8 @@ LocalModifier ::= ‘abstract’ | ‘implicit’ | ‘lazy’ | ‘inline’ + | ‘transparent’ + | ‘infix’ AccessModifier ::= (‘private’ | ‘protected’) [AccessQualifier] AccessQualifier ::= ‘[’ id ‘]’ @@ -407,24 +409,22 @@ EndMarkerTag ::= id | ‘if’ | ‘while’ | ‘for’ | ‘match’ | ``` RefineDcl ::= ‘val’ ValDcl | ‘def’ DefDcl - | ‘type’ {nl} TypeDcl -Dcl ::= RefineDcl - | ‘var’ VarDcl + | ‘type’ {nl} TypeDef ValDcl ::= ids ‘:’ Type -VarDcl ::= ids ‘:’ Type DefDcl ::= DefSig ‘:’ Type -DefSig ::= id [DefTypeParamClause] [TypelessClauses] [DefImplicitClause] -TypeDcl ::= id [TypeParamClause] {FunParamClause} TypeBounds Def ::= ‘val’ PatDef | ‘var’ PatDef | ‘def’ DefDef | ‘type’ {nl} TypeDcl | TmplDef -PatDef ::= ids [‘:’ Type] ‘=’ Expr - | Pattern2 [‘:’ Type] ‘=’ Expr -DefDef ::= DefSig [‘:’ Type] ‘=’ Expr - | ‘this’ TypelessClauses [DefImplicitClause] ‘=’ ConstrExpr +PatDef ::= ids [‘:’ Type] [‘=’ Expr] + | Pattern2 [‘:’ Type] [‘=’ Expr] PatDef(_, pats, tpe?, expr) +DefDef ::= DefSig [‘:’ Type] [‘=’ Expr] DefDef(_, name, paramss, tpe, expr) + | ‘this’ TypelessClauses [DefImplicitClause] ‘=’ ConstrExpr DefDef(_, , vparamss, EmptyTree, expr | Block) +DefSig ::= id [DefParamClauses] [DefImplicitClause] +TypeDef ::= id [TypeParamClause] {FunParamClause} TypeBounds TypeDefTree(_, name, tparams, bound + [‘=’ Type] TmplDef ::= ([‘case’] ‘class’ | ‘trait’) ClassDef | [‘case’] ‘object’ ObjectDef From c123c2021487904af2ed75167cfa4c1942b3006b Mon Sep 17 00:00:00 2001 From: Wojciech Mazur Date: Mon, 1 Jul 2024 21:22:41 +0200 Subject: [PATCH 2/5] Align Parser with syntax - Change doc comments to match described syntax - Refactor `typ` method to make it clear it matches the syntax [Cherry-picked 6a9bea8138bb2c307d61571cd0b9120ddfa8c404][modified] --- .../dotty/tools/dotc/parsing/Parsers.scala | 176 +++++++++--------- .../dotty/tools/dotc/transform/Recheck.scala | 3 +- docs/_docs/internals/syntax.md | 10 +- 3 files changed, 91 insertions(+), 98 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 5fc6bf539ac0..53d0e056b2a5 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -1521,13 +1521,15 @@ object Parsers { * PolyFunType ::= HKTypeParamClause '=>' Type * | HKTypeParamClause ‘->’ [CaptureSet] Type -- under pureFunctions * FunTypeArgs ::= InfixType - * | `(' [ [ ‘['erased'] FunArgType {`,' FunArgType } ] `)' - * | '(' [ ‘['erased'] TypedFunParam {',' TypedFunParam } ')' + * | `(' [ FunArgType {`,' FunArgType } ] `)' + * | '(' [ TypedFunParam {',' TypedFunParam } ')' + * MatchType ::= InfixType `match` <<< TypeCaseClauses >>> */ def typ(): Tree = val start = in.offset var imods = Modifiers() var erasedArgs: ListBuffer[Boolean] = ListBuffer() + def functionRest(params: List[Tree]): Tree = val paramSpan = Span(start, in.lastOffset) atSpan(start, in.offset) { @@ -1556,7 +1558,8 @@ object Parsers { else accept(ARROW) - val resultType = if isPure then capturesAndResult(typ) else typ() + val resultType = + if isPure then capturesAndResult(typ) else typ() if token == TLARROW then for case ValDef(_, tpt, _) <- params do if isByNameType(tpt) then @@ -1573,99 +1576,94 @@ object Parsers { Function(params, resultType) } - var isValParamList = false + def typeRest(t: Tree) = in.token match + case ARROW | CTXARROW => + erasedArgs.addOne(false) + functionRest(t :: Nil) + case MATCH => + matchType(t) + case FORSOME => + syntaxError(ExistentialTypesNoLongerSupported()) + t + case _ if isPureArrow => + erasedArgs.addOne(false) + functionRest(t :: Nil) + case _ => + if erasedArgs.contains(true) && !t.isInstanceOf[FunctionWithMods] then + syntaxError(ErasedTypesCanOnlyBeFunctionTypes(), implicitKwPos(start)) + t - val t = - if (in.token == LPAREN) { + var isValParamList = false + if in.token == LPAREN then + in.nextToken() + if in.token == RPAREN then in.nextToken() - if (in.token == RPAREN) { - in.nextToken() - functionRest(Nil) - } - else { - val paramStart = in.offset - def addErased() = - erasedArgs.addOne(isErasedKw) - if isErasedKw then { in.skipToken(); } - addErased() - val ts = in.currentRegion.withCommasExpected { + functionRest(Nil) + else + val paramStart = in.offset + def addErased() = + erasedArgs.addOne(isErasedKw) + if isErasedKw then in.skipToken() + addErased() + val args = + in.currentRegion.withCommasExpected: funArgType() match case Ident(name) if name != tpnme.WILDCARD && in.isColon => isValParamList = true - def funParam(start: Offset, mods: Modifiers) = { - atSpan(start) { + def funParam(start: Offset, mods: Modifiers) = + atSpan(start): addErased() typedFunParam(in.offset, ident(), imods) - } - } commaSeparatedRest( typedFunParam(paramStart, name.toTermName, imods), () => funParam(in.offset, imods)) case t => - def funParam() = { - addErased() - funArgType() - } - commaSeparatedRest(t, funParam) - } - accept(RPAREN) - if isValParamList || in.isArrow || isPureArrow then - functionRest(ts) - else { - val ts1 = ts.mapConserve { t => - if isByNameType(t) then - syntaxError(ByNameParameterNotSupported(t), t.span) - stripByNameType(t) - else - t - } - val tuple = atSpan(start) { makeTupleOrParens(ts1) } - infixTypeRest( - refinedTypeRest( - withTypeRest( - annotTypeRest( - simpleTypeRest(tuple))))) - } - } - } - else if (in.token == LBRACKET) { - val start = in.offset - val tparams = typeParamClause(ParamOwner.TypeParam) - if (in.token == TLARROW) - atSpan(start, in.skipToken())(LambdaTypeTree(tparams, toplevelTyp())) - else if (in.token == ARROW || isPureArrow(nme.PUREARROW)) { - val arrowOffset = in.skipToken() - val body = toplevelTyp() - atSpan(start, arrowOffset) { - getFunction(body) match { - case Some(f) => - checkFunctionNotErased(f, "poly function") - PolyFunction(tparams, body) - case None => - syntaxError(em"Implementation restriction: polymorphic function types must have a value parameter", arrowOffset) - Ident(nme.ERROR.toTypeName) - } - } - } - else { accept(TLARROW); typ() } - } - else if (in.token == INDENT) enclosed(INDENT, typ()) - else infixType() - - in.token match - case ARROW | CTXARROW => - erasedArgs.addOne(false) - functionRest(t :: Nil) - case MATCH => matchType(t) - case FORSOME => syntaxError(ExistentialTypesNoLongerSupported()); t - case _ => - if isPureArrow then - erasedArgs.addOne(false) - functionRest(t :: Nil) + def funArg() = + addErased() + funArgType() + commaSeparatedRest(t, funArg) + accept(RPAREN) + if isValParamList || in.isArrow || isPureArrow then + functionRest(args) else - if (erasedArgs.contains(true) && !t.isInstanceOf[FunctionWithMods]) - syntaxError(ErasedTypesCanOnlyBeFunctionTypes(), implicitKwPos(start)) - t + val args1 = args.mapConserve: t => + if isByNameType(t) then + syntaxError(ByNameParameterNotSupported(t), t.span) + stripByNameType(t) + else + t + val tuple = atSpan(start): + makeTupleOrParens(args1) + typeRest: + infixTypeRest: + refinedTypeRest: + withTypeRest: + annotTypeRest: + simpleTypeRest(tuple) + else if in.token == LBRACKET then + val start = in.offset + val tparams = typeParamClause(ParamOwner.TypeParam) + if in.token == TLARROW then + atSpan(start, in.skipToken()): + LambdaTypeTree(tparams, toplevelTyp()) + else if in.token == ARROW || isPureArrow(nme.PUREARROW) then + val arrowOffset = in.skipToken() + val body = toplevelTyp() + atSpan(start, arrowOffset): + getFunction(body) match + case Some(f) => + checkFunctionNotErased(f, "poly function") + PolyFunction(tparams, body) + case None => + syntaxError(em"Implementation restriction: polymorphic function types must have a value parameter", arrowOffset) + Ident(nme.ERROR.toTypeName) + else + accept(TLARROW) + typ() + else if in.token == INDENT then + enclosed(INDENT, typ()) + else + typeRest(infixType()) end typ private def makeKindProjectorTypeDef(name: TypeName): TypeDef = { @@ -1702,7 +1700,7 @@ object Parsers { private def implicitKwPos(start: Int): Span = Span(start, start + nme.IMPLICITkw.asSimpleName.length) - /** TypedFunParam ::= id ':' Type */ + /** TypedFunParam ::= [`erased`] id ':' Type */ def typedFunParam(start: Offset, name: TermName, mods: Modifiers = EmptyModifiers): ValDef = atSpan(start) { acceptColon() @@ -2016,7 +2014,7 @@ object Parsers { */ def paramType(): Tree = paramTypeOf(paramValueType) - /** ParamValueType ::= [`into`] Type [`*'] + /** ParamValueType ::= Type [`*'] */ def paramValueType(): Tree = { val t = maybeInto(toplevelTyp) @@ -2374,7 +2372,7 @@ object Parsers { Match(t, inBracesOrIndented(caseClauses(() => caseClause()))) } - /** `match' `{' TypeCaseClauses `}' + /** `match' <<< TypeCaseClauses >>> */ def matchType(t: Tree): MatchTypeTree = atSpan(startOffset(t), accept(MATCH)) { @@ -2384,7 +2382,7 @@ object Parsers { /** FunParams ::= Bindings * | id * | `_' - * Bindings ::= `(' [[‘erased’] Binding {`,' Binding}] `)' + * Bindings ::= `(' [Binding {`,' Binding}] `)' */ def funParams(mods: Modifiers, location: Location): List[Tree] = if in.token == LPAREN then @@ -3126,7 +3124,7 @@ object Parsers { * | AccessModifier * | override * | opaque - * LocalModifier ::= abstract | final | sealed | open | implicit | lazy | erased | inline | transparent + * LocalModifier ::= abstract | final | sealed | open | implicit | lazy | inline | transparent | infix | erased */ def modifiers(allowed: BitSet = modifierTokens, start: Modifiers = Modifiers()): Modifiers = { @tailrec diff --git a/compiler/src/dotty/tools/dotc/transform/Recheck.scala b/compiler/src/dotty/tools/dotc/transform/Recheck.scala index 9554fa4ffcda..5963a98f50f2 100644 --- a/compiler/src/dotty/tools/dotc/transform/Recheck.scala +++ b/compiler/src/dotty/tools/dotc/transform/Recheck.scala @@ -9,13 +9,12 @@ import ast.* import Names.Name import Phases.Phase import DenotTransformers.{DenotTransformer, IdentityDenotTransformer, SymTransformer} -import NamerOps.{methodType, linkConstructorParams} +import NamerOps.linkConstructorParams import NullOpsDecorator.stripNull import typer.ErrorReporting.err import typer.ProtoTypes.* import typer.TypeAssigner.seqLitType import typer.ConstFold -import NamerOps.methodType import config.Printers.recheckr import util.Property import StdNames.nme diff --git a/docs/_docs/internals/syntax.md b/docs/_docs/internals/syntax.md index 93011a114482..5038bb6423a8 100644 --- a/docs/_docs/internals/syntax.md +++ b/docs/_docs/internals/syntax.md @@ -186,7 +186,7 @@ FunTypeArgs ::= InfixType | ‘(’ [ FunArgTypes ] ‘)’ | FunParamClause FunParamClause ::= ‘(’ TypedFunParam {‘,’ TypedFunParam } ‘)’ -TypedFunParam ::= [`erased`] id ‘:’ IntoType +TypedFunParam ::= [`erased`] id ‘:’ Type MatchType ::= InfixType `match` <<< TypeCaseClauses >>> InfixType ::= RefinedType {id [nl] RefinedType} InfixOp(t1, op, t2) RefinedType ::= AnnotType {[nl] Refinement} RefinedTypeTree(t, ds) @@ -206,15 +206,11 @@ SimpleType1 ::= id Singleton ::= SimpleRef | SimpleLiteral | Singleton ‘.’ id -FunArgType ::= IntoType - | ‘=>’ IntoType PrefixOp(=>, t) +FunArgType ::= Type + | ‘=>’ Type PrefixOp(=>, t) FunArgTypes ::= FunArgType { ‘,’ FunArgType } ParamType ::= [‘=>’] ParamValueType ParamValueType ::= IntoType [‘*’] PostfixOp(t, "*") -IntoType ::= [‘into’] IntoTargetType Into(t) - | ‘(’ ‘into’ IntoTargetType ‘)’ -IntoTargetType ::= Type - | FunTypeArgs (‘=>’ | ‘?=>’) IntoType TypeArgs ::= ‘[’ Types ‘]’ ts Refinement ::= :<<< [RefineDef] {semi [RefineDcl]} >>> ds TypeBounds ::= [‘>:’ Type] [‘<:’ Type] TypeBoundsTree(lo, hi) From 8274988be647feeaf11338c3e976dd6b03c2e440 Mon Sep 17 00:00:00 2001 From: Wojciech Mazur Date: Mon, 1 Jul 2024 21:25:02 +0200 Subject: [PATCH 3/5] Simplify erased parameter syntax erased is not always a modifier on the parameter name. The syntax `erased Type` is dropped. There's not really a need for this syntactic inconsistency. [Cherry-picked 6159045fd1d6fe4d1c330ec8dccd6a21b3d2adf0][modified] --- compiler/src/dotty/tools/dotc/parsing/Parsers.scala | 2 +- tests/neg/lambda-infer.scala | 4 ++-- tests/run/erased-lambdas.scala | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 53d0e056b2a5..84714b37bf69 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -1619,7 +1619,7 @@ object Parsers { () => funParam(in.offset, imods)) case t => def funArg() = - addErased() + erasedArgs.addOne(false) funArgType() commaSeparatedRest(t, funArg) accept(RPAREN) diff --git a/tests/neg/lambda-infer.scala b/tests/neg/lambda-infer.scala index 90f40aa05e86..6c3db90cb893 100644 --- a/tests/neg/lambda-infer.scala +++ b/tests/neg/lambda-infer.scala @@ -1,6 +1,6 @@ //> using options -language:experimental.erasedDefinitions -type F = (Int, erased Int) => Int +type F = (x: Int, erased y: Int) => Int erased class A @@ -14,7 +14,7 @@ erased class A use { (x, y) => x } // error: Expected F got (Int, Int) => Int - def singleParam(f: (erased Int) => Int) = f(5) + def singleParam(f: (erased x: Int) => Int) = f(5) singleParam(x => 5) // error: Expected (erased Int) => Int got Int => Int singleParam((erased x) => 5) // ok diff --git a/tests/run/erased-lambdas.scala b/tests/run/erased-lambdas.scala index 9c107e0fa0d4..e6be086bec8c 100644 --- a/tests/run/erased-lambdas.scala +++ b/tests/run/erased-lambdas.scala @@ -3,8 +3,8 @@ // lambdas should parse and work -type F = (erased Int, String) => String -type S = (Int, erased String) => Int +type F = (erased x: Int, y: String) => String +type S = (x: Int, erased y: String) => Int def useF(f: F) = f(5, "a") def useS(f: S) = f(5, "a") @@ -16,7 +16,7 @@ val fsExpl = (x: Int, erased y: String) => x // contextual lambdas should work -type FC = (Int, erased String) ?=> Int +type FC = (x: Int, erased y: String) ?=> Int def useCtx(f: FC) = f(using 5, "a") @@ -25,7 +25,7 @@ val fCvExpl = (x: Int, erased y: String) ?=> x // nested lambdas should work -val nested: Int => (String, erased Int) => FC = a => (_, erased _) => (c, erased d) ?=> a + c +val nested: Int => (x: String, erased y: Int) => FC = a => (_, erased _) => (c, erased d) ?=> a + c @main def Test() = assert("a" == useF(ff)) From 2073550c5a45250430205c953f40e0ffa1d5fff3 Mon Sep 17 00:00:00 2001 From: Wojciech Mazur Date: Mon, 1 Jul 2024 21:29:21 +0200 Subject: [PATCH 4/5] Address review comments [Cherry-picked 32723c5811a88a5ccad9c2ead16dcbb0610f80ab][modified] --- compiler/src/dotty/tools/dotc/parsing/Parsers.scala | 4 ++-- docs/_docs/internals/syntax.md | 9 ++++----- docs/_docs/reference/syntax.md | 9 ++++++--- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 84714b37bf69..98906a5703d2 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -1528,7 +1528,7 @@ object Parsers { def typ(): Tree = val start = in.offset var imods = Modifiers() - var erasedArgs: ListBuffer[Boolean] = ListBuffer() + val erasedArgs: ListBuffer[Boolean] = ListBuffer() def functionRest(params: List[Tree]): Tree = val paramSpan = Span(start, in.lastOffset) @@ -3281,7 +3281,7 @@ object Parsers { /** ClsTermParamClause ::= ‘(’ ClsParams ‘)’ | UsingClsTermParamClause * UsingClsTermParamClause::= ‘(’ ‘using’ [‘erased’] (ClsParams | ContextTypes) ‘)’ * ClsParams ::= ClsParam {‘,’ ClsParam} - * ClsParam ::= {Annotation} + * ClsParam ::= {Annotation} [{Modifier} (‘val’ | ‘var’)] Param * * TypelessClause ::= DefTermParamClause * | UsingParamClause diff --git a/docs/_docs/internals/syntax.md b/docs/_docs/internals/syntax.md index 5038bb6423a8..471ee1b5d41f 100644 --- a/docs/_docs/internals/syntax.md +++ b/docs/_docs/internals/syntax.md @@ -210,9 +210,9 @@ FunArgType ::= Type | ‘=>’ Type PrefixOp(=>, t) FunArgTypes ::= FunArgType { ‘,’ FunArgType } ParamType ::= [‘=>’] ParamValueType -ParamValueType ::= IntoType [‘*’] PostfixOp(t, "*") +ParamValueType ::= Type [‘*’] PostfixOp(t, "*") TypeArgs ::= ‘[’ Types ‘]’ ts -Refinement ::= :<<< [RefineDef] {semi [RefineDcl]} >>> ds +Refinement ::= :<<< [RefineDcl] {semi [RefineDcl]} >>> ds TypeBounds ::= [‘>:’ Type] [‘<:’ Type] TypeBoundsTree(lo, hi) TypeParamBounds ::= TypeBounds {‘:’ Type} ContextBounds(typeBounds, tps) Types ::= Type {‘,’ Type} @@ -299,7 +299,7 @@ BlockStat ::= Import | Expr1 | EndMarker TypeBlock ::= {TypeBlockStat semi} Type -TypeBlockStat ::= ‘type’ {nl} TypeDcl +TypeBlockStat ::= ‘type’ {nl} TypeDef ForExpr ::= ‘for’ ‘(’ Enumerators0 ‘)’ {nl} [‘do‘ | ‘yield’] Expr ForYield(enums, expr) / ForDo(enums, expr) | ‘for’ ‘{’ Enumerators0 ‘}’ {nl} [‘do‘ | ‘yield’] Expr @@ -359,7 +359,7 @@ ClsParamClause ::= [nl] ‘(’ ClsParams ‘)’ | [nl] ‘(’ ‘using’ (ClsParams | FunArgTypes) ‘)’ ClsParams ::= ClsParam {‘,’ ClsParam} ClsParam ::= {Annotation} ValDef(mods, id, tpe, expr) -- point of mods on val/var - [{Modifier} (‘val’ | ‘var’) | ‘inline’] Param + [{Modifier} (‘val’ | ‘var’)] Param DefParamClauses ::= DefParamClause { DefParamClause } -- and two DefTypeParamClause cannot be adjacent DefParamClause ::= DefTypeParamClause @@ -473,7 +473,6 @@ TemplateBody ::= :<<< [SelfType] TemplateStat {semi TemplateStat} >>> TemplateStat ::= Import | Export | {Annotation [nl]} {Modifier} Def - | {Annotation [nl]} {Modifier} Dcl | Extension | Expr1 | EndMarker diff --git a/docs/_docs/reference/syntax.md b/docs/_docs/reference/syntax.md index 885c30fe9558..be64abb07119 100644 --- a/docs/_docs/reference/syntax.md +++ b/docs/_docs/reference/syntax.md @@ -348,8 +348,12 @@ ClsParamClauses ::= {ClsParamClause} [[nl] ‘(’ [‘implicit’] ClsParams ClsParamClause ::= [nl] ‘(’ ClsParams ‘)’ | [nl] ‘(’ ‘using’ (ClsParams | FunArgTypes) ‘)’ ClsParams ::= ClsParam {‘,’ ClsParam} -ClsParam ::= {Annotation} [{Modifier} (‘val’ | ‘var’) | ‘inline’] Param +ClsParam ::= {Annotation} [{Modifier} (‘val’ | ‘var’)] Param +DefParamClauses ::= DefParamClause { DefParamClause } -- and two DefTypeParamClause cannot be adjacent +DefParamClause ::= DefTypeParamClause + | DefTermParamClause + | UsingParamClause TypelessClauses ::= TypelessClause {TypelessClause} TypelessClause ::= DefTermParamClause | UsingParamClause @@ -416,7 +420,7 @@ DefDcl ::= DefSig ‘:’ Type Def ::= ‘val’ PatDef | ‘var’ PatDef | ‘def’ DefDef - | ‘type’ {nl} TypeDcl + | ‘type’ {nl} TypeDef | TmplDef PatDef ::= ids [‘:’ Type] [‘=’ Expr] | Pattern2 [‘:’ Type] [‘=’ Expr] PatDef(_, pats, tpe?, expr) @@ -456,7 +460,6 @@ TemplateBody ::= :<<< [SelfType] TemplateStat {semi TemplateStat} >>> TemplateStat ::= Import | Export | {Annotation [nl]} {Modifier} Def - | {Annotation [nl]} {Modifier} Dcl | Extension | Expr1 | EndMarker From 889e27480ff9d9cd13b6ca139088945a23839ca1 Mon Sep 17 00:00:00 2001 From: odersky Date: Tue, 13 Feb 2024 22:59:07 +0100 Subject: [PATCH 5/5] Update docs/_docs/internals/syntax.md Co-authored-by: Eugene Flesselle [Cherry-picked f2f505194687d2bfe2de6d9688ff79518360f12d] --- docs/_docs/internals/syntax.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_docs/internals/syntax.md b/docs/_docs/internals/syntax.md index 471ee1b5d41f..ae6d85c7deae 100644 --- a/docs/_docs/internals/syntax.md +++ b/docs/_docs/internals/syntax.md @@ -104,7 +104,7 @@ semi ::= ‘;’ | nl {nl} The principle of optional braces is that any keyword that can be followed by `{` can also be followed by an indented block, without needing an intervening `:`. (Allowing an optional `:` would be counterproductive since it would introduce several ways to do the same thing.) -The lexical analyzer inserts `indent` and `outdent` tokens that represent regions of indented code [at certain points](./other-new-features/indentation.md). +The lexical analyzer inserts `indent` and `outdent` tokens that represent regions of indented code [at certain points](../reference/other-new-features/indentation.md). In the context-free productions below we use the notation `<<< ts >>>` to indicate a token sequence `ts` that is either enclosed in a pair of braces `{ ts }` or that constitutes an indented region `indent ts outdent`. Analogously, the