diff options
author | Nicolas Stucki <nicolas.stucki@gmail.com> | 2016-06-03 15:00:10 +0200 |
---|---|---|
committer | Nicolas Stucki <nicolas.stucki@gmail.com> | 2016-07-07 11:10:45 +0200 |
commit | 5a7cacbb37f8f1edfded03a095eb45c04a883185 (patch) | |
tree | e00dc214c0c8236141f0d99531e0d211f77df8df /src/dotty/tools/dotc | |
parent | 75da0358fd7866f3dccdfcf4fbeae9af8ccc69f3 (diff) | |
download | dotty-5a7cacbb37f8f1edfded03a095eb45c04a883185.tar.gz dotty-5a7cacbb37f8f1edfded03a095eb45c04a883185.tar.bz2 dotty-5a7cacbb37f8f1edfded03a095eb45c04a883185.zip |
Add scala.Dynamic language feature check.
Diffstat (limited to 'src/dotty/tools/dotc')
-rw-r--r-- | src/dotty/tools/dotc/core/Definitions.scala | 4 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/StdNames.scala | 1 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/TypeOps.scala | 6 | ||||
-rw-r--r-- | src/dotty/tools/dotc/reporting/Reporter.scala | 30 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Typer.scala | 8 |
5 files changed, 45 insertions, 4 deletions
diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala index 5cb373cfd..1fa3f70f9 100644 --- a/src/dotty/tools/dotc/core/Definitions.scala +++ b/src/dotty/tools/dotc/core/Definitions.scala @@ -424,8 +424,10 @@ class Definitions { def Product_productArity(implicit ctx: Context) = Product_productArityR.symbol lazy val Product_productPrefixR = ProductClass.requiredMethodRef(nme.productPrefix) def Product_productPrefix(implicit ctx: Context) = Product_productPrefixR.symbol - lazy val LanguageModuleRef = ctx.requiredModule("dotty.language") + lazy val LanguageModuleRef = ctx.requiredModule("dotty.language") def LanguageModuleClass(implicit ctx: Context) = LanguageModuleRef.symbol.moduleClass.asClass + lazy val Scala2LanguageModuleRef = ctx.requiredModule("scala.language") + def Scala2LanguageModuleClass(implicit ctx: Context) = Scala2LanguageModuleRef.symbol.moduleClass.asClass lazy val NonLocalReturnControlType: TypeRef = ctx.requiredClassRef("scala.runtime.NonLocalReturnControl") lazy val ClassTagType = ctx.requiredClassRef("scala.reflect.ClassTag") diff --git a/src/dotty/tools/dotc/core/StdNames.scala b/src/dotty/tools/dotc/core/StdNames.scala index 81f6da0e2..345322cf5 100644 --- a/src/dotty/tools/dotc/core/StdNames.scala +++ b/src/dotty/tools/dotc/core/StdNames.scala @@ -383,6 +383,7 @@ object StdNames { val delayedInit: N = "delayedInit" val delayedInitArg: N = "delayedInit$body" val drop: N = "drop" + val dynamics: N = "dynamics" val dummyApply: N = "<dummy-apply>" val elem: N = "elem" val emptyValDef: N = "emptyValDef" diff --git a/src/dotty/tools/dotc/core/TypeOps.scala b/src/dotty/tools/dotc/core/TypeOps.scala index 1288c0b23..3da119a9c 100644 --- a/src/dotty/tools/dotc/core/TypeOps.scala +++ b/src/dotty/tools/dotc/core/TypeOps.scala @@ -455,7 +455,8 @@ trait TypeOps { this: Context => // TODO: Make standalone object. */ def featureEnabled(owner: ClassSymbol, feature: TermName): Boolean = { def toPrefix(sym: Symbol): String = - if (sym eq defn.LanguageModuleClass) "" else toPrefix(sym.owner) + sym.name + "." + if (!sym.exists || (sym eq defn.LanguageModuleClass) || (sym eq defn.Scala2LanguageModuleRef)) "" + else toPrefix(sym.owner) + sym.name + "." def featureName = toPrefix(owner) + feature def hasImport(implicit ctx: Context): Boolean = ( ctx.importInfo != null @@ -477,6 +478,9 @@ trait TypeOps { this: Context => // TODO: Make standalone object. def scala2Mode = featureEnabled(defn.LanguageModuleClass, nme.Scala2) + def dynamicsEnabled = + featureEnabled(defn.Scala2LanguageModuleClass, nme.dynamics) + def testScala2Mode(msg: String, pos: Position) = { if (scala2Mode) migrationWarning(msg, pos) scala2Mode diff --git a/src/dotty/tools/dotc/reporting/Reporter.scala b/src/dotty/tools/dotc/reporting/Reporter.scala index e4169b1fd..bddfd2f68 100644 --- a/src/dotty/tools/dotc/reporting/Reporter.scala +++ b/src/dotty/tools/dotc/reporting/Reporter.scala @@ -12,6 +12,7 @@ import config.Printers import java.lang.System.currentTimeMillis import core.Mode import interfaces.Diagnostic.{ERROR, WARNING, INFO} +import dotty.tools.dotc.core.Symbols.Symbol object Reporter { class Error(msgFn: => String, pos: SourcePosition) extends Diagnostic(msgFn, pos, ERROR) @@ -68,6 +69,29 @@ trait Reporting { this: Context => def featureWarning(msg: => String, pos: SourcePosition = NoSourcePosition): Unit = reporter.report(new FeatureWarning(msg, pos)) + def featureWarning(feature: String, featureDescription: String, isScala2Feature: Boolean, + 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 explain = { + if (reporter.isReportedFeatureUseSite(featureUseSite)) "" + else { + reporter.reportNewFeatureUseSite(featureUseSite) + s"""| + |This can be achieved by adding the import clause 'import $fqname' + |or by setting the compiler option -language:$feature. + |See the Scala docs for value $fqname for a discussion + |why the feature $req be explicitly enabled.""".stripMargin + } + } + + val msg = s"$featureDescription $req be enabled\nby making the implicit value $fqname visible.$explain" + if (required) error(msg, pos) + else reporter.report(new FeatureWarning(msg, pos)) + } + def warning(msg: => String, pos: SourcePosition = NoSourcePosition): Unit = reporter.report(new Warning(msg, pos)) @@ -172,7 +196,7 @@ abstract class Reporter extends interfaces.ReporterResult { /** Report a diagnostic */ def doReport(d: Diagnostic)(implicit ctx: Context): Unit - /** Whether very long lines can be truncated. This exists so important + /** Whether very long lines can be truncated. This exists so important * debugging information (like printing the classpath) is not rendered * invisible due to the max message length. */ @@ -206,6 +230,10 @@ abstract class Reporter extends interfaces.ReporterResult { */ def errorsReported = hasErrors + private[this] var reportedFeaturesUseSites = Set[Symbol]() + def isReportedFeatureUseSite(featureTrait: Symbol): Boolean = reportedFeaturesUseSites.contains(featureTrait) + def reportNewFeatureUseSite(featureTrait: Symbol): Unit = reportedFeaturesUseSites += featureTrait + val unreportedWarnings = new mutable.HashMap[String, Int] { override def default(key: String) = 0 } diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 019c460e8..34400ede7 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -1092,7 +1092,13 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit .withType(dummy.nonMemberTermRef) checkVariance(impl1) if (!cls.is(AbstractOrTrait) && !ctx.isAfterTyper) checkRealizableBounds(cls.typeRef, cdef.pos) - assignType(cpy.TypeDef(cdef)(name, impl1, Nil), cls) + val cdef1 = assignType(cpy.TypeDef(cdef)(name, impl1, Nil), cls) + if (ctx.phase.isTyper && cdef1.tpe.derivesFrom(defn.DynamicClass) && !ctx.dynamicsEnabled) { + val isRequired = parents1.exists(_.tpe.isRef(defn.DynamicClass)) + ctx.featureWarning(nme.dynamics.toString, "extension of type scala.Dynamic", isScala2Feature = true, + cls, isRequired, cdef.pos) + } + cdef1 // todo later: check that // 1. If class is non-abstract, it is instantiatable: |