Skip to content

Commit ebbd685

Browse files
authored
Implement SIP 64 as non-experimental (#21668)
For the new syntax of givens and context bounds, see the diffs in reference/syntax.md.
2 parents 49d39d9 + df75afc commit ebbd685

File tree

297 files changed

+1352
-1182
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

297 files changed

+1352
-1182
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -1261,7 +1261,7 @@ object desugar {
12611261
str.toTermName.asSimpleName
12621262

12631263
/** Extract a synthesized given name from a type tree. This is used for
1264-
* both anonymous givens and (under x.modularity) deferred givens.
1264+
* both anonymous givens and deferred givens.
12651265
* @param followArgs if true include argument types in the name
12661266
*/
12671267
private class NameExtractor(followArgs: Boolean) extends UntypedTreeAccumulator[String] {

compiler/src/dotty/tools/dotc/ast/untpd.scala

-1
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
119119
case class PatDef(mods: Modifiers, pats: List[Tree], tpt: Tree, rhs: Tree)(implicit @constructorOnly src: SourceFile) extends DefTree
120120
case class ExtMethods(paramss: List[ParamClause], methods: List[Tree])(implicit @constructorOnly src: SourceFile) extends Tree
121121
case class ContextBoundTypeTree(tycon: Tree, paramName: TypeName, ownName: TermName)(implicit @constructorOnly src: SourceFile) extends Tree
122-
// `paramName: tycon as ownName`, ownName != EmptyTermName only under x.modularity
123122
case class MacroTree(expr: Tree)(implicit @constructorOnly src: SourceFile) extends Tree
124123

125124
case class ImportSelector(imported: Ident, renamed: Tree = EmptyTree, bound: Tree = EmptyTree)(implicit @constructorOnly src: SourceFile) extends Tree {

compiler/src/dotty/tools/dotc/config/MigrationVersion.scala

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ enum MigrationVersion(val warnFrom: SourceVersion, val errorFrom: SourceVersion)
3030
case ImportRename extends MigrationVersion(future, future)
3131
case ParameterEnclosedByParenthesis extends MigrationVersion(future, future)
3232
case XmlLiteral extends MigrationVersion(future, future)
33+
case GivenSyntax extends MigrationVersion(future, never)
3334

3435
require(warnFrom.ordinal <= errorFrom.ordinal)
3536

compiler/src/dotty/tools/dotc/config/SourceVersion.scala

+3-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ enum SourceVersion:
1616
// !!! Keep in sync with scala.runtime.stdlibPatches.language !!!
1717
case `future-migration`, `future`
1818

19+
case `never` // needed for MigrationVersion.errorFrom if we never want to issue an error
20+
1921
val isMigrating: Boolean = toString.endsWith("-migration")
2022

2123
def stable: SourceVersion =
@@ -32,7 +34,7 @@ object SourceVersion extends Property.Key[SourceVersion]:
3234
def defaultSourceVersion = `3.6`
3335

3436
/** language versions that may appear in a language import, are deprecated, but not removed from the standard library. */
35-
val illegalSourceVersionNames = List("3.1-migration").map(_.toTermName)
37+
val illegalSourceVersionNames = List("3.1-migration", "never").map(_.toTermName)
3638

3739
/** language versions that the compiler recognises. */
3840
val validSourceVersionNames = values.toList.map(_.toString.toTermName)

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

+28-12
Original file line numberDiff line numberDiff line change
@@ -994,8 +994,8 @@ object Parsers {
994994
skipParams()
995995
lookahead.isColon
996996
&& {
997-
!in.featureEnabled(Feature.modularity)
998-
|| { // with modularity language import, a `:` at EOL after an identifier represents a single identifier given
997+
!sourceVersion.isAtLeast(`3.6`)
998+
|| { // in the new given syntax, a `:` at EOL after an identifier represents a single identifier given
999999
// Example:
10001000
// given C:
10011001
// def f = ...
@@ -1833,7 +1833,7 @@ object Parsers {
18331833
infixOps(t, canStartInfixTypeTokens, operand, Location.ElseWhere, ParseKind.Type,
18341834
isOperator = !followingIsVararg()
18351835
&& !isPureArrow
1836-
&& !(isIdent(nme.as) && in.featureEnabled(Feature.modularity))
1836+
&& !(isIdent(nme.as) && sourceVersion.isAtLeast(`3.6`))
18371837
&& nextCanFollowOperator(canStartInfixTypeTokens))
18381838

18391839
/** RefinedType ::= WithType {[nl] Refinement} [`^` CaptureSet]
@@ -2226,20 +2226,30 @@ object Parsers {
22262226
def contextBound(pname: TypeName): Tree =
22272227
val t = toplevelTyp()
22282228
val ownName =
2229-
if isIdent(nme.as) && in.featureEnabled(Feature.modularity) then
2229+
if isIdent(nme.as) && sourceVersion.isAtLeast(`3.6`) then
22302230
in.nextToken()
22312231
ident()
22322232
else EmptyTermName
22332233
ContextBoundTypeTree(t, pname, ownName)
22342234

2235-
/** ContextBounds ::= ContextBound | `{` ContextBound {`,` ContextBound} `}`
2235+
/** ContextBounds ::= ContextBound [`:` ContextBounds]
2236+
* | `{` ContextBound {`,` ContextBound} `}`
22362237
*/
22372238
def contextBounds(pname: TypeName): List[Tree] =
22382239
if in.isColon then
22392240
in.nextToken()
2240-
if in.token == LBRACE && in.featureEnabled(Feature.modularity)
2241+
if in.token == LBRACE && sourceVersion.isAtLeast(`3.6`)
22412242
then inBraces(commaSeparated(() => contextBound(pname)))
2242-
else contextBound(pname) :: contextBounds(pname)
2243+
else
2244+
val bound = contextBound(pname)
2245+
val rest =
2246+
if in.isColon then
2247+
report.errorOrMigrationWarning(
2248+
em"Multiple context bounds should be enclosed in `{ ... }`",
2249+
in.sourcePos(), MigrationVersion.GivenSyntax)
2250+
contextBounds(pname)
2251+
else Nil
2252+
bound :: rest
22432253
else if in.token == VIEWBOUND then
22442254
report.errorOrMigrationWarning(
22452255
em"view bounds `<%' are no longer supported, use a context bound `:' instead",
@@ -4014,7 +4024,7 @@ object Parsers {
40144024
case SEMI | NEWLINE | NEWLINES | COMMA | RBRACE | OUTDENT | EOF =>
40154025
makeTypeDef(typeAndCtxBounds(tname))
40164026
case _ if (staged & StageKind.QuotedPattern) != 0
4017-
|| in.featureEnabled(Feature.modularity) && in.isColon =>
4027+
|| sourceVersion.isAtLeast(`3.6`) && in.isColon =>
40184028
makeTypeDef(typeAndCtxBounds(tname))
40194029
case _ =>
40204030
syntaxErrorOrIncomplete(ExpectedTypeBoundOrEquals(in.token))
@@ -4189,7 +4199,7 @@ object Parsers {
41894199
def givenDef(start: Offset, mods: Modifiers, givenMod: Mod) = atSpan(start, nameStart) {
41904200
var mods1 = addMod(mods, givenMod)
41914201
val nameStart = in.offset
4192-
var newSyntaxAllowed = in.featureEnabled(Feature.modularity)
4202+
var newSyntaxAllowed = sourceVersion.isAtLeast(`3.6`)
41934203
val hasEmbeddedColon = !in.isColon && followingIsGivenDefWithColon()
41944204
val name = if isIdent && hasEmbeddedColon then ident() else EmptyTermName
41954205

@@ -4260,6 +4270,9 @@ object Parsers {
42604270
in.nextToken()
42614271
newSignature()
42624272
else if hasEmbeddedColon then
4273+
report.errorOrMigrationWarning(
4274+
em"This old given syntax is no longer supported; use `=>` instead of `:`",
4275+
in.sourcePos(), MigrationVersion.GivenSyntax)
42634276
newSyntaxAllowed = false
42644277
val tparamsOld = typeParamClauseOpt(ParamOwner.Given)
42654278
newLineOpt()
@@ -4294,10 +4307,10 @@ object Parsers {
42944307
if name.isEmpty then
42954308
syntaxError(em"Anonymous given cannot be abstract, or maybe you want to define a concrete given and are missing a `()` argument?", in.lastOffset)
42964309
if newSyntaxAllowed then
4297-
warning(
4298-
em"""This defines an abstract given, which is deprecated. Use a `deferred` given instead.
4310+
report.errorOrMigrationWarning(
4311+
em"""This defines an abstract given, which is no longer supported. Use a `deferred` given instead.
42994312
|Or, if you intend to define a concrete given, follow the type with `()` arguments.""",
4300-
in.lastOffset)
4313+
in.sourcePos(in.lastOffset), MigrationVersion.GivenSyntax)
43014314
DefDef(name, adjustDefParams(joinParams(tparams, vparamss)), parents.head, EmptyTree)
43024315
else
43034316
// structural instance
@@ -4487,6 +4500,9 @@ object Parsers {
44874500

44884501
/** with Template, with EOL <indent> interpreted */
44894502
def withTemplate(constr: DefDef, parents: List[Tree]): Template =
4503+
report.errorOrMigrationWarning(
4504+
em"Given member definitions starting with `with` are no longer supported; use `{...}` or `:` followed by newline instead",
4505+
in.sourcePos(), MigrationVersion.GivenSyntax)
44904506
accept(WITH)
44914507
val (self, stats) = templateBody(parents, rewriteWithColon = false)
44924508
Template(constr, parents, Nil, self, stats)

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

+3-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import TypeApplications.*
2424
import NameKinds.{WildcardParamName, DefaultGetterName}
2525
import util.Chars.isOperatorPart
2626
import config.{Config, Feature}
27+
import config.Feature.sourceVersion
28+
import config.SourceVersion.*
2729

2830
import dotty.tools.dotc.util.SourcePosition
2931
import dotty.tools.dotc.ast.untpd.{MemberDef, Modifiers, PackageDef, RefTree, Template, TypeDef, ValOrDefDef}
@@ -751,7 +753,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
751753
case GenAlias(pat, expr) =>
752754
toText(pat) ~ " = " ~ toText(expr)
753755
case ContextBounds(bounds, cxBounds) =>
754-
if Feature.enabled(Feature.modularity) then
756+
if sourceVersion.isAtLeast(`3.6`) then
755757
def boundsText(bounds: Tree) = bounds match
756758
case ContextBoundTypeTree(tpt, _, ownName) =>
757759
toText(tpt) ~ (" as " ~ toText(ownName) `provided` !ownName.isEmpty)

docs/_docs/internals/syntax.md

+8-2
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,9 @@ TypeArgs ::= ‘[’ Types ‘]’
223223
Refinement ::= :<<< [RefineDcl] {semi [RefineDcl]} >>> ds
224224
TypeBounds ::= [‘>:’ Type] [‘<:’ Type] TypeBoundsTree(lo, hi)
225225
TypeAndCtxBounds ::= TypeBounds [‘:’ ContextBounds] ContextBounds(typeBounds, tps)
226-
ContextBounds ::= ContextBound | '{' ContextBound {',' ContextBound} '}'
226+
ContextBounds ::= ContextBound
227+
| ContextBound `:` ContextBounds -- to be deprecated
228+
| '{' ContextBound {',' ContextBound} '}'
227229
ContextBound ::= Type ['as' id]
228230
Types ::= Type {‘,’ Type}
229231
NamesAndTypes ::= NameAndType {‘,’ NameAndType}
@@ -464,7 +466,7 @@ TypeDef ::= id [HkTypeParamClause] {FunParamClause} TypeAndCtxBounds
464466
TmplDef ::= ([‘case’] ‘class’ | ‘trait’) ClassDef
465467
| [‘case’] ‘object’ ObjectDef
466468
| ‘enum’ EnumDef
467-
| ‘given’ GivenDef
469+
| ‘given’ (GivenDef | OldGivenDef)
468470
ClassDef ::= id ClassConstr [Template] ClassDef(mods, name, tparams, templ)
469471
ClassConstr ::= [ClsTypeParamClause] [ConstrMods] ClsParamClauses with DefDef(_, <init>, Nil, vparamss, EmptyTree, EmptyTree) as first stat
470472
ConstrMods ::= {Annotation} [AccessModifier]
@@ -483,6 +485,10 @@ GivenConditional ::= DefTypeParamClause
483485
| GivenType
484486
GivenType ::= AnnotType1 {id [nl] AnnotType1}
485487
488+
OldGivenDef ::= [OldGivenSig] (AnnotType [‘=’ Expr] | StructuralInstance) -- syntax up to Scala 3.5, to be deprecated in the future
489+
OldGivenSig ::= [id] [DefTypeParamClause] {UsingParamClause} ‘:’ -- one of `id`, `DefTypeParamClause`, `UsingParamClause` must be present
490+
StructuralInstance ::= ConstrApp {‘with’ ConstrApp} [‘with’ WithTemplateBody]
491+
486492
Extension ::= ‘extension’ [DefTypeParamClause] {UsingParamClause}
487493
‘(’ DefTermParam ‘)’ {UsingParamClause} ExtMethods
488494
ExtMethods ::= ExtMethod | [nl] <<< ExtMethod {semi ExtMethod} >>>

docs/_docs/reference/contextual/by-name-context-parameters.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ trait Codec[T]:
1212

1313
given intCodec: Codec[Int] = ???
1414

15-
given optionCodec[T](using ev: => Codec[T]): Codec[Option[T]] with
15+
given optionCodec: [T] => (ev: => Codec[T]) => Codec[Option[T]]:
1616
def write(xo: Option[T]) = xo match
1717
case Some(x) => ev.write(x)
1818
case None =>

0 commit comments

Comments
 (0)