From 14acdc06067a202f381fa9066a961cebb1314d6a Mon Sep 17 00:00:00 2001 From: odersky Date: Sat, 28 Sep 2024 14:58:05 +0200 Subject: [PATCH] Implement SIP 64 as non-experimental --- .../src/dotty/tools/dotc/ast/Desugar.scala | 2 +- compiler/src/dotty/tools/dotc/ast/untpd.scala | 1 - .../dotty/tools/dotc/parsing/Parsers.scala | 20 ++++++-------- .../tools/dotc/printing/RefinedPrinter.scala | 4 ++- docs/_docs/internals/syntax.md | 10 +++++-- docs/_docs/reference/syntax.md | 27 +++++++++++++++---- library/src/scala/compiletime/package.scala | 1 - .../AutoImplementAbstractMembersSuite.scala | 4 ++- tests/neg/empty-given.scala | 4 +-- tests/neg/i12348.check | 6 ++--- .../stdlibExperimentalDefinitions.scala | 1 - tests/warn/abstract-givens-new.check | 6 +---- tests/warn/abstract-givens-new.scala | 3 ++- 13 files changed, 53 insertions(+), 36 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index 5c468721fd43..e1a6b97fc7d3 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -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] { diff --git a/compiler/src/dotty/tools/dotc/ast/untpd.scala b/compiler/src/dotty/tools/dotc/ast/untpd.scala index 60309d4d83bd..935e42d5e05c 100644 --- a/compiler/src/dotty/tools/dotc/ast/untpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/untpd.scala @@ -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 { diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 8a173faa3cec..5af9b105a5c1 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -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 = ... @@ -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] @@ -2226,18 +2226,19 @@ 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 if in.token == VIEWBOUND then @@ -4189,7 +4190,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 @@ -4293,11 +4294,6 @@ object Parsers { // old-style abstract given 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. - |Or, if you intend to define a concrete given, follow the type with `()` arguments.""", - in.lastOffset) DefDef(name, adjustDefParams(joinParams(tparams, vparamss)), parents.head, EmptyTree) else // structural instance diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index ea729e9549d5..b229c7ec29d9 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -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} @@ -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) diff --git a/docs/_docs/internals/syntax.md b/docs/_docs/internals/syntax.md index f82e9c998b4d..0cde7bc127aa 100644 --- a/docs/_docs/internals/syntax.md +++ b/docs/_docs/internals/syntax.md @@ -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} @@ -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(_, , Nil, vparamss, EmptyTree, EmptyTree) as first stat ConstrMods ::= {Annotation} [AccessModifier] @@ -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} >>> diff --git a/docs/_docs/reference/syntax.md b/docs/_docs/reference/syntax.md index 5d984c762a89..adf25c9342fa 100644 --- a/docs/_docs/reference/syntax.md +++ b/docs/_docs/reference/syntax.md @@ -214,7 +214,11 @@ ParamValueType ::= Type [‘*’] TypeArgs ::= ‘[’ Types ‘]’ Refinement ::= :<<< [RefineDcl] {semi [RefineDcl]} >>> TypeBounds ::= [‘>:’ Type] [‘<:’ Type] -TypeAndCtxBounds ::= TypeBounds {‘:’ Type} +TypeAndCtxBounds ::= TypeBounds [‘:’ ContextBounds] +ContextBounds ::= ContextBound + | ContextBound `:` ContextBounds -- to be deprecated + | '{' ContextBound {',' ContextBound} '}' +ContextBound ::= Type ['as' id] Types ::= Type {‘,’ Type} ``` @@ -437,16 +441,29 @@ TypeDef ::= id [HkTypeParamClause] {FunParamClause}TypeBounds TmplDef ::= ([‘case’] ‘class’ | ‘trait’) ClassDef | [‘case’] ‘object’ ObjectDef | ‘enum’ EnumDef - | ‘given’ GivenDef + | ‘given’ (GivenDef | OldGivenDef) ClassDef ::= id ClassConstr [Template] ClassConstr ::= [ClsTypeParamClause] [ConstrMods] ClsParamClauses ConstrMods ::= {Annotation} [AccessModifier] ObjectDef ::= id [Template] EnumDef ::= id ClassConstr InheritClauses EnumBody -GivenDef ::= [GivenSig] (AnnotType [‘=’ Expr] | StructuralInstance) -GivenSig ::= [id] [DefTypeParamClause] {UsingParamClause} ‘:’ -- one of `id`, `DefTypeParamClause`, `UsingParamClause` must be present -GivenType ::= AnnotType {id [nl] AnnotType} + +GivenDef ::= [id ':'] GivenSig +GivenSig ::= GivenImpl + | '(' ')' '=>' GivenImpl + | GivenConditional '=>' GivenSig +GivenImpl ::= GivenType ([‘=’ Expr] | TemplateBody) + | ConstrApps TemplateBody +GivenConditional ::= DefTypeParamClause + | DefTermParamClause + | '(' FunArgTypes ')' + | 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} >>> diff --git a/library/src/scala/compiletime/package.scala b/library/src/scala/compiletime/package.scala index a3896a1eeb06..8215ae2452a3 100644 --- a/library/src/scala/compiletime/package.scala +++ b/library/src/scala/compiletime/package.scala @@ -52,7 +52,6 @@ def uninitialized: Nothing = ??? * that implement the enclosing trait and that do not contain an explicit overriding * definition of that given. */ -@experimental @compileTimeOnly("`deferred` can only be used as the right hand side of a given definition in a trait") def deferred: Nothing = ??? diff --git a/presentation-compiler/test/dotty/tools/pc/tests/edit/AutoImplementAbstractMembersSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/edit/AutoImplementAbstractMembersSuite.scala index ffe4e293ba30..2df69cc85af2 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/edit/AutoImplementAbstractMembersSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/edit/AutoImplementAbstractMembersSuite.scala @@ -1089,11 +1089,13 @@ class AutoImplementAbstractMembersSuite extends BaseCodeActionSuite: | def foo(x: Int): Int | def bar(x: String): String | - |given Foo with + |given Foo { | | override def foo(x: Int): Int = ??? | | override def bar(x: String): String = ??? + | + |} |""".stripMargin ) diff --git a/tests/neg/empty-given.scala b/tests/neg/empty-given.scala index 10daf5ac009a..cf7566724cc2 100644 --- a/tests/neg/empty-given.scala +++ b/tests/neg/empty-given.scala @@ -1,3 +1,3 @@ -given { // error +given { def foo = 1 // error -} // error \ No newline at end of file +} \ No newline at end of file diff --git a/tests/neg/i12348.check b/tests/neg/i12348.check index 55806fa5ca1b..8d0a24a60308 100644 --- a/tests/neg/i12348.check +++ b/tests/neg/i12348.check @@ -1,4 +1,4 @@ --- [E040] Syntax Error: tests/neg/i12348.scala:2:15 -------------------------------------------------------------------- +-- [E040] Syntax Error: tests/neg/i12348.scala:2:16 -------------------------------------------------------------------- 2 | given inline x: Int = 0 // error - | ^ - | 'with' expected, but identifier found + | ^ + | an identifier expected, but ':' found diff --git a/tests/run-tasty-inspector/stdlibExperimentalDefinitions.scala b/tests/run-tasty-inspector/stdlibExperimentalDefinitions.scala index 15ccd38f860c..e28c2240a414 100644 --- a/tests/run-tasty-inspector/stdlibExperimentalDefinitions.scala +++ b/tests/run-tasty-inspector/stdlibExperimentalDefinitions.scala @@ -83,7 +83,6 @@ val experimentalDefinitionInLibrary = Set( // New feature: modularity "scala.Precise", "scala.annotation.internal.WitnessNames", - "scala.compiletime.package$package$.deferred", "scala.runtime.stdLibPatches.Predef$.is", // New feature: functions with erased parameters. diff --git a/tests/warn/abstract-givens-new.check b/tests/warn/abstract-givens-new.check index 197d9bcb4f3e..8b137891791f 100644 --- a/tests/warn/abstract-givens-new.check +++ b/tests/warn/abstract-givens-new.check @@ -1,5 +1 @@ --- Warning: tests/warn/abstract-givens-new.scala:7:22 ------------------------------------------------------------------ -7 | given intC: Int is C // warn - | ^ - | This defines an abstract given, which is deprecated. Use a `deferred` given instead. - | Or, if you intend to define a concrete given, follow the type with `()` arguments. + diff --git a/tests/warn/abstract-givens-new.scala b/tests/warn/abstract-givens-new.scala index b38fd11c4458..2ecf700f18f7 100644 --- a/tests/warn/abstract-givens-new.scala +++ b/tests/warn/abstract-givens-new.scala @@ -4,6 +4,7 @@ class C: trait T: given Int is C // ok - given intC: Int is C // warn + given intC: Int is C // ok for now, will be warning given intC2: (Int is C)() // ok given intC3: Int is C {} // also ok +