summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/reflect/internal/Definitions.scala14
-rw-r--r--src/compiler/scala/reflect/internal/Symbols.scala6
-rw-r--r--src/compiler/scala/reflect/internal/Types.scala17
-rw-r--r--src/compiler/scala/tools/nsc/CompilationUnits.scala11
-rw-r--r--src/compiler/scala/tools/nsc/ast/Trees.scala4
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala3
-rw-r--r--src/compiler/scala/tools/nsc/interactive/Global.scala1
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala1
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala56
9 files changed, 97 insertions, 16 deletions
diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala
index 8ea3cd511a..d3a9821596 100644
--- a/src/compiler/scala/reflect/internal/Definitions.scala
+++ b/src/compiler/scala/reflect/internal/Definitions.scala
@@ -914,6 +914,18 @@ trait Definitions extends reflect.api.StandardDefinitions {
lazy val GetterTargetClass = getMetaAnnotation("getter")
lazy val ParamTargetClass = getMetaAnnotation("param")
lazy val SetterTargetClass = getMetaAnnotation("setter")
+ lazy val LanguageFeatureClass = getMetaAnnotation("languageFeature")
+
+ // Language features
+ lazy val languageFeatureModule = getRequiredModule("scala.languageFeature")
+ lazy val MacrosFeature = getRequiredClass("scala.languageFeature.experimental.macros")
+ lazy val DynamicsFeature = getRequiredClass("scala.languageFeature.dynamics")
+ lazy val PostfixOpsFeature = getRequiredClass("scala.languageFeature.postfixOps")
+ lazy val ReflectiveCallsFeature = getRequiredClass("scala.languageFeature.reflectiveCalls")
+ lazy val ImplicitConversionsFeature = getRequiredClass("scala.languageFeature.implicitConversions")
+ lazy val HigherKindsFeature = getRequiredClass("scala.languageFeature.higherKinds")
+ lazy val ExistentialsFeature = getRequiredClass("scala.languageFeature.existentials")
+
// TODO: module, moduleClass? package, packageObject?
private def getMetaAnnotation(name: String) = getRequiredClass("scala.annotation.meta." + name)
@@ -990,7 +1002,7 @@ trait Definitions extends reflect.api.StandardDefinitions {
case result => result
}
}
-
+
def packageExists(packageName: String): Boolean =
getModuleIfDefined(packageName).isPackage
diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala
index 5c43047046..b984383dd2 100644
--- a/src/compiler/scala/reflect/internal/Symbols.scala
+++ b/src/compiler/scala/reflect/internal/Symbols.scala
@@ -1191,7 +1191,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* which immediately follows any of parser, namer, typer, or erasure.
* In effect that means this will return one of:
*
- * - packageobjects (follows namer)
+ * - packageobjects (follows namer)
* - superaccessors (follows typer)
* - lazyvals (follows erasure)
* - null
@@ -1882,7 +1882,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** Remove private modifier from symbol `sym`s definition. If `sym` is a
* is not a constructor nor a static module rename it by expanding its name to avoid name clashes
- * @param base the fully qualified name of this class will be appended if name expansion is needed
+ * @param base the fully qualified name of this class will be appended if name expansion is needed
*/
final def makeNotPrivate(base: Symbol) {
if (this.isPrivate) {
@@ -2782,7 +2782,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
assert(validFrom != NoPeriod)
override def toString() =
"TypeHistory(" + phaseOf(validFrom)+":"+runId(validFrom) + "," + info + "," + prev + ")"
-
+
def toList: List[TypeHistory] = this :: ( if (prev eq null) Nil else prev.toList )
}
}
diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala
index 786b680ff8..46c56ccd4c 100644
--- a/src/compiler/scala/reflect/internal/Types.scala
+++ b/src/compiler/scala/reflect/internal/Types.scala
@@ -2493,26 +2493,33 @@ trait Types extends api.Types { self: SymbolTable =>
* - where there is a 1-to-1 correspondence between underlying's typeargs and quantified
* - and none of the existential parameters is referenced from anywhere else in the type
* - and none of the existential parameters are singleton types
+ * - @param checkBounds if set returns false for situations like
+ * (S, T) forSome { type S; type T <: S }
+ * If not set returns true. The reason for this mode is to
+ * avoid cyclic reference errors when the method is called
+ * early (e.g. from Typers # checkExistentialsFeature)
*/
- private def isRepresentableWithWildcards = !settings.debug.value && {
+ def isRepresentableWithWildcards(checkBounds: Boolean) = {
val qset = quantified.toSet
- !qset.exists(_.isSingletonExistential) && (underlying match {
+ underlying match {
case TypeRef(_, sym, args) =>
sameLength(args, quantified) && {
args forall { arg =>
- qset(arg.typeSymbol) && !qset.exists(arg.typeSymbol.info.bounds contains _)
+ qset(arg.typeSymbol) &&
+ (!checkBounds || !qset.exists(arg.typeSymbol.info.bounds contains _))
}
}
case _ => false
- })
+ }
}
+
override def safeToString: String = {
def clauses = {
val str = quantified map (_.existentialToString) mkString (" forSome { ", "; ", " }")
if (settings.explaintypes.value) "(" + str + ")" else str
}
underlying match {
- case TypeRef(pre, sym, args) if isRepresentableWithWildcards =>
+ case TypeRef(pre, sym, args) if !settings.debug.value && isRepresentableWithWildcards(checkBounds = true) =>
"" + TypeRef(pre, sym, Nil) + wildcardArgsString(quantified.toSet, args).mkString("[", ", ", "]")
case MethodType(_, _) | NullaryMethodType(_) | PolyType(_, _) =>
"(" + underlying + ")" + clauses
diff --git a/src/compiler/scala/tools/nsc/CompilationUnits.scala b/src/compiler/scala/tools/nsc/CompilationUnits.scala
index d6f57801e7..27722a99c9 100644
--- a/src/compiler/scala/tools/nsc/CompilationUnits.scala
+++ b/src/compiler/scala/tools/nsc/CompilationUnits.scala
@@ -61,6 +61,9 @@ trait CompilationUnits { self: Global =>
/** things to check at end of compilation unit */
val toCheck = new ListBuffer[() => Unit]
+ /** The features that were already checked for this unit */
+ var checkedFeatures = Set[Symbol]()
+
def position(pos: Int) = source.position(pos)
/** The position of a targeted type check
@@ -104,10 +107,14 @@ trait CompilationUnits { self: Global =>
override def toString() = source.toString()
def clear() {
- fresh = null
- body = null
+ fresh = new FreshNameCreator.Default
+ body = EmptyTree
depends.clear()
defined.clear()
+ synthetics.clear()
+ toCheck.clear()
+ checkedFeatures = Set()
+ icode.clear()
}
}
}
diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala
index 43c231cf2d..de610df93e 100644
--- a/src/compiler/scala/tools/nsc/ast/Trees.scala
+++ b/src/compiler/scala/tools/nsc/ast/Trees.scala
@@ -81,6 +81,8 @@ trait Trees extends reflect.internal.Trees { self: Global =>
case class InjectDerivedValue(arg: Tree)
extends SymTree
+ class PostfixSelect(qual: Tree, name: Name) extends Select(qual, name)
+
/** emitted by typer, eliminated by refchecks */
case class TypeTreeWithDeferredRefCheck()(val check: () => TypeTree) extends TypTree
@@ -397,4 +399,4 @@ trait Trees extends reflect.internal.Trees { self: Global =>
*/
- } \ No newline at end of file
+ }
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index 45325b4694..eda75ae187 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -1456,11 +1456,12 @@ self =>
return reduceStack(true, base, top, 0, true)
top = next
} else {
+ // postfix expression
val topinfo = opstack.head
opstack = opstack.tail
val od = stripParens(reduceStack(true, base, topinfo.operand, 0, true))
return atPos(od.pos.startOrPoint, topinfo.offset) {
- Select(od, topinfo.operator.encode)
+ new PostfixSelect(od, topinfo.operator.encode)
}
}
}
diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala
index 166b38f503..4cf31cc576 100644
--- a/src/compiler/scala/tools/nsc/interactive/Global.scala
+++ b/src/compiler/scala/tools/nsc/interactive/Global.scala
@@ -529,6 +529,7 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "")
unit.defined.clear()
unit.synthetics.clear()
unit.toCheck.clear()
+ unit.checkedFeatures = Set()
unit.targetPos = NoPosition
unit.contexts.clear()
unit.problems.clear()
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index 14b3bcc8ce..c0b75fecc4 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -62,6 +62,7 @@ trait ScalaSettings extends AbsScalaSettings
val classpath = PathSetting ("-classpath", "Specify where to find user class files.", defaultClasspath) withAbbreviation "-cp"
val d = OutputSetting (outputDirs, ".")
val nospecialization = BooleanSetting ("-no-specialization", "Ignore @specialize annotations.")
+ val feature = MultiStringSetting("-language", "feature", "Enable one or more language features.")
/**
* -X "Advanced" settings
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 36c81b09cd..19d7dde875 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -508,7 +508,6 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
res
}
-
/** The typer for a label definition. If this is part of a template we
* first have to enter the label definition.
*/
@@ -730,6 +729,38 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
}
+ def checkFeature(pos: Position, featureTrait: Symbol, construct: => String = "") =
+ if (!isPastTyper) {
+ val nestedOwners =
+ featureTrait.owner.ownerChain.takeWhile(_ != languageFeatureModule.moduleClass).reverse
+ val featureName = (nestedOwners map (_ + ".")).mkString + featureTrait.name
+ unit.toCheck += { () =>
+ if (!(unit.checkedFeatures contains featureTrait)) {
+ def hasImport = inferImplicit(EmptyTree: Tree, featureTrait.tpe, true, false, context) != SearchFailure
+ def hasOption = settings.feature.value contains featureName
+ if (!hasImport && !hasOption) {
+ val Some(AnnotationInfo(_, List(Literal(Constant(featureDesc: String)), Literal(Constant(required: Boolean))), _)) =
+ featureTrait getAnnotation LanguageFeatureClass
+ val req = if (required) "needs to" else "should"
+ val raw = featureDesc + " " + req + " be enabled by making\n" +
+ "the implicit value language." + featureName + " visible. This can be achieved by adding the import\n" +
+ "import language." + featureName + " or by setting the compiler option -language:" + featureName + ".\n" +
+ "See the Scala docs for value scala.language." + featureName + "for a discussion\n" +
+ "why the feature " + req + " be explicitly enabled."
+ val msg = raw replace ("#", construct)
+ if (required) unit.error(pos, msg) else unit.warning(pos, msg)
+ unit.checkedFeatures += featureTrait
+ }
+ }
+ }
+ }
+
+ def checkExistentialsFeature(pos: Position, tpe: Type, prefix: String) = tpe match {
+ case extp: ExistentialType if !extp.isRepresentableWithWildcards(checkBounds = false) =>
+ checkFeature(pos, ExistentialsFeature, prefix+" "+tpe)
+ case _ =>
+ }
+
/** Perform the following adaptations of expression, pattern or type `tree` wrt to
* given mode `mode` and given prototype `pt`:
* (-1) For expressions with annotated types, let AnnotationCheckers decide what to do
@@ -1937,6 +1968,13 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
if (meth.isStructuralRefinementMember)
checkMethodStructuralCompatible(meth)
+ if (meth.isImplicit) meth.info.paramss match {
+ case List(param) :: _ if !param.isImplicit =>
+ println("check implicit +"+meth+" "+isPastTyper)
+ checkFeature(ddef.pos, ImplicitConversionsFeature, meth.toString)
+ case _ =>
+ }
+
treeCopy.DefDef(ddef, typedMods, ddef.name, tparams1, vparamss1, tpt1, rhs1) setType NoType
}
@@ -1968,6 +2006,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
case TypeBounds(lo1, hi1) if (!(lo1 <:< hi1)) => LowerBoundError(tdef, lo1, hi1)
case _ => ()
}
+
+ if (tdef.symbol.isDeferred && tdef.symbol.info.isHigherKinded)
+ checkFeature(tdef.pos, HigherKindsFeature)
+
treeCopy.TypeDef(tdef, typedMods, tdef.name, tparams1, rhs1) setType NoType
}
@@ -4666,6 +4708,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
else
typedSelect(qual1, name)
+ val sym = tree1.symbol
+ if (sym != null && sym.isTerm && sym.owner.isRefinementClass && !sym.isConstant)
+ checkFeature(tree1.pos, ReflectiveCallsFeature, sym.toString)
+
if (qual1.symbol == RootPackage) treeCopy.Ident(tree1, name)
else tree1
@@ -4708,9 +4754,11 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
treeCopy.TypeBoundsTree(tree, lo1, hi1) setType TypeBounds(lo1.tpe, hi1.tpe)
case etpt @ ExistentialTypeTree(_, _) =>
- typerWithLocalContext(context.makeNewScope(tree, context.owner)){
+ val tree1 = typerWithLocalContext(context.makeNewScope(tree, context.owner)){
_.typedExistentialTypeTree(etpt, mode)
}
+ checkExistentialsFeature(tree1.pos, tree1.tpe, "the existential type")
+ tree1
case dc@TypeTreeWithDeferredRefCheck() => dc // TODO: should we re-type the wrapped tree? then we need to change TypeTreeWithDeferredRefCheck's representation to include the wrapped tree explicitly (instead of in its closure)
case tpt @ TypeTree() =>
@@ -4918,7 +4966,9 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
def computeType(tree: Tree, pt: Type): Type = {
val tree1 = typed(tree, pt)
transformed(tree) = tree1
- packedType(tree1, context.owner)
+ val tpe = packedType(tree1, context.owner)
+ checkExistentialsFeature(tree.pos, tpe, "inferred existential type")
+ tpe
}
def transformedOrTyped(tree: Tree, mode: Int, pt: Type): Tree = transformed.get(tree) match {