From 7e26ac39e331eced36ea55989f198edb5dfdb82c Mon Sep 17 00:00:00 2001 From: Olivier Blanvillain Date: Thu, 7 Mar 2019 14:40:39 +0100 Subject: [PATCH 1/3] Remove view bounds :fire: --- compiler/src/dotty/tools/dotc/parsing/Parsers.scala | 5 ++++- compiler/src/dotty/tools/dotc/parsing/Tokens.scala | 4 ++-- docs/docs/internals/syntax.md | 2 +- tests/{pos => pos-scala2}/spec-doubledef-old.scala | 0 tests/{pos => pos-scala2}/t3688.scala | 0 5 files changed, 7 insertions(+), 4 deletions(-) rename tests/{pos => pos-scala2}/spec-doubledef-old.scala (100%) rename tests/{pos => pos-scala2}/t3688.scala (100%) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 93a3a1e9c9d5..a20298d0a68e 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -296,6 +296,9 @@ object Parsers { def deprecationWarning(msg: => Message, offset: Int = in.offset): Unit = ctx.deprecationWarning(msg, source.atSpan(Span(offset))) + def errorOrMigrationWarning(msg: => Message, offset: Int = in.offset): Unit = + ctx.errorOrMigrationWarning(msg, source.atSpan(Span(offset))) + /** Issue an error at current offset that input is incomplete */ def incompleteInputError(msg: => Message): Unit = ctx.incompleteInputError(msg, source.atSpan(Span(in.offset))) @@ -1135,7 +1138,7 @@ object Parsers { AppliedTypeTree(toplevelTyp(), Ident(pname)) } :: contextBounds(pname) case VIEWBOUND => - deprecationWarning("view bounds `<%' are deprecated, use a context bound `:' instead") + errorOrMigrationWarning("view bounds `<%' are deprecated, use a context bound `:' instead") atSpan(in.skipToken()) { Function(Ident(pname) :: Nil, toplevelTyp()) } :: contextBounds(pname) diff --git a/compiler/src/dotty/tools/dotc/parsing/Tokens.scala b/compiler/src/dotty/tools/dotc/parsing/Tokens.scala index 936663eb9b14..3bebe4a6f6cd 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Tokens.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Tokens.scala @@ -112,7 +112,7 @@ abstract class TokensCommon { //final val SUPERTYPE = 81; enter(SUPERTYPE, ">:") //final val HASH = 82; enter(HASH, "#") final val AT = 83; enter(AT, "@") - //final val VIEWBOUND = 84; enter(VIEWBOUND, "<%") // TODO: deprecate + //final val VIEWBOUND = 84; enter(VIEWBOUND, "<%") val keywords: TokenSet @@ -193,7 +193,7 @@ object Tokens extends TokensCommon { final val SUBTYPE = 80; enter(SUBTYPE, "<:") final val SUPERTYPE = 81; enter(SUPERTYPE, ">:") final val HASH = 82; enter(HASH, "#") - final val VIEWBOUND = 84; enter(VIEWBOUND, "<%") // TODO: deprecate + final val VIEWBOUND = 84; enter(VIEWBOUND, "<%") final val QUOTE = 85; enter(QUOTE, "'") /** XML mode */ diff --git a/docs/docs/internals/syntax.md b/docs/docs/internals/syntax.md index 9e3bf68924c9..6ec6675f9931 100644 --- a/docs/docs/internals/syntax.md +++ b/docs/docs/internals/syntax.md @@ -171,7 +171,7 @@ NamedTypeArg ::= id ‘=’ Type NamedTypeArgs ::= ‘[’ NamedTypeArg {‘,’ NamedTypeArg} ‘]’ nts Refinement ::= ‘{’ [RefineDcl] {semi [RefineDcl]} ‘}’ ds SubtypeBounds ::= [‘>:’ Type] [‘<:’ Type] | INT TypeBoundsTree(lo, hi) -TypeParamBounds ::= SubtypeBounds {‘<%’ Type} {‘:’ Type} ContextBounds(typeBounds, tps) +TypeParamBounds ::= SubtypeBounds {‘:’ Type} ContextBounds(typeBounds, tps) ``` ### Expressions diff --git a/tests/pos/spec-doubledef-old.scala b/tests/pos-scala2/spec-doubledef-old.scala similarity index 100% rename from tests/pos/spec-doubledef-old.scala rename to tests/pos-scala2/spec-doubledef-old.scala diff --git a/tests/pos/t3688.scala b/tests/pos-scala2/t3688.scala similarity index 100% rename from tests/pos/t3688.scala rename to tests/pos-scala2/t3688.scala From b9d4893b51799cdf9af12111fb34eba0d6ef1e3a Mon Sep 17 00:00:00 2001 From: Olivier Blanvillain Date: Tue, 2 Apr 2019 11:17:38 +0200 Subject: [PATCH 2/3] Refactor abstraction over language.feature module All the deleted code was used to distinguish between scala.language.feature and dotty.language.feature, but the latter got removed with the introduction of the scalaShadowing package and has been dead code since then. --- .../src/dotty/tools/dotc/core/TypeOps.scala | 26 ++++++++----------- .../dotty/tools/dotc/reporting/Reporter.scala | 5 ++-- .../src/dotty/tools/dotc/typer/Checking.scala | 15 +++++------ .../dotty/tools/dotc/typer/Implicits.scala | 2 +- .../dotty/tools/dotc/typer/ImportInfo.scala | 5 ++-- .../src/dotty/tools/dotc/typer/Typer.scala | 3 +-- .../dotty/tools/dotc/CompilationTests.scala | 4 +-- library/src/scalaShadowing/language.scala | 3 ++- 8 files changed, 28 insertions(+), 35 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index 3d5482701ce8..ce5240001d98 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -379,29 +379,24 @@ trait TypeOps { this: Context => // TODO: Make standalone object. * where is the full name of the owner followed by a "." minus * the prefix "dotty.language.". */ - def featureEnabled(owner: ClassSymbol, feature: TermName): Boolean = { - val hasImport = + def featureEnabled(feature: TermName): Boolean = { + def hasImport = ctx.importInfo != null && - ctx.importInfo.featureImported(owner, feature)(ctx.withPhase(ctx.typerPhase)) - def hasOption = { - def toPrefix(sym: Symbol): String = - if (!sym.exists || (sym eq defn.LanguageModuleClass)) "" - else toPrefix(sym.owner) + sym.name + "." - val featureName = toPrefix(owner) + feature - ctx.base.settings.language.value exists (s => s == featureName || s == "_") - } - hasImport || hasOption + ctx.importInfo.featureImported(feature)(ctx.withPhase(ctx.typerPhase)) + val hasOption = + ctx.base.settings.language.value.exists(s => s == feature.toString || s == "_") + hasOption || hasImport } /** Is auto-tupling enabled? */ def canAutoTuple: Boolean = - !featureEnabled(defn.LanguageModuleClass, nme.noAutoTupling) + !featureEnabled(nme.noAutoTupling) def scala2Mode: Boolean = - featureEnabled(defn.LanguageModuleClass, nme.Scala2) + featureEnabled(nme.Scala2) def dynamicsEnabled: Boolean = - featureEnabled(defn.LanguageModuleClass, nme.dynamics) + featureEnabled(nme.dynamics) def testScala2Mode(msg: => Message, pos: SourcePosition, replace: => Unit = ()): Boolean = { if (scala2Mode) { @@ -414,7 +409,8 @@ trait TypeOps { this: Context => // TODO: Make standalone object. /** Is option -language:Scala2 set? * This test is used when we are too early in the pipeline to consider imports. */ - def scala2Setting = ctx.settings.language.value.contains(nme.Scala2.toString) + def scala2Setting: Boolean = + ctx.settings.language.value.contains(nme.Scala2.toString) /** Refine child based on parent * diff --git a/compiler/src/dotty/tools/dotc/reporting/Reporter.scala b/compiler/src/dotty/tools/dotc/reporting/Reporter.scala index e0b3af4ad99b..f03e39963663 100644 --- a/compiler/src/dotty/tools/dotc/reporting/Reporter.scala +++ b/compiler/src/dotty/tools/dotc/reporting/Reporter.scala @@ -66,11 +66,10 @@ trait Reporting { this: Context => def featureWarning(msg: => Message, pos: SourcePosition = NoSourcePosition): Unit = reportWarning(new FeatureWarning(msg, pos)) - def featureWarning(feature: String, featureDescription: String, isScala2Feature: Boolean, + def featureWarning(feature: String, featureDescription: String, featureUseSite: Symbol, required: Boolean, pos: SourcePosition): Unit = { val req = if (required) "needs to" else "should" - val prefix = if (isScala2Feature) "scala." else "dotty." - val fqname = prefix + "language." + feature + val fqname = s"scala.language.$feature" val explain = { if (reporter.isReportedFeatureUseSite(featureUseSite)) "" diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 8d197bf7fbf3..c6d4f0fbd0e4 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -617,7 +617,7 @@ trait Checking { def checkImplicitConversionDefOK(sym: Symbol)(implicit ctx: Context): Unit = { def check(): Unit = { checkFeature( - defn.LanguageModuleClass, nme.implicitConversions, + nme.implicitConversions, i"Definition of implicit conversion $sym", ctx.owner.topLevelClass, sym.sourcePos) @@ -654,20 +654,17 @@ trait Checking { defn.isPredefClass(conv.owner) || conv.name == nme.reflectiveSelectable && conv.maybeOwner.maybeOwner.maybeOwner == defn.ScalaPackageClass if (!conversionOK) - checkFeature(defn.LanguageModuleClass, nme.implicitConversions, + checkFeature(nme.implicitConversions, i"Use of implicit conversion ${conv.showLocated}", NoSymbol, posd.sourcePos) } /** Issue a feature warning if feature is not enabled */ - def checkFeature(base: ClassSymbol, - name: TermName, + def checkFeature(name: TermName, description: => String, featureUseSite: Symbol, pos: SourcePosition)(implicit ctx: Context): Unit = - if (!ctx.featureEnabled(base, name)) - ctx.featureWarning(name.toString, description, - isScala2Feature = base.isContainedIn(defn.LanguageModuleClass), - featureUseSite, required = false, pos) + if (!ctx.featureEnabled(name)) + ctx.featureWarning(name.toString, description, featureUseSite, required = false, pos) /** Check that `tp` is a class type and that any top-level type arguments in this type * are feasible, i.e. that their lower bound conforms to their upper bound. If a type @@ -1048,5 +1045,5 @@ trait NoChecking extends ReChecking { override def checkNoForwardDependencies(vparams: List[ValDef])(implicit ctx: Context): Unit = () override def checkMembersOK(tp: Type, pos: SourcePosition)(implicit ctx: Context): Type = tp override def checkInInlineContext(what: String, posd: Positioned)(implicit ctx: Context): Unit = () - override def checkFeature(base: ClassSymbol, name: TermName, description: => String, featureUseSite: Symbol, pos: SourcePosition)(implicit ctx: Context): Unit = () + override def checkFeature(name: TermName, description: => String, featureUseSite: Symbol, pos: SourcePosition)(implicit ctx: Context): Unit = () } diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 99e6800ad66d..f4df867ef2da 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -947,7 +947,7 @@ trait Implicits { self: Typer => private def strictEquality(implicit ctx: Context): Boolean = ctx.mode.is(Mode.StrictEquality) || - ctx.featureEnabled(defn.LanguageModuleClass, nme.strictEquality) + ctx.featureEnabled(nme.strictEquality) /** An Eql[T, U] instance is assumed * - if one of T, U is an error type, or diff --git a/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala b/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala index 33e02fd349a0..6c5679139668 100644 --- a/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala +++ b/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala @@ -146,7 +146,8 @@ class ImportInfo(symf: Context => Symbol, val selectors: List[untpd.Tree], private[this] var myUnimported: Symbol = _ /** Does this import clause or a preceding import clause import `owner.feature`? */ - def featureImported(owner: Symbol, feature: TermName)(implicit ctx: Context): Boolean = { + def featureImported(feature: TermName)(implicit ctx: Context): Boolean = { + val owner: Symbol = defn.LanguageModuleClass def compute = { val isImportOwner = site.widen.typeSymbol `eq` owner if (isImportOwner && originals.contains(feature)) true @@ -154,7 +155,7 @@ class ImportInfo(symf: Context => Symbol, val selectors: List[untpd.Tree], else { var c = ctx.outer while (c.importInfo eq ctx.importInfo) c = c.outer - (c.importInfo != null) && c.importInfo.featureImported(owner, feature)(c) + (c.importInfo != null) && c.importInfo.featureImported(feature)(c) } } if (lastOwner.ne(owner) || !lastResults.contains(feature)) { diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 48171be2327a..3ca8421e88c2 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1692,8 +1692,7 @@ class Typer extends Namer !ctx.dynamicsEnabled if (reportDynamicInheritance) { val isRequired = parents1.exists(_.tpe.isRef(defn.DynamicClass)) - ctx.featureWarning(nme.dynamics.toString, "extension of type scala.Dynamic", isScala2Feature = true, - cls, isRequired, cdef.sourcePos) + ctx.featureWarning(nme.dynamics.toString, "extension of type scala.Dynamic", cls, isRequired, cdef.sourcePos) } checkNonCyclicInherited(cls.thisType, cls.classParents, cls.info.decls, cdef.posd) diff --git a/compiler/test/dotty/tools/dotc/CompilationTests.scala b/compiler/test/dotty/tools/dotc/CompilationTests.scala index 772ab1b3b544..686b162b73eb 100644 --- a/compiler/test/dotty/tools/dotc/CompilationTests.scala +++ b/compiler/test/dotty/tools/dotc/CompilationTests.scala @@ -31,10 +31,10 @@ class CompilationTests extends ParallelTesting { // Positive tests ------------------------------------------------------------ - // @Test // enable to test compileStdLib separately with detailed stats + @Test // enable to test compileStdLib separately with detailed stats def compileStdLibOnly: Unit = { implicit val testGroup: TestGroup = TestGroup("compileStdLibOnly") - compileList("compileStdLib", TestSources.stdLibSources, scala2Mode.and("-migration", "-Yno-inline", "-Ydetailed-stats")) + compileList("compileStdLib", TestSources.stdLibSources, scala2Mode.and("-migration", "-Yno-inline")) }.checkCompile() @Test def pos: Unit = { diff --git a/library/src/scalaShadowing/language.scala b/library/src/scalaShadowing/language.scala index a64c985e5a10..f2d655c0fdcf 100644 --- a/library/src/scalaShadowing/language.scala +++ b/library/src/scalaShadowing/language.scala @@ -30,6 +30,7 @@ package scalaShadowing * * - [[Scala2 `Scala2`] backwards compatibility mode for Scala2 * - [[noAtoTupling `noAutoTupling`]] disable auto-tupling + * - [[strictEquality `strictEquality`]] enable strick equality * * @groupname production Language Features * @groupname experimental Experimental Language Features @@ -217,6 +218,6 @@ object language { /** Where imported, auto-tupling is disabled */ object noAutoTupling - /* Where imported loose equality using eqAny is disabled */ + /** Where imported loose equality using eqAny is disabled */ object strictEquality } From 84402203ac12d60f176d0876ef13f5e4c5f1642b Mon Sep 17 00:00:00 2001 From: Olivier Blanvillain Date: Tue, 9 Apr 2019 14:28:32 +0200 Subject: [PATCH 3/3] Address review --- .../src/dotty/tools/dotc/core/TypeOps.scala | 17 ++++++++++++----- .../src/dotty/tools/dotc/typer/ImportInfo.scala | 7 +++---- .../dotty/tools/dotc/CompilationTests.scala | 2 +- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index ce5240001d98..3b01eabf4d41 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -379,12 +379,19 @@ trait TypeOps { this: Context => // TODO: Make standalone object. * where is the full name of the owner followed by a "." minus * the prefix "dotty.language.". */ - def featureEnabled(feature: TermName): Boolean = { - def hasImport = + def featureEnabled(feature: TermName, owner: Symbol = NoSymbol): Boolean = { + def hasImport = { + val owner1 = if (!owner.exists) defn.LanguageModuleClass else owner ctx.importInfo != null && - ctx.importInfo.featureImported(feature)(ctx.withPhase(ctx.typerPhase)) - val hasOption = - ctx.base.settings.language.value.exists(s => s == feature.toString || s == "_") + ctx.importInfo.featureImported(feature, owner1)(ctx.withPhase(ctx.typerPhase)) + } + val hasOption = { + def toPrefix(sym: Symbol): String = + if (!sym.exists) "" + else toPrefix(sym.owner) + sym.name + "." + val featureName = toPrefix(owner) + feature + ctx.base.settings.language.value exists (s => s == featureName || s == "_") + } hasOption || hasImport } diff --git a/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala b/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala index 6c5679139668..0c69d37cd0db 100644 --- a/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala +++ b/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala @@ -146,16 +146,15 @@ class ImportInfo(symf: Context => Symbol, val selectors: List[untpd.Tree], private[this] var myUnimported: Symbol = _ /** Does this import clause or a preceding import clause import `owner.feature`? */ - def featureImported(feature: TermName)(implicit ctx: Context): Boolean = { - val owner: Symbol = defn.LanguageModuleClass + def featureImported(feature: TermName, owner: Symbol)(implicit ctx: Context): Boolean = { def compute = { - val isImportOwner = site.widen.typeSymbol `eq` owner + val isImportOwner = site.widen.typeSymbol.eq(owner) if (isImportOwner && originals.contains(feature)) true else if (isImportOwner && excluded.contains(feature)) false else { var c = ctx.outer while (c.importInfo eq ctx.importInfo) c = c.outer - (c.importInfo != null) && c.importInfo.featureImported(feature)(c) + (c.importInfo != null) && c.importInfo.featureImported(feature, owner)(c) } } if (lastOwner.ne(owner) || !lastResults.contains(feature)) { diff --git a/compiler/test/dotty/tools/dotc/CompilationTests.scala b/compiler/test/dotty/tools/dotc/CompilationTests.scala index 686b162b73eb..c8f34726d2d0 100644 --- a/compiler/test/dotty/tools/dotc/CompilationTests.scala +++ b/compiler/test/dotty/tools/dotc/CompilationTests.scala @@ -31,7 +31,7 @@ class CompilationTests extends ParallelTesting { // Positive tests ------------------------------------------------------------ - @Test // enable to test compileStdLib separately with detailed stats + // @Test // enable to test compileStdLib separately with detailed stats def compileStdLibOnly: Unit = { implicit val testGroup: TestGroup = TestGroup("compileStdLibOnly") compileList("compileStdLib", TestSources.stdLibSources, scala2Mode.and("-migration", "-Yno-inline"))