summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2012-04-11 11:06:54 -0700
committerMartin Odersky <odersky@gmail.com>2012-04-11 11:06:54 -0700
commitf7a0558059559305a88ffa2c28506b29b2bc57f2 (patch)
tree267f7d00bbb327ca80b14df92e540251bf2da283 /src/compiler
parent754b4a85e4093f25cc10f092fefdb34215097c94 (diff)
downloadscala-f7a0558059559305a88ffa2c28506b29b2bc57f2.tar.gz
scala-f7a0558059559305a88ffa2c28506b29b2bc57f2.tar.bz2
scala-f7a0558059559305a88ffa2c28506b29b2bc57f2.zip
Implementation of SIP 18. We still need to get rid of the warnings caused by it. Before we do that, I'd like to check in the SIP 13 implementation.
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 {