Skip to content

Disallow refinements in GivenTypes #6290

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Apr 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/ast/Desugar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
26 changes: 19 additions & 7 deletions compiler/src/dotty/tools/dotc/parsing/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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(
Expand All @@ -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))
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions compiler/src/dotty/tools/dotc/parsing/Tokens.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
3 changes: 3 additions & 0 deletions compiler/test/dotc/run-from-tasty.blacklist
Original file line number Diff line number Diff line change
Expand Up @@ -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
11 changes: 5 additions & 6 deletions docs/docs/internals/syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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’}
```

Expand Down Expand Up @@ -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)
Expand All @@ -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}
Expand Down
11 changes: 5 additions & 6 deletions docs/docs/reference/contextual/inferable-params.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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)
Expand Down
6 changes: 3 additions & 3 deletions docs/docs/reference/contextual/instance-defs.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
15 changes: 15 additions & 0 deletions tests/pos-special/fatal-warnings/i6290.scala
Original file line number Diff line number Diff line change
@@ -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)

6 changes: 6 additions & 0 deletions tests/run/i2567.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
hi
hi
hi
hi
hi
hi
15 changes: 15 additions & 0 deletions tests/run/i2567.scala
Original file line number Diff line number Diff line change
@@ -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
}