aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/typer/Checking.scala
diff options
context:
space:
mode:
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