aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc
diff options
context:
space:
mode:
authorNicolas Stucki <nicolas.stucki@gmail.com>2016-06-03 15:00:10 +0200
committerNicolas Stucki <nicolas.stucki@gmail.com>2016-07-07 11:10:45 +0200
commit5a7cacbb37f8f1edfded03a095eb45c04a883185 (patch)
treee00dc214c0c8236141f0d99531e0d211f77df8df /src/dotty/tools/dotc
parent75da0358fd7866f3dccdfcf4fbeae9af8ccc69f3 (diff)
downloaddotty-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.scala4
-rw-r--r--src/dotty/tools/dotc/core/StdNames.scala1
-rw-r--r--src/dotty/tools/dotc/core/TypeOps.scala6
-rw-r--r--src/dotty/tools/dotc/reporting/Reporter.scala30
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala8
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: