From 13a71ef6075cc8acec3c2cb248251170d7203943 Mon Sep 17 00:00:00 2001 From: odersky Date: Mon, 8 Jan 2024 19:34:33 +0100 Subject: [PATCH] Address review comments --- .../tools/dotc/config/MigrationVersion.scala | 14 ++++++-- .../tools/dotc/config/SourceVersion.scala | 3 ++ .../dotty/tools/dotc/typer/Migrations.scala | 32 ++++++++++++------- .../src/dotty/tools/dotc/typer/ReTyper.scala | 1 - .../src/dotty/tools/dotc/typer/Typer.scala | 5 +-- .../context-bounds-migration.scala | 4 +-- 6 files changed, 38 insertions(+), 21 deletions(-) rename tests/{neg => warn}/context-bounds-migration.scala (61%) diff --git a/compiler/src/dotty/tools/dotc/config/MigrationVersion.scala b/compiler/src/dotty/tools/dotc/config/MigrationVersion.scala index d4afc599896c..4dd9d065395b 100644 --- a/compiler/src/dotty/tools/dotc/config/MigrationVersion.scala +++ b/compiler/src/dotty/tools/dotc/config/MigrationVersion.scala @@ -6,10 +6,16 @@ import SourceVersion.* import Feature.* import core.Contexts.Context -class MigrationVersion(val warnFrom: SourceVersion, val errorFrom: SourceVersion): - assert(warnFrom.ordinal <= errorFrom.ordinal) +class MigrationVersion( + val warnFrom: SourceVersion, + val errorFrom: SourceVersion): + require(warnFrom.ordinal <= errorFrom.ordinal) + def needsPatch(using Context): Boolean = - sourceVersion.isMigrating && sourceVersion.isAtLeast(errorFrom) + sourceVersion.isMigrating && sourceVersion.isAtLeast(warnFrom) + + def patchFrom: SourceVersion = + warnFrom.prevMigrating object MigrationVersion: @@ -27,6 +33,8 @@ object MigrationVersion: val AscriptionAfterPattern = MigrationVersion(`3.3`, future) + val ExplicitContextBoundArgument = MigrationVersion(`3.4`, `3.5`) + val AlphanumericInfix = MigrationVersion(`3.4`, future) val RemoveThisQualifier = MigrationVersion(`3.4`, future) val UninitializedVars = MigrationVersion(`3.4`, future) diff --git a/compiler/src/dotty/tools/dotc/config/SourceVersion.scala b/compiler/src/dotty/tools/dotc/config/SourceVersion.scala index 33b946ed173f..7a464d331930 100644 --- a/compiler/src/dotty/tools/dotc/config/SourceVersion.scala +++ b/compiler/src/dotty/tools/dotc/config/SourceVersion.scala @@ -19,6 +19,9 @@ enum SourceVersion: def stable: SourceVersion = if isMigrating then SourceVersion.values(ordinal + 1) else this + def prevMigrating: SourceVersion = + if isMigrating then this else SourceVersion.values(ordinal - 1).prevMigrating + def isAtLeast(v: SourceVersion) = stable.ordinal >= v.ordinal def isAtMost(v: SourceVersion) = stable.ordinal <= v.ordinal diff --git a/compiler/src/dotty/tools/dotc/typer/Migrations.scala b/compiler/src/dotty/tools/dotc/typer/Migrations.scala index 9c038abbd851..84db91f9dee9 100644 --- a/compiler/src/dotty/tools/dotc/typer/Migrations.scala +++ b/compiler/src/dotty/tools/dotc/typer/Migrations.scala @@ -13,7 +13,7 @@ import Symbols.* import Trees.* import ProtoTypes.* import Decorators.* -import config.MigrationVersion +import config.MigrationVersion as mv import config.Feature.{sourceVersion, migrateTo3} import config.SourceVersion.* import reporting.* @@ -30,6 +30,15 @@ trait Migrations: import tpd.* + /** Run `migration`, asserting we are in the proper Typer (not a ReTyper) */ + inline def migrate[T](inline migration: T): T = + assert(!this.isInstanceOf[ReTyper]) + migration + + /** Run `migration`, provided we are in the proper Typer (not a ReTyper) */ + inline def migrate(inline migration: Unit): Unit = + if !this.isInstanceOf[ReTyper] then migration + /** Flag & migrate `?` used as a higher-kinded type parameter * Warning in 3.0-migration, error from 3.0 */ @@ -40,7 +49,7 @@ trait Migrations: else "" val namePos = tree.sourcePos.withSpan(tree.nameSpan) report.errorOrMigrationWarning( - em"`?` is not a valid type name$addendum", namePos, MigrationVersion.Scala2to3) + em"`?` is not a valid type name$addendum", namePos, mv.Scala2to3) def typedAsFunction(tree: untpd.PostfixOp, pt: Type)(using Context): Tree = { val untpd.PostfixOp(qual, Ident(nme.WILDCARD)) = tree: @unchecked @@ -52,8 +61,8 @@ trait Migrations: case _ => val recovered = typed(qual)(using ctx.fresh.setExploreTyperState()) val msg = OnlyFunctionsCanBeFollowedByUnderscore(recovered.tpe.widen, tree) - report.errorOrMigrationWarning(msg, tree.srcPos, MigrationVersion.Scala2to3) - if MigrationVersion.Scala2to3.needsPatch then + report.errorOrMigrationWarning(msg, tree.srcPos, mv.Scala2to3) + if mv.Scala2to3.needsPatch then // Under -rewrite, patch `x _` to `(() => x)` msg.actions .headOption @@ -69,16 +78,16 @@ trait Migrations: case _ => ("(() => ", ")") } + val mversion = mv.FunctionUnderscore def remedy = if ((prefix ++ suffix).isEmpty) "simply leave out the trailing ` _`" else s"use `$prefix$suffix` instead" - def rewrite = Message.rewriteNotice("This construct", `3.4-migration`) + def rewrite = Message.rewriteNotice("This construct", mversion.patchFrom) report.errorOrMigrationWarning( em"""The syntax ` _` is no longer supported; |you can $remedy$rewrite""", - tree.srcPos, - MigrationVersion.FunctionUnderscore) - if MigrationVersion.FunctionUnderscore.needsPatch then + tree.srcPos, mversion) + if mversion.needsPatch then patch(Span(tree.span.start), prefix) patch(Span(qual.span.end, tree.span.end), suffix) @@ -89,6 +98,7 @@ trait Migrations: * Warning in 3.4, error in 3.5, rewrite in 3.5-migration. */ def contextBoundParams(tree: Tree, tp: Type, pt: FunProto)(using Context): Unit = + val mversion = mv.ExplicitContextBoundArgument def isContextBoundParams = tp.stripPoly match case MethodType(ContextBoundParamName(_) :: _) => true case _ => false @@ -96,12 +106,12 @@ trait Migrations: && isContextBoundParams && pt.applyKind != ApplyKind.Using then - def rewriteMsg = Message.rewriteNotice("This code", `3.5-migration`) + def rewriteMsg = Message.rewriteNotice("This code", mversion.patchFrom) report.errorOrMigrationWarning( em"""Context bounds will map to context parameters. |A `using` clause is needed to pass explicit arguments to them.$rewriteMsg""", - tree.srcPos, MigrationVersion(`3.4`, `3.5`)) - if sourceVersion.isAtLeast(`3.5-migration`) then + tree.srcPos, mversion) + if mversion.needsPatch then patch(Span(pt.args.head.span.start), "using ") end contextBoundParams diff --git a/compiler/src/dotty/tools/dotc/typer/ReTyper.scala b/compiler/src/dotty/tools/dotc/typer/ReTyper.scala index 253c4fda9396..e152b5e6b9c7 100644 --- a/compiler/src/dotty/tools/dotc/typer/ReTyper.scala +++ b/compiler/src/dotty/tools/dotc/typer/ReTyper.scala @@ -189,5 +189,4 @@ class ReTyper(nestingLevel: Int = 0) extends Typer(nestingLevel) with ReChecking override protected def checkEqualityEvidence(tree: tpd.Tree, pt: Type)(using Context): Unit = () override protected def matchingApply(methType: MethodOrPoly, pt: FunProto)(using Context): Boolean = true override protected def typedScala2MacroBody(call: untpd.Tree)(using Context): Tree = promote(call) - override protected def migrate[T](migration: => T, disabled: => T = ()): T = disabled } diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 5cb42f659551..1303b64cbd12 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -158,9 +158,6 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer // Overridden in derived typers def newLikeThis(nestingLevel: Int): Typer = new Typer(nestingLevel) - // Overridden to do nothing in derived typers - protected def migrate[T](migration: => T, disabled: => T = ()): T = migration - /** Find the type of an identifier with given `name` in given context `ctx`. * @param name the name of the identifier * @param pt the expected type @@ -2982,7 +2979,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer } override def typedAsFunction(tree: untpd.PostfixOp, pt: Type)(using Context): Tree = - migrate(super.typedAsFunction(tree, pt), throw new AssertionError("can't retype a PostfixOp")) + migrate(super.typedAsFunction(tree, pt)) /** Translate infix operation expression `l op r` to * diff --git a/tests/neg/context-bounds-migration.scala b/tests/warn/context-bounds-migration.scala similarity index 61% rename from tests/neg/context-bounds-migration.scala rename to tests/warn/context-bounds-migration.scala index b27dc884692c..1094db68f41b 100644 --- a/tests/neg/context-bounds-migration.scala +++ b/tests/warn/context-bounds-migration.scala @@ -1,4 +1,4 @@ -//> using options -Xfatal-warnings +//> using options -source 3.4 class C[T] def foo[X: C] = () @@ -6,5 +6,5 @@ def foo[X: C] = () given [T]: C[T] = C[T]() def Test = - foo(C[Int]()) // error + foo(C[Int]()) // warn foo(using C[Int]()) // ok