aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/typer
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2013-07-25 22:16:07 +0200
committerMartin Odersky <odersky@gmail.com>2013-07-25 22:22:42 +0200
commitcf65e84a6da2a151286a36297c057b72545960c8 (patch)
tree55f3d8a30f5751602836d62d0b1a4ae6269b64bd /src/dotty/tools/dotc/typer
parent0a86c0ae8668070f62df25c7a4ba12369f23b216 (diff)
downloaddotty-cf65e84a6da2a151286a36297c057b72545960c8.tar.gz
dotty-cf65e84a6da2a151286a36297c057b72545960c8.tar.bz2
dotty-cf65e84a6da2a151286a36297c057b72545960c8.zip
More typer logic, in particular dealing with variants of applications
Diffstat (limited to 'src/dotty/tools/dotc/typer')
-rw-r--r--src/dotty/tools/dotc/typer/Applications.scala273
-rw-r--r--src/dotty/tools/dotc/typer/ErrorReporting.scala13
-rw-r--r--src/dotty/tools/dotc/typer/Inferencing.scala32
-rw-r--r--src/dotty/tools/dotc/typer/Mode.scala1
-rw-r--r--src/dotty/tools/dotc/typer/Namer.scala2
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala137
6 files changed, 355 insertions, 103 deletions
diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala
index f4b8d8b12..3ce735c12 100644
--- a/src/dotty/tools/dotc/typer/Applications.scala
+++ b/src/dotty/tools/dotc/typer/Applications.scala
@@ -13,7 +13,10 @@ import Denotations._
import NameOps._
import Symbols._
import Types._
+import Typer.TreeDecorator
import Decorators._
+import ErrorReporting._
+import Trees._
import Names._
import StdNames._
import Constants._
@@ -24,6 +27,8 @@ import language.implicitConversions
object Applications {
+ import tpd._
+
private val isNamedArg = (arg: Any) => arg.isInstanceOf[Trees.NamedArg[_]]
def hasNamedArg(args: List[Any]) = args exists isNamedArg
@@ -61,16 +66,18 @@ object Applications {
}
case class FunProtoType(args: List[untpd.Tree], override val resultType: Type, typer: Typer)(implicit ctx: Context) extends UncachedGroundType {
- private var myTypedArgs: List[tpd.Tree] = null
+ private var myTypedArgs: List[Tree] = null
def argsAreTyped: Boolean = myTypedArgs != null
- def typedArgs: List[tpd.Tree] = {
+ def typedArgs: List[Tree] = {
if (myTypedArgs == null)
myTypedArgs = args mapconserve (typer.typed(_))
myTypedArgs
}
}
+
+ case class PolyProtoType(nargs: Int, override val resultType: Type) extends UncachedGroundType
}
import Applications._
@@ -78,7 +85,7 @@ import Applications._
trait Applications extends Compatibility{ self: Typer =>
import Applications._
- import Trees._
+ import tpd._
private def state(implicit ctx: Context) = ctx.typerState
@@ -100,7 +107,7 @@ trait Applications extends Compatibility{ self: Typer =>
protected def typedArg(arg: Arg, formal: Type): TypedArg
/** Turn a typed tree into an argument */
- protected def treeToArg(arg: tpd.Tree): Arg
+ protected def treeToArg(arg: Tree): Arg
/** Check that argument corresponds to type `formal` and
* possibly add it to the list of adapted arguments
@@ -126,7 +133,7 @@ trait Applications extends Compatibility{ self: Typer =>
/** If constructing trees, the current function part, which might be
* affected by lifting. EmptyTree otherwise.
*/
- protected def normalizedFun: tpd.Tree
+ protected def normalizedFun: Tree
/** If constructing trees, pull out all parts of the function
* which are not idempotent into separate prefix definitions
@@ -175,11 +182,11 @@ trait Applications extends Compatibility{ self: Typer =>
private def methString: String = s"method ${methRef.name}: ${methType.show}"
/** Re-order arguments to correctly align named arguments */
- def reorder[T >: Untyped](args: List[Tree[T]]): List[Tree[T]] = {
- var namedToArg: Map[Name, Tree[T]] =
+ def reorder[T >: Untyped](args: List[Trees.Tree[T]]): List[Trees.Tree[T]] = {
+ var namedToArg: Map[Name, Trees.Tree[T]] =
(for (NamedArg(name, arg1) <- args) yield (name, arg1)).toMap
- def badNamedArg(arg: Tree[_ >: Untyped]): Unit = {
+ def badNamedArg(arg: Trees.Tree[_ >: Untyped]): Unit = {
val NamedArg(name, _) = arg
def msg =
if (methodType.paramNames contains name)
@@ -189,7 +196,7 @@ trait Applications extends Compatibility{ self: Typer =>
fail(msg, arg.asInstanceOf[Arg])
}
- def recur(pnames: List[Name], args: List[Tree[T]]): List[Tree[T]] = pnames match {
+ def recur(pnames: List[Name], args: List[Trees.Tree[T]]): List[Trees.Tree[T]] = pnames match {
case pname :: pnames1 =>
namedToArg get pname match {
case Some(arg) =>
@@ -223,9 +230,9 @@ trait Applications extends Compatibility{ self: Typer =>
}
/** Splice new method reference into existing application */
- def spliceMeth(meth: tpd.Tree, app: tpd.Tree): tpd.Tree = app match {
- case Apply(fn, args) => tpd.Apply(spliceMeth(meth, fn), args)
- case TypeApply(fn, targs) => tpd.TypeApply(spliceMeth(meth, fn), targs)
+ def spliceMeth(meth: Tree, app: Tree): Tree = app match {
+ case Apply(fn, args) => Apply(spliceMeth(meth, fn), args)
+ case TypeApply(fn, targs) => TypeApply(spliceMeth(meth, fn), targs)
case _ => meth
}
@@ -285,7 +292,7 @@ trait Applications extends Compatibility{ self: Typer =>
findDefaultGetter(n + TreeInfo.numArgs(normalizedFun)) match {
case dref: NamedType =>
liftFun()
- addTyped(treeToArg(spliceMeth(tpd.Ident(dref), normalizedFun)), formal)
+ addTyped(treeToArg(spliceMeth(Ident(dref), normalizedFun)), formal)
matchArgs(args1, formals1, n + 1)
case _ =>
missingArg(n)
@@ -362,29 +369,29 @@ trait Applications extends Compatibility{ self: Typer =>
ok = false
def fail(msg: => String) =
ok = false
- def normalizedFun = tpd.EmptyTree
+ def normalizedFun = EmptyTree
}
/** Subtrait of Application for the cases where arguments are (typed or
* untyped) trees.
*/
- trait TreeApplication[T >: Untyped] extends Application[Tree[T]] {
- type TypeArg = tpd.Tree
- def isVarArg(arg: Tree[T]): Boolean = TreeInfo.isWildcardStarArg(arg)
+ trait TreeApplication[T >: Untyped] extends Application[Trees.Tree[T]] {
+ type TypeArg = Tree
+ def isVarArg(arg: Trees.Tree[T]): Boolean = TreeInfo.isWildcardStarArg(arg)
}
/** Subclass of Application for applicability tests with trees as arguments. */
- class ApplicableToTrees(methRef: TermRef, args: List[tpd.Tree], resultType: Type)(implicit ctx: Context)
+ class ApplicableToTrees(methRef: TermRef, args: List[Tree], resultType: Type)(implicit ctx: Context)
extends TestApplication(methRef, methRef, args, resultType) with TreeApplication[Type] {
- def argType(arg: tpd.Tree): Type = normalize(arg.tpe)
- def treeToArg(arg: tpd.Tree): tpd.Tree = arg
+ def argType(arg: Tree): Type = normalize(arg.tpe)
+ def treeToArg(arg: Tree): Tree = arg
}
/** Subclass of Application for applicability tests with types as arguments. */
class ApplicableToTypes(methRef: TermRef, args: List[Type], resultType: Type)(implicit ctx: Context)
extends TestApplication(methRef, methRef, args, resultType) {
def argType(arg: Type): Type = arg
- def treeToArg(arg: tpd.Tree): Type = arg.tpe
+ def treeToArg(arg: Tree): Type = arg.tpe
def isVarArg(arg: Type): Boolean = arg.isRepeatedParam
}
@@ -392,24 +399,24 @@ trait Applications extends Compatibility{ self: Typer =>
* types of arguments are either known or unknown.
*/
abstract class TypedApply[T >: Untyped](
- app: untpd.Apply, fun: tpd.Tree, methRef: TermRef, args: List[Tree[T]], resultType: Type)(implicit ctx: Context)
+ app: untpd.Apply, fun: Tree, methRef: TermRef, args: List[Trees.Tree[T]], resultType: Type)(implicit ctx: Context)
extends Application(methRef, fun.tpe, args, resultType) with TreeApplication[T] {
- type TypedArg = tpd.Tree
- private var typedArgBuf = new mutable.ListBuffer[tpd.Tree]
- private var liftedDefs: mutable.ListBuffer[tpd.Tree] = null
- private var myNormalizedFun: tpd.Tree = fun
+ type TypedArg = Tree
+ private var typedArgBuf = new mutable.ListBuffer[Tree]
+ private var liftedDefs: mutable.ListBuffer[Tree] = null
+ private var myNormalizedFun: Tree = fun
- def addArg(arg: tpd.Tree, formal: Type): Unit =
+ def addArg(arg: Tree, formal: Type): Unit =
typedArgBuf += adapt(arg, formal)
def makeVarArg(n: Int, elemFormal: Type): Unit = {
val args = typedArgBuf.takeRight(n).toList
typedArgBuf.trimEnd(n)
val seqType = if (methodType.isJava) defn.ArrayType else defn.SeqType
- typedArgBuf += tpd.SeqLiteral(seqType.appliedTo(elemFormal :: Nil), args)
+ typedArgBuf += SeqLiteral(seqType.appliedTo(elemFormal :: Nil), args)
}
- def fail(msg: => String, arg: Tree[T]) = {
+ def fail(msg: => String, arg: Trees.Tree[T]) = {
ctx.error(msg, arg.pos)
ok = false
}
@@ -423,7 +430,7 @@ trait Applications extends Compatibility{ self: Typer =>
override def liftFun(): Unit =
if (liftedDefs == null) {
- liftedDefs = new mutable.ListBuffer[tpd.Tree]
+ liftedDefs = new mutable.ListBuffer[Tree]
myNormalizedFun = liftApp(liftedDefs, myNormalizedFun)
}
@@ -431,7 +438,7 @@ trait Applications extends Compatibility{ self: Typer =>
* where `EmptyTree`s in the second list are skipped.
* -1 if there are no differences.
*/
- private def firstDiff[T <: Tree[_]](xs: List[T], ys: List[T], n: Int = 0): Int = xs match {
+ private def firstDiff[T <: Trees.Tree[_]](xs: List[T], ys: List[T], n: Int = 0): Int = xs match {
case x :: xs1 =>
ys match {
case EmptyTree :: ys1 => firstDiff(xs1, ys1, n)
@@ -445,53 +452,183 @@ trait Applications extends Compatibility{ self: Typer =>
case nil => -1
}
}
- def sameSeq[T <: Tree[_]](xs: List[T], ys: List[T]): Boolean = firstDiff(xs, ys) < 0
-
- val result: tpd.Tree =
- if (!success) app withType ErrorType
- else {
- var typedArgs = typedArgBuf.toList
- if (!sameSeq(app.args, orderedArgs)) {
- // need to lift arguments to maintain evaluation order in the
- // presence of argument reorderings.
- liftFun()
- val eqSuffixLength = firstDiff(app.args.reverse, orderedArgs.reverse)
- val (liftable, rest) = typedArgs splitAt (typedArgs.length - eqSuffixLength)
- typedArgs = liftArgs(liftedDefs, methType, liftable) ++ rest
+ def sameSeq[T <: Trees.Tree[_]](xs: List[T], ys: List[T]): Boolean = firstDiff(xs, ys) < 0
+
+ val result = {
+ var typedArgs = typedArgBuf.toList
+ val ownType =
+ if (!success) ErrorType
+ else {
+ if (!sameSeq(app.args, orderedArgs)) {
+ // need to lift arguments to maintain evaluation order in the
+ // presence of argument reorderings.
+ liftFun()
+ val eqSuffixLength = firstDiff(app.args.reverse, orderedArgs.reverse)
+ val (liftable, rest) = typedArgs splitAt (typedArgs.length - eqSuffixLength)
+ typedArgs = liftArgs(liftedDefs, methType, liftable) ++ rest
+ }
+ if (sameSeq(typedArgs, args)) // trick to cut down on tree copying
+ typedArgs = args.asInstanceOf[List[Tree]]
+ methodType.instantiate(typedArgs map (_.tpe))
}
- if (sameSeq(typedArgs, args)) // trick to cut down on tree copying
- typedArgs = args.asInstanceOf[List[tpd.Tree]]
- val app1 = app.withType(methodType.instantiate(typedArgs map (_.tpe)))
- .derivedApply(normalizedFun, typedArgs)
- if (liftedDefs != null && liftedDefs.nonEmpty) tpd.Block(liftedDefs.toList, app1)
- else app1
- }
+ val app1 = app.withType(ownType).derivedApply(normalizedFun, typedArgs)
+ if (liftedDefs != null && liftedDefs.nonEmpty) Block(liftedDefs.toList, app1)
+ else app1
+ }
}
/** Subclass of Application for type checking an Apply node with untyped arguments. */
- class ApplyToUntyped(app: untpd.Apply, fun: tpd.Tree, methRef: TermRef, args: List[untpd.Tree], resultType: Type)(implicit ctx: Context)
+ class ApplyToUntyped(app: untpd.Apply, fun: Tree, methRef: TermRef, args: List[untpd.Tree], resultType: Type)(implicit ctx: Context)
extends TypedApply(app, fun, methRef, args, resultType) {
def typedArg(arg: untpd.Tree, formal: Type): TypedArg = typed(arg, formal)
- def treeToArg(arg: tpd.Tree): untpd.Tree = untpd.TypedSplice(arg)
+ def treeToArg(arg: Tree): untpd.Tree = untpd.TypedSplice(arg)
}
/** Subclass of Application for type checking an Apply node with typed arguments. */
- class ApplyToTyped(app: untpd.Apply, fun: tpd.Tree, methRef: TermRef, args: List[tpd.Tree], resultType: Type)(implicit ctx: Context)
+ class ApplyToTyped(app: untpd.Apply, fun: Tree, methRef: TermRef, args: List[Tree], resultType: Type)(implicit ctx: Context)
extends TypedApply(app, fun, methRef, args, resultType) {
- def typedArg(arg: tpd.Tree, formal: Type): TypedArg = arg
- def treeToArg(arg: tpd.Tree): tpd.Tree = arg
+ def typedArg(arg: Tree, formal: Type): TypedArg = arg
+ def treeToArg(arg: Tree): Tree = arg
}
- def typedApply(app: untpd.Apply, fun: tpd.Tree, methRef: TermRef, args: List[tpd.Tree], resultType: Type)(implicit ctx: Context): tpd.Tree =
+ def typedApply(app: untpd.Apply, fun: Tree, methRef: TermRef, args: List[Tree], resultType: Type)(implicit ctx: Context): Tree =
new ApplyToTyped(app, fun, methRef, args, resultType).result
- def typedApply(fun: tpd.Tree, methRef: TermRef, args: List[tpd.Tree], resultType: Type)(implicit ctx: Context): tpd.Tree =
- typedApply(Apply(untpd.TypedSplice(fun), Nil), fun, methRef, args, resultType)
+ def typedApply(fun: Tree, methRef: TermRef, args: List[Tree], resultType: Type)(implicit ctx: Context): Tree =
+ typedApply(Trees.Apply(untpd.TypedSplice(fun), Nil), fun, methRef, args, resultType)
+
+ def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = {
+ if (ctx.mode is Mode.Pattern)
+ typedUnApply(tree.fun, tree.args, tree, pt)
+ else {
+
+ def realApply(implicit ctx: Context) = {
+ val proto = new FunProtoType(tree.args, pt, this)
+ val fun1 = typedExpr(tree.fun, proto)
+ TreeInfo.methPart(fun1).tpe match {
+ case funRef: TermRef =>
+ val app =
+ if (proto.argsAreTyped) new ApplyToTyped(tree, fun1, funRef, proto.typedArgs, pt)
+ else new ApplyToUntyped(tree, fun1, funRef, tree.args, pt)
+ val result = app.result
+ ConstFold(result) orElse result
+ case _ =>
+ fun1.exprType match {
+ case ErrorType =>
+ tree.withType(ErrorType)
+ }
+ }
+ }
+
+ def typedOpAssign: Tree = {
+ val Apply(Select(lhs, name), rhss) = tree
+ val lhs1 = typedExpr(lhs)
+ val lifted = new mutable.ListBuffer[Tree]
+ val lhs2 = untpd.TypedSplice(liftApp(lifted, lhs1))
+ val assign = Trees.Assign(lhs2, Trees.Apply(Trees.Select(lhs2, name.init), rhss))
+ typed(assign)
+ }
+
+ realApply
+ if (TreeInfo.isOpAssign(tree))
+ tryEither {
+ implicit ctx => realApply
+ } { failed =>
+ tryEither {
+ implicit ctx => typedOpAssign
+ } { _ =>
+ failed.commit()
+ }
+ }
+ else realApply
+ }
+ }
+
+ def typedTypeApply(tree: untpd.TypeApply, pt: Type)(implicit ctx: Context): Tree = {
+ val typedFn = typedExpr(tree.fun, PolyProtoType(tree.args.length, pt))
+ val typedArgs = tree.args map (typedType(_))
+ val ownType = typedFn.tpe.widen match {
+ case pt: PolyType =>
+ checkBounds(typedArgs, pt, tree.pos)
+ pt.resultType.substParams(pt, typedArgs map (_.tpe))
+ case _ =>
+ ctx.error(s"${err.exprStr(typedFn)} does not take type parameters", tree.pos)
+ ErrorType
+ }
+ tree.withType(ownType).derivedTypeApply(typedFn, typedArgs)
+ }
+
+ def typedUnApply(qual: untpd.Tree, args: List[untpd.Tree], tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = {
+
+ def unapplyArgs(unapplyResult: Type)(implicit ctx: Context): List[Type] = {
+ def recur(tp: Type): List[Type] = {
+ def nonOverloadedMember(name: Name) = {
+ val ref = tp member name
+ if (ref.isOverloaded) {
+ errorType(s"Overloaded reference to $ref is not allowed in extractor", tree.pos)
+ }
+ else
+ ref.info
+ }
+
+ def productSelectors: List[Type] = {
+ val sels = for (n <- Iterator.from(0)) yield nonOverloadedMember(("_" + n).toTermName)
+ sels.takeWhile(_.exists).toList
+ }
+ def seqSelector = defn.RepeatedParamType.appliedTo(tp.elemType :: Nil)
+
+ if (tp derivesFrom defn.ProductClass) productSelectors
+ else if (tp derivesFrom defn.SeqClass) seqSelector :: Nil
+ else if (tp.typeSymbol == defn.BooleanClass) Nil
+ else if (nonOverloadedMember(nme.isDefined).exists &&
+ nonOverloadedMember(nme.get).exists) recur(nonOverloadedMember(nme.get))
+ else {
+ ctx.error(s"${unapplyResult.show} is not a valid result type of an unapply method of an extractor", tree.pos)
+ Nil
+ }
+ }
+
+ recur(unapplyResult)
+ }
+
+ val fn = {
+ val dummyArg = untpd.TypedSplice(dummyTreeOfType(WildcardType))
+ val unappProto = FunProtoType(dummyArg :: Nil, pt, this)
+ tryEither {
+ implicit ctx => typedExpr(Trees.Select(qual, nme.unapply), unappProto)
+ } {
+ s => tryEither {
+ implicit ctx => typedExpr(Trees.Select(qual, nme.unapplySeq), unappProto) // for backwards compatibility; will be dropped
+ } {
+ _ => errorTree(s.value, s"${qual.show} cannot be used as an extractor in a pattern because it lacks an unapply or unapplySeq method")
+ }
+ }
+ }
+ fn.tpe.widen match {
+ case mt: MethodType =>
+ val ownType = mt.resultType
+ ownType <:< pt // done for registering the constraints; error message would come later
+ var argTypes = unapplyArgs(ownType)
+ val bunchedArgs = argTypes match {
+ case argType :: Nil if argType.isRepeatedParam => Trees.SeqLiteral(args) :: Nil
+ case _ => args
+ }
+ if (argTypes.length != bunchedArgs.length) {
+ ctx.error(s"wrong number of argument patterns for ${err.patternConstrStr(fn)}", tree.pos)
+ argTypes = argTypes.take(args.length) ++
+ List.fill(argTypes.length - args.length)(WildcardType)
+ }
+ val typedArgs = (bunchedArgs, argTypes).zipped map (typed(_, _))
+ Trees.UnApply(fn, typedArgs).withPos(tree.pos).withType(ownType)
+ case et: ErrorType =>
+ tree.withType(ErrorType)
+ }
+ }
/** Is given method reference applicable to argument types `args`?
* @param resultType The expected result type of the application
*/
- def isApplicableToTrees(methRef: TermRef, args: List[tpd.Tree], resultType: Type)(implicit ctx: Context) =
+ def isApplicableToTrees(methRef: TermRef, args: List[Tree], resultType: Type)(implicit ctx: Context) =
new ApplicableToTrees(methRef, args, resultType)(ctx.fresh.withNewTyperState).success
/** Is given method reference applicable to arguments `args`?
@@ -576,8 +713,8 @@ trait Applications extends Compatibility{ self: Typer =>
best :: asGood(alts1)
}
- private val dummyTree = Literal(Constant(null))
- def dummyTreeOfType(tp: Type): tpd.Tree = dummyTree withType tp
+ private val dummyTree = Trees.Literal(Constant(null))
+ def dummyTreeOfType(tp: Type): Tree = dummyTree withType tp
/** Resolve overloaded alternative `alts`, given expected type `pt`. */
def resolveOverloaded(alts: List[TermRef], pt: Type)(implicit ctx: Context): List[TermRef] = {
@@ -595,7 +732,7 @@ trait Applications extends Compatibility{ self: Typer =>
/** The shape of given tree as a type; is more expensive than
* typeShape but can can handle named arguments.
*/
- def treeShape(tree: untpd.Tree): tpd.Tree = tree match {
+ def treeShape(tree: untpd.Tree): Tree = tree match {
case NamedArg(name, arg) =>
val argShape = treeShape(arg)
tree.withType(argShape.tpe).derivedNamedArg(name, argShape)
@@ -627,14 +764,14 @@ trait Applications extends Compatibility{ self: Typer =>
def narrowByShapes(alts: List[TermRef]): List[TermRef] =
if (args exists (_.isInstanceOf[untpd.Function]))
- if (args exists (_.isInstanceOf[NamedArg[_]]))
+ if (args exists (_.isInstanceOf[Trees.NamedArg[_]]))
narrowByTrees(alts, args map treeShape, resultType)
else
narrowByTypes(alts, args map typeShape, resultType)
else
alts
- def narrowByTrees(alts: List[TermRef], args: List[tpd.Tree], resultType: Type): List[TermRef] =
+ def narrowByTrees(alts: List[TermRef], args: List[Tree], resultType: Type): List[TermRef] =
alts filter (isApplicableToTrees(_, args, resultType))
val alts1 = narrowBySize(alts)
@@ -645,6 +782,12 @@ trait Applications extends Compatibility{ self: Typer =>
else narrowByTrees(alts2, pt.typedArgs, resultType)
}
+ case pt @ PolyProtoType(nargs, _) =>
+ alts filter ( alt => alt.widen match {
+ case PolyType(pnames) if pnames.length == nargs => true
+ case _ => false
+ })
+
case defn.FunctionType(args, resultType) =>
narrowByTypes(alts, args, resultType)
diff --git a/src/dotty/tools/dotc/typer/ErrorReporting.scala b/src/dotty/tools/dotc/typer/ErrorReporting.scala
index ef6184394..e0ff8e351 100644
--- a/src/dotty/tools/dotc/typer/ErrorReporting.scala
+++ b/src/dotty/tools/dotc/typer/ErrorReporting.scala
@@ -13,9 +13,12 @@ object ErrorReporting {
import tpd._
- def errorTree(tree: Trees.Tree[_], msg: => String)(implicit ctx: Context): tpd.Tree = {
- ctx.error(msg, tree.pos)
- tree withType ErrorType
+ def errorTree(tree: Tree, msg: => String)(implicit ctx: Context): tpd.Tree =
+ tree withType errorType(msg, tree.pos)
+
+ def errorType(msg: => String, pos: Position)(implicit ctx: Context): ErrorType = {
+ ctx.error(msg, pos)
+ ErrorType
}
class Errors(implicit ctx: Context) {
@@ -54,6 +57,10 @@ object ErrorReporting {
case _ => anonymousTypeMemberStr(tp)
}
+ def exprStr(tree: Tree): String = refStr(tree.tpe)
+
+ def patternConstrStr(tree: Tree): String = ???
+
def typeMismatch(tree: Tree, pt: Type): Tree =
errorTree(tree,
s"""type mismatch:
diff --git a/src/dotty/tools/dotc/typer/Inferencing.scala b/src/dotty/tools/dotc/typer/Inferencing.scala
index 9d244ea3e..1ae33d87a 100644
--- a/src/dotty/tools/dotc/typer/Inferencing.scala
+++ b/src/dotty/tools/dotc/typer/Inferencing.scala
@@ -3,11 +3,42 @@ package dotc
package typer
import core._
+import ast._
import Contexts._, Types._, Flags._, Denotations._, NameOps._, Symbols._
+import Trees._
import annotation.unchecked
+import util.Positions._
+import Decorators._
object Inferencing {
+ import tpd._
+
+ def checkBounds(args: List[Tree], poly: PolyType, pos: Position)(implicit ctx: Context): Unit = {
+
+ }
+
+ def checkStable(tp: Type, pos: Position)(implicit ctx: Context): Unit = {
+ if (!tp.isStable)
+ ctx.error(s"Prefix ${tp.show} is not stable", pos)
+ tp
+ }
+
+ def checkClassTypeWithStablePrefix(tp: Type, pos: Position)(implicit ctx: Context): ClassSymbol = tp.dealias match {
+ case tp: TypeRef if tp.symbol.isClass =>
+ checkStable(tp.prefix, pos)
+ tp.symbol.asClass
+ case _: RefinedType | _: TypeVar | _: AnnotatedType =>
+ checkClassTypeWithStablePrefix(tp.asInstanceOf[TypeProxy].underlying, pos)
+ case _ =>
+ ctx.error(s"${tp.show} is not a class type", pos)
+ defn.ObjectClass
+ }
+
+ def checkInstantiatable(cls: ClassSymbol, pos: Position): Unit = {
+ ???
+ }
+
implicit class Infer(val ictx: Context) extends AnyVal {
implicit private def ctx = ictx
@@ -68,6 +99,7 @@ object Inferencing {
case nil =>
actuals.isEmpty
}
+
/* not needed right now
def formalParameters[T](mtp: MethodType, actuals: List[T])(isRepeated: T => Boolean)(implicit ctx: Context) =
if (mtp.isVarArgs && !(actuals.nonEmpty && isRepeated(actuals.last))) {
diff --git a/src/dotty/tools/dotc/typer/Mode.scala b/src/dotty/tools/dotc/typer/Mode.scala
index d71c0c020..fe2692a88 100644
--- a/src/dotty/tools/dotc/typer/Mode.scala
+++ b/src/dotty/tools/dotc/typer/Mode.scala
@@ -30,6 +30,7 @@ object Mode {
val Type = newMode(1, "Type")
val ImplicitsDisabled = newMode(2, "ImplicitsDisabled")
+ val InSuperInit = newMode(3, "inSuperInit")
val PatternOrType = Pattern | Type
} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala
index 0b6aa3c9e..1279fcf03 100644
--- a/src/dotty/tools/dotc/typer/Namer.scala
+++ b/src/dotty/tools/dotc/typer/Namer.scala
@@ -211,7 +211,7 @@ class Namer { typer: Typer =>
else typeDefSig(tree, sym)(localContext.withNewScope)
case imp: Import =>
val expr1 = typedAheadExpr(imp.expr)
- ImportType(SharedTree(expr1))
+ ImportType(tpd.SharedTree(expr1))
}
sym.info = typeSig(original)
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index f99c08ecb..6d6211daf 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -9,7 +9,7 @@ import Constants._
import StdNames._
import Scopes._
import Denotations._
-import Inferencing.Infer
+import Inferencing._
import Contexts._
import Symbols._
import Types._
@@ -19,7 +19,7 @@ import NameOps._
import Flags._
import Decorators._
import ErrorReporting._
-import Applications.FunProtoType
+import Applications.{FunProtoType, PolyProtoType}
import EtaExpansion.etaExpand
import util.Positions._
import util.SourcePosition
@@ -31,6 +31,8 @@ trait TyperContextOps { ctx: Context => }
object Typer {
+ import tpd._
+
object BindingPrec {
val definition = 4
val namedImport = 3
@@ -40,12 +42,19 @@ object Typer {
def isImportPrec(prec: Int) = prec == namedImport || prec == wildImport
}
- implicit class TreeDecorator(tree: tpd.Tree) {
+ implicit class TreeDecorator(tree: Tree) {
def exprType(implicit ctx: Context): Type = tree.tpe match {
case tpe: TermRef if !tpe.symbol.isStable => tpe.info
case tpe => tpe
}
}
+
+ case class StateFul[T](value: T, state: TyperState) {
+ def commit()(implicit ctx: Context): T = {
+ state.commit()
+ value
+ }
+ }
}
class Typer extends Namer with Applications with Implicits {
@@ -60,11 +69,15 @@ class Typer extends Namer with Applications with Implicits {
private var importedFromRoot: Set[Symbol] = Set()
def typedSelection(site: Type, name: Name, pos: Position)(implicit ctx: Context): Type = {
- val ref = site.member(name)
+ val ref =
+ if (name == nme.CONSTRUCTOR) site.decl(name)
+ else site.member(name)
if (ref.exists) NamedType(site, name).withDenot(ref)
else {
if (!site.isErroneous)
- ctx.error(s"$name is not a member of ${site.show}", pos)
+ ctx.error(
+ if (name == nme.CONSTRUCTOR) s"${site.show} does not have a constructor"
+ else s"$name is not a member of ${site.show}", pos)
ErrorType
}
}
@@ -95,6 +108,21 @@ class Typer extends Namer with Applications with Implicits {
tpe
}
+ /** The qualifying class
+ * of a this or super with prefix `qual`.
+ * packageOk is equal false when qualifying class symbol
+ */
+ def qualifyingClass(tree: untpd.Tree, qual: Name, packageOK: Boolean)(implicit ctx: Context): Symbol =
+ ctx.owner.enclosingClass.ownersIterator.find(o => qual.isEmpty || o.isClass && o.name == qual) match {
+ case Some(c) if packageOK || !(c is Package) =>
+ c
+ case _ =>
+ ctx.error(
+ if (qual.isEmpty) tree.show + " can be used only in a class, object, or template"
+ else qual.show + " is not an enclosing class", tree.pos)
+ NoSymbol
+ }
+
/** Attribute an identifier consisting of a simple name or an outer reference.
*
* @param tree The tree representing the identifier.
@@ -258,7 +286,7 @@ class Typer extends Namer with Applications with Implicits {
val rawType =
try findRef(NoType, BindingPrec.nothingBound, NoContext)
finally importedFromRoot = saved
-
+
val ownType =
if (rawType.exists) checkAccessible(rawType, superAccess = false, tree.pos)
else {
@@ -275,21 +303,61 @@ class Typer extends Namer with Applications with Implicits {
tree.withType(ownType).derivedSelect(qual1, tree.name)
}
- def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = {
- val proto = new FunProtoType(tree.args, pt, this)
- val fun1 = typedExpr(tree.fun, proto)
- TreeInfo.methPart(fun1).tpe match {
- case funRef: TermRef =>
- val app =
- if (proto.argsAreTyped) new ApplyToTyped(tree, fun1, funRef, proto.typedArgs, pt)
- else new ApplyToUntyped(tree, fun1, funRef, tree.args, pt)
- app.result
- case _ =>
- fun1.exprType match {
- case ErrorType =>
- tree.withType(ErrorType)
- }
+ def typedThis(tree: untpd.This)(implicit ctx: Context): Tree = {
+ val cls = qualifyingClass(tree, tree.qual, packageOK = false)
+ tree.withType(cls.thisType)
+ }
+
+ def typedSuper(tree: untpd.Super)(implicit ctx: Context): Tree = {
+ val mix = tree.mix
+ val qual1 = typed(tree.qual)
+ val cls = qual1.tpe.typeSymbol
+
+ def findMixinSuper(site: Type): Type = site.parents filter (_.name == mix) match {
+ case p :: Nil =>
+ p
+ case Nil =>
+ errorType(s"$mix does not name a parent class of $cls", tree.pos)
+ case p :: q :: _ =>
+ errorType(s"ambiguous parent class qualifier", tree.pos)
}
+ val owntype =
+ if (!mix.isEmpty) findMixinSuper(cls.info)
+ else if (ctx.mode is Mode.InSuperInit) cls.info.firstParent
+ else cls.info.parents.reduceLeft((x: Type, y: Type) => AndType(x, y))
+
+ tree.withType(SuperType(cls.thisType, owntype)).derivedSuper(qual1, mix)
+ }
+
+ def typedLiteral(tree: untpd.Literal)(implicit ctx: Context) =
+ tree.withType(if (tree.const.tag == UnitTag) defn.UnitType else ConstantType(tree.const))
+
+ def typedNew(tree: untpd.New)(implicit ctx: Context) = {
+ val tpt1 = typedType(tree.tpt)
+ val cls = checkClassTypeWithStablePrefix(tpt1.tpe, tpt1.pos)
+ checkInstantiatable(cls, tpt1.pos)
+ tree.withType(tpt1.tpe).derivedNew(tpt1)
+ }
+
+ def typedPair(tree: untpd.Pair)(implicit ctx: Context) = {
+ val left1 = typed(tree.left)
+ val right1 = typed(tree.right)
+ tree.withType(defn.PairType.appliedTo(left1.tpe :: right1.tpe :: Nil)).derivedPair(left1, right1)
+ }
+
+ def TypedTyped(tree: untpd.Typed)(implicit ctx: Context) = {
+ val tpt1 = typedType(tree.tpt)
+ val expr1 = typedExpr(tree.expr, tpt1.tpe)
+ tree.withType(tpt1.tpe).derivedTyped(tpt1, expr1)
+ }
+
+ def NamedArg(tree: untpd.NamedArg, pt: Type)(implicit ctx: Context) = {
+ val arg1 = typed(tree.arg, pt)
+ tree.withType(arg1.tpe).derivedNamedArg(tree.name, arg1)
+ }
+
+ def Assign(tree: untpd.Assign)(implicit ctx: Context) = {
+ ???
}
def typedModifiers(mods: untpd.Modifiers)(implicit ctx: Context): Modifiers = {
@@ -428,29 +496,24 @@ class Typer extends Namer with Applications with Implicits {
def typedPattern(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree =
typed(tree, pt)(ctx addMode Mode.Pattern)
- def tryEither[T](op: Context => T)(fallBack: => T)(implicit ctx: Context) = {
+ def tryEither[T](op: Context => T)(fallBack: StateFul[T] => T)(implicit ctx: Context) = {
val nestedCtx = ctx.fresh.withNewTyperState
val result = op(nestedCtx)
if (nestedCtx.reporter.hasErrors)
- fallBack
+ fallBack(StateFul(result, nestedCtx.typerState))
else {
nestedCtx.typerState.commit()
result
}
}
- def tryInsertApply(tree: Tree, pt: Type)(fallBack: => Tree)(implicit ctx: Context): Tree =
+ def tryInsertApply(tree: Tree, pt: Type)(fallBack: StateFul[Tree] => Tree)(implicit ctx: Context): Tree =
tryEither {
implicit ctx => typedSelect(Trees.Select(untpd.TypedSplice(tree), nme.apply), pt)
} {
fallBack
}
- def tryInsertApplyIfFunProto(tree: Tree, pt: Type)(fallBack: => Tree)(implicit ctx: Context): Tree = pt match {
- case pt: FunProtoType => tryInsertApply(tree, pt)(fallBack)
- case _ => fallBack
- }
-
/**
* (-1) For expressions with annotated types, let AnnotationCheckers decide what to do
* (0) Convert expressions with constant types to literals (unless in interactive/scaladoc mode)
@@ -501,10 +564,13 @@ class Typer extends Namer with Applications with Implicits {
case alt :: Nil =>
adapt(tree.withType(alt), pt)
case Nil =>
- tryInsertApplyIfFunProto(tree, pt) {
+ def noMatches =
errorTree(tree,
s"""none of the ${err.overloadedAltsStr(altDenots)}
|match $expectedStr""".stripMargin)
+ pt match {
+ case pt: FunProtoType => tryInsertApply(tree, pt)(_ => noMatches)
+ case _ => noMatches
}
case alts =>
errorTree(tree,
@@ -521,7 +587,7 @@ class Typer extends Namer with Applications with Implicits {
case Apply(_, _) => " more"
case _ => ""
}
- errorTree(tree, s"$fn does not take$more parameters")
+ _ => errorTree(tree, s"$fn does not take$more parameters")
}
}
@@ -559,10 +625,13 @@ class Typer extends Namer with Applications with Implicits {
tree.tpe.widen match {
case ref: TermRef =>
adaptOverloaded(ref)
- case pt: PolyType =>
- val tracked = ctx.track(pt)
- val tvars = ctx.newTypeVars(tracked)
- adapt(tpd.TypeApply(tree, tvars map (tpd.TypeTree(_))), pt)
+ case poly: PolyType =>
+ if (pt.isInstanceOf[PolyProtoType]) tree
+ else {
+ val tracked = ctx.track(poly)
+ val tvars = ctx.newTypeVars(tracked)
+ adapt(tpd.TypeApply(tree, tvars map (tpd.TypeTree(_))), pt)
+ }
case tp =>
pt match {
case pt: FunProtoType => adaptToArgs(tp, pt)