Skip to content
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

Implement SIP 64 as non-experimental #21668

Merged
merged 9 commits into from
Oct 4, 2024
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 @@ -1261,7 +1261,7 @@ object desugar {
str.toTermName.asSimpleName

/** Extract a synthesized given name from a type tree. This is used for
* both anonymous givens and (under x.modularity) deferred givens.
* both anonymous givens and deferred givens.
* @param followArgs if true include argument types in the name
*/
private class NameExtractor(followArgs: Boolean) extends UntypedTreeAccumulator[String] {
Expand Down
1 change: 0 additions & 1 deletion compiler/src/dotty/tools/dotc/ast/untpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
case class PatDef(mods: Modifiers, pats: List[Tree], tpt: Tree, rhs: Tree)(implicit @constructorOnly src: SourceFile) extends DefTree
case class ExtMethods(paramss: List[ParamClause], methods: List[Tree])(implicit @constructorOnly src: SourceFile) extends Tree
case class ContextBoundTypeTree(tycon: Tree, paramName: TypeName, ownName: TermName)(implicit @constructorOnly src: SourceFile) extends Tree
// `paramName: tycon as ownName`, ownName != EmptyTermName only under x.modularity
case class MacroTree(expr: Tree)(implicit @constructorOnly src: SourceFile) extends Tree

case class ImportSelector(imported: Ident, renamed: Tree = EmptyTree, bound: Tree = EmptyTree)(implicit @constructorOnly src: SourceFile) extends Tree {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ enum MigrationVersion(val warnFrom: SourceVersion, val errorFrom: SourceVersion)
case ImportRename extends MigrationVersion(future, future)
case ParameterEnclosedByParenthesis extends MigrationVersion(future, future)
case XmlLiteral extends MigrationVersion(future, future)
case GivenSyntax extends MigrationVersion(future, never)

require(warnFrom.ordinal <= errorFrom.ordinal)

Expand Down
4 changes: 3 additions & 1 deletion compiler/src/dotty/tools/dotc/config/SourceVersion.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ enum SourceVersion:
// !!! Keep in sync with scala.runtime.stdlibPatches.language !!!
case `future-migration`, `future`

case `never` // needed for MigrationVersion.errorFrom if we never want to issue an error
bishabosha marked this conversation as resolved.
Show resolved Hide resolved

val isMigrating: Boolean = toString.endsWith("-migration")

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

/** language versions that may appear in a language import, are deprecated, but not removed from the standard library. */
val illegalSourceVersionNames = List("3.1-migration").map(_.toTermName)
val illegalSourceVersionNames = List("3.1-migration", "never").map(_.toTermName)
odersky marked this conversation as resolved.
Show resolved Hide resolved

/** language versions that the compiler recognises. */
val validSourceVersionNames = values.toList.map(_.toString.toTermName)
Expand Down
40 changes: 28 additions & 12 deletions compiler/src/dotty/tools/dotc/parsing/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -994,8 +994,8 @@ object Parsers {
skipParams()
lookahead.isColon
&& {
!in.featureEnabled(Feature.modularity)
|| { // with modularity language import, a `:` at EOL after an identifier represents a single identifier given
!sourceVersion.isAtLeast(`3.6`)
|| { // in the new given syntax, a `:` at EOL after an identifier represents a single identifier given
// Example:
// given C:
// def f = ...
Expand Down Expand Up @@ -1833,7 +1833,7 @@ object Parsers {
infixOps(t, canStartInfixTypeTokens, operand, Location.ElseWhere, ParseKind.Type,
isOperator = !followingIsVararg()
&& !isPureArrow
&& !(isIdent(nme.as) && in.featureEnabled(Feature.modularity))
&& !(isIdent(nme.as) && sourceVersion.isAtLeast(`3.6`))
&& nextCanFollowOperator(canStartInfixTypeTokens))

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

/** ContextBounds ::= ContextBound | `{` ContextBound {`,` ContextBound} `}`
/** ContextBounds ::= ContextBound [`:` ContextBounds]
* | `{` ContextBound {`,` ContextBound} `}`
*/
def contextBounds(pname: TypeName): List[Tree] =
if in.isColon then
in.nextToken()
if in.token == LBRACE && in.featureEnabled(Feature.modularity)
if in.token == LBRACE && sourceVersion.isAtLeast(`3.6`)
then inBraces(commaSeparated(() => contextBound(pname)))
else contextBound(pname) :: contextBounds(pname)
else
val bound = contextBound(pname)
val rest =
if in.isColon then
report.errorOrMigrationWarning(
em"Multiple context bounds should be enclosed in `{ ... }`",
in.sourcePos(), MigrationVersion.GivenSyntax)
contextBounds(pname)
else Nil
bound :: rest
else if in.token == VIEWBOUND then
report.errorOrMigrationWarning(
em"view bounds `<%' are no longer supported, use a context bound `:' instead",
Expand Down Expand Up @@ -4014,7 +4024,7 @@ object Parsers {
case SEMI | NEWLINE | NEWLINES | COMMA | RBRACE | OUTDENT | EOF =>
makeTypeDef(typeAndCtxBounds(tname))
case _ if (staged & StageKind.QuotedPattern) != 0
|| in.featureEnabled(Feature.modularity) && in.isColon =>
|| sourceVersion.isAtLeast(`3.6`) && in.isColon =>
makeTypeDef(typeAndCtxBounds(tname))
case _ =>
syntaxErrorOrIncomplete(ExpectedTypeBoundOrEquals(in.token))
Expand Down Expand Up @@ -4189,7 +4199,7 @@ object Parsers {
def givenDef(start: Offset, mods: Modifiers, givenMod: Mod) = atSpan(start, nameStart) {
var mods1 = addMod(mods, givenMod)
val nameStart = in.offset
var newSyntaxAllowed = in.featureEnabled(Feature.modularity)
var newSyntaxAllowed = sourceVersion.isAtLeast(`3.6`)
val hasEmbeddedColon = !in.isColon && followingIsGivenDefWithColon()
val name = if isIdent && hasEmbeddedColon then ident() else EmptyTermName

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

/** with Template, with EOL <indent> interpreted */
def withTemplate(constr: DefDef, parents: List[Tree]): Template =
report.errorOrMigrationWarning(
em"Given member definitions starting with `with` are no longer supported; use `{...}` or `:` followed by newline instead",
in.sourcePos(), MigrationVersion.GivenSyntax)
accept(WITH)
val (self, stats) = templateBody(parents, rewriteWithColon = false)
Template(constr, parents, Nil, self, stats)
Expand Down
4 changes: 3 additions & 1 deletion compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import TypeApplications.*
import NameKinds.{WildcardParamName, DefaultGetterName}
import util.Chars.isOperatorPart
import config.{Config, Feature}
import config.Feature.sourceVersion
import config.SourceVersion.*

import dotty.tools.dotc.util.SourcePosition
import dotty.tools.dotc.ast.untpd.{MemberDef, Modifiers, PackageDef, RefTree, Template, TypeDef, ValOrDefDef}
Expand Down Expand Up @@ -751,7 +753,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
case GenAlias(pat, expr) =>
toText(pat) ~ " = " ~ toText(expr)
case ContextBounds(bounds, cxBounds) =>
if Feature.enabled(Feature.modularity) then
if sourceVersion.isAtLeast(`3.6`) then
def boundsText(bounds: Tree) = bounds match
case ContextBoundTypeTree(tpt, _, ownName) =>
toText(tpt) ~ (" as " ~ toText(ownName) `provided` !ownName.isEmpty)
Expand Down
10 changes: 8 additions & 2 deletions docs/_docs/internals/syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,9 @@ TypeArgs ::= ‘[’ Types ‘]’
Refinement ::= :<<< [RefineDcl] {semi [RefineDcl]} >>> ds
TypeBounds ::= [‘>:’ Type] [‘<:’ Type] TypeBoundsTree(lo, hi)
TypeAndCtxBounds ::= TypeBounds [‘:’ ContextBounds] ContextBounds(typeBounds, tps)
ContextBounds ::= ContextBound | '{' ContextBound {',' ContextBound} '}'
ContextBounds ::= ContextBound
| ContextBound `:` ContextBounds -- to be deprecated
| '{' ContextBound {',' ContextBound} '}'
ContextBound ::= Type ['as' id]
Types ::= Type {‘,’ Type}
NamesAndTypes ::= NameAndType {‘,’ NameAndType}
Expand Down Expand Up @@ -464,7 +466,7 @@ TypeDef ::= id [HkTypeParamClause] {FunParamClause} TypeAndCtxBounds
TmplDef ::= ([‘case’] ‘class’ | ‘trait’) ClassDef
| [‘case’] ‘object’ ObjectDef
| ‘enum’ EnumDef
| ‘given’ GivenDef
| ‘given’ (GivenDef | OldGivenDef)
ClassDef ::= id ClassConstr [Template] ClassDef(mods, name, tparams, templ)
ClassConstr ::= [ClsTypeParamClause] [ConstrMods] ClsParamClauses with DefDef(_, <init>, Nil, vparamss, EmptyTree, EmptyTree) as first stat
ConstrMods ::= {Annotation} [AccessModifier]
Expand All @@ -483,6 +485,10 @@ GivenConditional ::= DefTypeParamClause
| GivenType
GivenType ::= AnnotType1 {id [nl] AnnotType1}

OldGivenDef ::= [OldGivenSig] (AnnotType [‘=’ Expr] | StructuralInstance) -- syntax up to Scala 3.5, to be deprecated in the future
OldGivenSig ::= [id] [DefTypeParamClause] {UsingParamClause} ‘:’ -- one of `id`, `DefTypeParamClause`, `UsingParamClause` must be present
StructuralInstance ::= ConstrApp {‘with’ ConstrApp} [‘with’ WithTemplateBody]

Extension ::= ‘extension’ [DefTypeParamClause] {UsingParamClause}
‘(’ DefTermParam ‘)’ {UsingParamClause} ExtMethods
ExtMethods ::= ExtMethod | [nl] <<< ExtMethod {semi ExtMethod} >>>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ trait Codec[T]:

given intCodec: Codec[Int] = ???

given optionCodec[T](using ev: => Codec[T]): Codec[Option[T]] with
given optionCodec: [T] => (ev: => Codec[T]) => Codec[Option[T]]:
def write(xo: Option[T]) = xo match
case Some(x) => ev.write(x)
case None =>
Expand Down
Loading
Loading