aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/typer/Checking.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2014-03-05 18:36:38 +0100
committerMartin Odersky <odersky@gmail.com>2014-03-07 11:12:33 +0100
commit2669fac03190a4b52b120e07896cf5cd3de208c6 (patch)
tree8ceaebd4011f91847c4b0def3e55ad822646c394 /src/dotty/tools/dotc/typer/Checking.scala
parentaf3bfbab17f6f13b10497487259138732d8b8bb9 (diff)
downloaddotty-2669fac03190a4b52b120e07896cf5cd3de208c6.tar.gz
dotty-2669fac03190a4b52b120e07896cf5cd3de208c6.tar.bz2
dotty-2669fac03190a4b52b120e07896cf5cd3de208c6.zip
First step towards Typer Reorganization.
Goal is better modularization and avoiding code duplication and divergence between Typer and tpd. As a first step, we split Inferencing into Inferencing, Checking, and ProtoTypes. Inferencing and Checking become Typer traits, while ProtoTypes remains a global object. Eventually: - we want to have a SimpleTyper, which does the main stuff in tpd, and can mixin either full checking or no checking. Each method in SimpleTyper takes an untyped tree (which is assumed to have typed arguments) and adds a toplevel type to that tree. The methods subsume the type-checking parts in Typers, except for (1) simplifications and expansions (2) computing prototypes and recursing with them into childtrees (3) adaptation. The method calls the necessary checking operations, which may however be stubbed out. The idea is already exercised in the typechecking code for Literal and New, except that for now it calls methods in tpd (they will become methods in SimpleTyper instead). - Typer should inherit from SimpleTyper, and forward all logic except for (1) - (3) to it. - tpd should call the simple typer it gets from ctx.typer - ctx.typer should be a SimpleTyper, not a complete one.
Diffstat (limited to 'src/dotty/tools/dotc/typer/Checking.scala')
-rw-r--r--src/dotty/tools/dotc/typer/Checking.scala119
1 files changed, 119 insertions, 0 deletions
diff --git a/src/dotty/tools/dotc/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala
new file mode 100644
index 000000000..2fa0d5519
--- /dev/null
+++ b/src/dotty/tools/dotc/typer/Checking.scala
@@ -0,0 +1,119 @@
+package dotty.tools
+package dotc
+package typer
+
+import core._
+import ast._
+import Contexts._, Types._, Flags._, Denotations._, Names._, StdNames._, NameOps._, Symbols._
+import Trees._
+import Constants._
+import Scopes._
+import annotation.unchecked
+import util.Positions._
+import util.{Stats, SimpleMap}
+import util.common._
+import Decorators._
+import Uniques._
+import ErrorReporting.{errorType, InfoString}
+import config.Printers._
+import collection.mutable
+
+trait Checking {
+
+ import tpd._
+
+ /** Check that type arguments `args` conform to corresponding bounds in `poly` */
+ def checkBounds(args: List[tpd.Tree], poly: PolyType, pos: Position)(implicit ctx: Context): Unit =
+ for ((arg, bounds) <- args zip poly.paramBounds) {
+ def notConforms(which: String, bound: Type) =
+ ctx.error(i"Type argument ${arg.tpe} does not conform to $which bound $bound", arg.pos)
+ if (!(arg.tpe <:< bounds.hi)) notConforms("upper", bounds.hi)
+ if (!(bounds.lo <:< arg.tpe)) notConforms("lower", bounds.lo)
+ }
+
+ /** Check that type `tp` is stable.
+ * @return The type itself
+ */
+ def checkStable(tp: Type, pos: Position)(implicit ctx: Context): Unit =
+ if (!tp.isStable) ctx.error(i"Prefix of type ${tp.widenIfUnstable} is not stable", pos)
+
+ /** Check that `tp` is a class type with a stable prefix. Also, if `isFirst` is
+ * false check that `tp` is a trait.
+ * @return `tp` itself if it is a class or trait ref, ObjectClass.typeRef if not.
+ */
+ def checkClassTypeWithStablePrefix(tp: Type, pos: Position, traitReq: Boolean)(implicit ctx: Context): Type =
+ tp.underlyingClassRef match {
+ case tref: TypeRef =>
+ checkStable(tref.prefix, pos)
+ if (traitReq && !(tref.symbol is Trait)) ctx.error(i"$tref is not a trait", pos)
+ tp
+ case _ =>
+ ctx.error(i"$tp is not a class type", pos)
+ defn.ObjectClass.typeRef
+ }
+
+ /** Check that (return) type of implicit definition is not empty */
+ def checkImplicitTptNonEmpty(defTree: untpd.ValOrDefDef)(implicit ctx: Context): Unit = defTree.tpt match {
+ case TypeTree(original) if original.isEmpty =>
+ val resStr = if (defTree.isInstanceOf[untpd.DefDef]) "result " else ""
+ ctx.error(i"${resStr}type of implicit definition needs to be given explicitly", defTree.pos)
+ case _ =>
+ }
+
+ /** Check that a non-implicit parameter making up the first parameter section of an
+ * implicit conversion is not a singleton type.
+ */
+ def checkImplicitParamsNotSingletons(vparamss: List[List[ValDef]])(implicit ctx: Context): Unit = vparamss match {
+ case (vparam :: Nil) :: _ if !(vparam.symbol is Implicit) =>
+ if (vparam.tpt.tpe.isInstanceOf[SingletonType])
+ ctx.error(s"implicit conversion may not have a parameter of singleton type", vparam.tpt.pos)
+ case _ =>
+ }
+
+ /** Check that any top-level type arguments in this type are feasible, i.e. that
+ * their lower bound conforms to their upper cound. If a type argument is
+ * infeasible, issue and error and continue with upper bound.
+ */
+ def checkFeasible(tp: Type, pos: Position, where: => String = "")(implicit ctx: Context): Type = tp match {
+ case tp: RefinedType =>
+ tp.derivedRefinedType(tp.parent, tp.refinedName, checkFeasible(tp.refinedInfo, pos, where))
+ case tp @ TypeBounds(lo, hi) if !(lo <:< hi) =>
+ ctx.error(i"no type exists between low bound $lo and high bound $hi$where", pos)
+ tp.derivedTypeAlias(hi)
+ case _ =>
+ tp
+ }
+
+ /** Check that class does not define */
+ def checkNoDoubleDefs(cls: Symbol)(implicit ctx: Context): Unit = {
+ val seen = new mutable.HashMap[Name, List[Symbol]] {
+ override def default(key: Name) = Nil
+ }
+ typr.println(i"check no double defs $cls")
+ for (decl <- cls.info.decls) {
+ for (other <- seen(decl.name)) {
+ typr.println(i"conflict? $decl $other")
+ if (decl.signature matches other.signature) {
+ def doubleDefError(decl: Symbol, other: Symbol): Unit = {
+ def ofType = if (decl.isType) "" else i": ${other.info}"
+ def explanation =
+ if (!decl.isSourceMethod) ""
+ else "\n (both definitions have the same erased type signature)"
+ ctx.error(i"$decl is already defined as $other$ofType$explanation", decl.pos)
+ }
+ if (decl is Synthetic) doubleDefError(other, decl)
+ else doubleDefError(decl, other)
+ }
+ if ((decl is HasDefaultParams) && (other is HasDefaultParams)) {
+ ctx.error(i"two or more overloaded variants of $decl have default arguments")
+ decl resetFlag HasDefaultParams
+ }
+ }
+ seen(decl.name) = decl :: seen(decl.name)
+ }
+ }
+
+ def checkInstantiatable(cls: ClassSymbol, pos: Position): Unit = {
+ ??? // to be done in later phase: check that class `cls` is legal in a new.
+ }
+} \ No newline at end of file