diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index 8a4fec35b893..c3682329cd68 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -158,7 +158,7 @@ object desugar { vparamss = (setterParam :: Nil) :: Nil, tpt = TypeTree(defn.UnitType), rhs = setterRhs - ).withMods((mods | Accessor) &~ CaseAccessor) + ).withMods((mods | Accessor) &~ (CaseAccessor | Implicit | Given | Lazy)) Thicket(vdef, setter) } else vdef diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 20944cb4aaa2..8985088ff2fb 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -2082,12 +2082,12 @@ object Parsers { if (in.token == LBRACKET) typeParamClause(ownerKind) else Nil /** ClsParamClause ::= [nl] [‘erased’] ‘(’ [ClsParams] ‘)’ - * | ‘given’ [‘erased’] (‘(’ ClsParams ‘)’ | ContextTypes) + * | ‘given’ [‘erased’] (‘(’ ClsParams ‘)’ | GivenTypes) * ClsParams ::= ClsParam {`' ClsParam} * ClsParam ::= {Annotation} [{ParamModifier} (`val' | `var') | `inline'] Param * DefParamClause ::= [nl] [‘erased’] ‘(’ [DefParams] ‘)’ | GivenParamClause - * GivenParamClause ::= ‘given’ [‘erased’] (‘(’ DefParams ‘)’ | ContextTypes) - * ContextTypes ::= RefinedType {`,' RefinedType} + * GivenParamClause ::= ‘given’ [‘erased’] (‘(’ DefParams ‘)’ | GivenTypes) + * GivenTypes ::= RefinedType {`,' RefinedType} * DefParams ::= DefParam {`,' DefParam} * DefParam ::= {Annotation} [`inline'] Param * Param ::= id `:' ParamType [`=' Expr] @@ -2190,7 +2190,19 @@ object Parsers { } val isContextual = initialMods.is(Given) newLineOptWhenFollowedBy(LPAREN) - if (in.token == LPAREN) { + def isParamClause: Boolean = + !isContextual || { + val lookahead = in.lookaheadScanner + lookahead.nextToken() + paramIntroTokens.contains(lookahead.token) && { + lookahead.token != IDENTIFIER || + lookahead.name == nme.inline || { + lookahead.nextToken() + lookahead.token == COLON + } + } + } + if (in.token == LPAREN && isParamClause) { if (ofInstance && !isContextual) syntaxError(em"parameters of instance definitions must come after `given'") val params = paramClause( @@ -2203,7 +2215,7 @@ object Parsers { params :: (if (lastClause) Nil else recur(firstClause = false, nparams + params.length)) } else if (isContextual) { - val tps = commaSeparated(refinedType) + val tps = commaSeparated(() => annotType()) var counter = nparams def nextIdx = { counter += 1; counter } val params = tps.map(makeSyntheticParameter(nextIdx, _, Given | Implicit)) @@ -2612,8 +2624,8 @@ object Parsers { /** InstanceDef ::= [id] InstanceParams InstanceBody * InstanceParams ::= [DefTypeParamClause] {GivenParamClause} - * InstanceBody ::= [‘of’ ConstrApp {‘,’ ConstrApp }] [TemplateBody] - * | ‘of’ Type ‘=’ Expr + * InstanceBody ::= [‘for’ ConstrApp {‘,’ ConstrApp }] [TemplateBody] + * | ‘for’ Type ‘=’ Expr */ def instanceDef(start: Offset, mods: Modifiers, instanceMod: Mod) = atSpan(start, nameStart) { var mods1 = addMod(mods, instanceMod) diff --git a/compiler/src/dotty/tools/dotc/parsing/Tokens.scala b/compiler/src/dotty/tools/dotc/parsing/Tokens.scala index 56b5e8b825ac..6269e6608db5 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Tokens.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Tokens.scala @@ -240,6 +240,8 @@ object Tokens extends TokensCommon { final val modifierFollowers = modifierTokens | defIntroTokens + final val paramIntroTokens: TokenSet = modifierTokens | identifierTokens | BitSet(AT, VAL, VAR, IMPLICIT) + /** Is token only legal as start of statement (eof also included)? */ final val mustStartStatTokens: TokenSet = defIntroTokens | modifierTokens | BitSet(IMPORT, EXPORT, PACKAGE) diff --git a/compiler/test/dotc/run-from-tasty.blacklist b/compiler/test/dotc/run-from-tasty.blacklist index fe0acf63becb..10b7644a5d93 100644 --- a/compiler/test/dotc/run-from-tasty.blacklist +++ b/compiler/test/dotc/run-from-tasty.blacklist @@ -3,3 +3,6 @@ eff-dependent.scala # It seems we still harmonize types in fromTasty. Not sure where this happens puzzle.scala + +# We get: class Foo needs to be abstract, since implicit val x$1: TC is not defined +i2567.scala diff --git a/docs/docs/internals/syntax.md b/docs/docs/internals/syntax.md index 6381d23ca996..7bc29e4782ed 100644 --- a/docs/docs/internals/syntax.md +++ b/docs/docs/internals/syntax.md @@ -292,7 +292,7 @@ HkTypeParam ::= {Annotation} [‘+’ | ‘-’] (Id[HkTypeParamClause] | ClsParamClauses ::= {ClsParamClause} [[nl] ‘(’ [‘implicit’] ClsParams ‘)’] ClsParamClause ::= [nl] [‘erased’] ‘(’ [ClsParams] ‘)’ - | ‘given’ [‘erased’] (‘(’ ClsParams ‘)’ | ContextTypes) + | ‘given’ [‘erased’] (‘(’ ClsParams ‘)’ | GivenTypes) ClsParams ::= ClsParam {‘,’ ClsParam} ClsParam ::= {Annotation} ValDef(mods, id, tpe, expr) -- point of mods on val/var [{Modifier} (‘val’ | ‘var’) | ‘inline’] Param @@ -301,10 +301,10 @@ Param ::= id ‘:’ ParamType [‘=’ Expr] DefParamClauses ::= {DefParamClause} [[nl] ‘(’ [‘implicit’] DefParams ‘)’] DefParamClause ::= [nl] [‘erased’] ‘(’ [DefParams] ‘)’ | GivenParamClause -GivenParamClause ::= ‘given’ [‘erased’] (‘(’ DefParams ‘)’ | ContextTypes) +GivenParamClause ::= ‘given’ [‘erased’] (‘(’ DefParams ‘)’ | GivenTypes) DefParams ::= DefParam {‘,’ DefParam} DefParam ::= {Annotation} [‘inline’] Param ValDef(mods, id, tpe, expr) -- point of mods at id. -ContextTypes ::= RefinedType {‘,’ RefinedType} +GivenTypes ::= AnnotType {‘,’ AnnotType} ClosureMods ::= { ‘implicit’ | ‘erased’ | ‘given’} ``` @@ -356,7 +356,6 @@ Def ::= ‘val’ PatDef | ‘var’ VarDef | ‘def’ DefDef | ‘type’ {nl} TypeDcl - | ‘instance’ {nl} InstanceDef | TmplDef | INT PatDef ::= Pattern2 {‘,’ Pattern2} [‘:’ Type] ‘=’ Expr PatDef(_, pats, tpe?, expr) @@ -379,8 +378,8 @@ ObjectDef ::= id [Template] EnumDef ::= id ClassConstr InheritClauses EnumBody EnumDef(mods, name, tparams, template) InstanceDef ::= [id] InstanceParams InstanceBody InstanceParams ::= [DefTypeParamClause] {GivenParamClause} -InstanceBody ::= [‘of’ ConstrApp {‘,’ ConstrApp }] [TemplateBody] - | ‘of’ Type ‘=’ Expr +InstanceBody ::= [‘for’ ConstrApp {‘,’ ConstrApp }] [TemplateBody] + | ‘for’ Type ‘=’ Expr Template ::= InheritClauses [TemplateBody] Template(constr, parents, self, stats) InheritClauses ::= [‘extends’ ConstrApps] [‘derives’ QualId {‘,’ QualId}] ConstrApps ::= ConstrApp {‘with’ ConstrApp} diff --git a/docs/docs/reference/contextual/inferable-params.md b/docs/docs/reference/contextual/inferable-params.md index 39f5229427ae..a3d2b1e80fdc 100644 --- a/docs/docs/reference/contextual/inferable-params.md +++ b/docs/docs/reference/contextual/inferable-params.md @@ -41,8 +41,7 @@ def maximum[T](xs: List[T]) given Ord[T]: T = inferred argument to `max`. The name of the parameter is left out. Generally, inferable parameters may be given either as a parameter list `(p_1: T_1, ..., p_n: T_n)` -or as a sequence of types, separated by commas. To distinguish the two, a leading -`(` always indicates a parameter list. +or as a sequence of types, separated by commas. ## Inferring Complex Arguments @@ -101,11 +100,11 @@ Functions like `the` that have only inferable parameters are also called _contex 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 ::= ... - | ‘given’ (‘(’ [ClsParams] ‘)’ | ContextTypes) + | ‘given’ (‘(’ [ClsParams] ‘)’ | GivenTypes) DefParamClause ::= ... - | InferParamClause -InferParamClause ::= ‘given’ (‘(’ DefParams ‘)’ | ContextTypes) -ContextTypes ::= RefinedType {‘,’ RefinedType} + | GivenParamClause +GivenParamClause ::= ‘given’ (‘(’ DefParams ‘)’ | GivenTypes) +GivenTypes ::= AnnotType {‘,’ AnnotType} InfixExpr ::= ... | InfixExpr ‘given’ (InfixExpr | ParArgumentExprs) diff --git a/docs/docs/reference/contextual/instance-defs.md b/docs/docs/reference/contextual/instance-defs.md index d985f31a928f..79fddb295b52 100644 --- a/docs/docs/reference/contextual/instance-defs.md +++ b/docs/docs/reference/contextual/instance-defs.md @@ -67,11 +67,11 @@ Here is the new syntax of implied instance definitions, seen as a delta from the TmplDef ::= ... | ‘implied’ InstanceDef InstanceDef ::= [id] InstanceParams InstanceBody -InstanceParams ::= [DefTypeParamClause] {InferParamClause} -InferParamClause ::= ‘given’ (‘(’ [DefParams] ‘)’ | ContextTypes) +InstanceParams ::= [DefTypeParamClause] {GivenParamClause} +GivenParamClause ::= ‘given’ (‘(’ [DefParams] ‘)’ | GivenTypes) InstanceBody ::= [‘for’ ConstrApp {‘,’ ConstrApp }] [TemplateBody] | ‘for’ Type ‘=’ Expr -ContextTypes ::= RefinedType {‘,’ RefinedType} +GivenTypes ::= AnnotType {‘,’ AnnotType} ``` The identifier `id` can be omitted only if either the `for` part or the template body is present. If the `for` part is missing, the template body must define at least one extension method. diff --git a/tests/pos-special/fatal-warnings/i6290.scala b/tests/pos-special/fatal-warnings/i6290.scala new file mode 100644 index 000000000000..50cabb06ac1e --- /dev/null +++ b/tests/pos-special/fatal-warnings/i6290.scala @@ -0,0 +1,15 @@ +class TC { type T } + +class C given (TC { type T = Int }) + +def f1 given (x: TC) = ??? +def f2 given (@unchecked x: TC) = ??? +inline def f3 given (inline x: TC) = ??? + +class C1 given (x: TC) +class C2 given (@unchecked x: TC) +class C3 given (val x: TC) +class C4 given (var x: TC) +class C5 given (private val x: TC) +class C6 given (private[this] val x: TC) + diff --git a/tests/run/i2567.check b/tests/run/i2567.check new file mode 100644 index 000000000000..3cac4ab61117 --- /dev/null +++ b/tests/run/i2567.check @@ -0,0 +1,6 @@ +hi +hi +hi +hi +hi +hi diff --git a/tests/run/i2567.scala b/tests/run/i2567.scala new file mode 100644 index 000000000000..aef27f2e0cd6 --- /dev/null +++ b/tests/run/i2567.scala @@ -0,0 +1,15 @@ +class TC +implied tc for TC + +class Foo given TC { + println("hi") +} + +object Test extends App { + new Foo + new Foo given tc + new Foo() + new Foo() given tc + Foo() + Foo() given tc +} \ No newline at end of file