aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/typer/Typer.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2013-08-01 18:21:23 +0200
committerMartin Odersky <odersky@gmail.com>2013-08-01 18:21:23 +0200
commitdbb4b3f7923427af4ba6e04f258309421d5ee1ab (patch)
treec8d47cbae32a0778d0bff3a22117d9d4a7c5ff7f /src/dotty/tools/dotc/typer/Typer.scala
parent413f364887d5bde7610adbbc08020e23470b4c8c (diff)
downloaddotty-dbb4b3f7923427af4ba6e04f258309421d5ee1ab.tar.gz
dotty-dbb4b3f7923427af4ba6e04f258309421d5ee1ab.tar.bz2
dotty-dbb4b3f7923427af4ba6e04f258309421d5ee1ab.zip
Handling typevars in inference.
Fleshed out handling of typevars for type inference. Also added some more methods to typer, for blocks, ifs and assignments. (Closures are still wip).
Diffstat (limited to 'src/dotty/tools/dotc/typer/Typer.scala')
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala177
1 files changed, 132 insertions, 45 deletions
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index 733eac739..ffd4b2ce1 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -346,21 +346,106 @@ class Typer extends Namer with Applications with Implicits {
cpy.Pair(tree, left1, right1).withType(defn.PairType.appliedTo(left1.tpe :: right1.tpe :: Nil))
}
- def TypedTyped(tree: untpd.Typed)(implicit ctx: Context) = {
+ def typedTyped(tree: untpd.Typed)(implicit ctx: Context) = {
val tpt1 = typedType(tree.tpt)
val expr1 = typedExpr(tree.expr, tpt1.tpe)
cpy.Typed(tree, tpt1, expr1).withType(tpt1.tpe)
}
- def NamedArg(tree: untpd.NamedArg, pt: Type)(implicit ctx: Context) = {
+ def typedNamedArg(tree: untpd.NamedArg, pt: Type)(implicit ctx: Context) = {
val arg1 = typed(tree.arg, pt)
cpy.NamedArg(tree, tree.name, arg1).withType(arg1.tpe)
}
- def Assign(tree: untpd.Assign)(implicit ctx: Context) = {
+ def typedAssign(tree: untpd.Assign)(implicit ctx: Context) = tree.lhs match {
+ case lhs @ Apply(fn, args) =>
+ typed(cpy.Apply(lhs, untpd.Select(fn, nme.update), args :+ tree.rhs))
+ case lhs =>
+ val lhs1 = typed(lhs)
+ def reassignmentToVal =
+ errorTree(cpy.Assign(tree, lhs1, typed(tree.rhs, lhs1.tpe.widen)),
+ "reassignment to val")
+ lhs1.tpe match {
+ case ref: TermRef if ref.symbol is Mutable =>
+ cpy.Assign(tree, lhs1, typed(tree.rhs, ref.info)).withType(defn.UnitType)
+ case ref: TermRef if ref.info.isParameterless =>
+ val pre = ref.prefix
+ val setterName = ref.name.getterToSetter
+ val setter = pre.member(setterName)
+ lhs1 match {
+ case lhs1: RefTree if setter.exists =>
+ val setterTypeRaw = TermRef(pre, setterName).withDenot(setter)
+ val setterType = checkAccessible(setterTypeRaw, isSuperSelection(tree), tree.pos)
+ val lhs2 = lhs1.withName(setterName).withType(setterType)
+ typed(cpy.Apply(tree, untpd.TypedSplice(lhs2), tree.rhs :: Nil))
+ case _ =>
+ reassignmentToVal
+ }
+ case _ =>
+ reassignmentToVal
+ }
+ }
+
+ def typedBlock(tree: Block, pt: Type)(implicit ctx: Context) = {
+ val exprCtx = enterSyms(tree.stats)
+ val stats1 = typedStats(tree.stats, ctx.owner)
+ val expr1 = typedExpr(tree.expr, pt)(exprCtx)
+ val result = cpy.Block(tree, stats1, expr1).withType(blockType(stats1, expr1.tpe))
+ val leaks = CheckTrees.escapingRefs(result)
+ if (leaks.isEmpty) result
+ else if (isFullyDefined(pt)) {
+ val expr2 = typed(untpd.Typed(untpd.TypedSplice(expr1), untpd.TypeTree(pt)))
+ untpd.Block(stats1, expr2) withType expr2.tpe
+ } else errorTree(result,
+ s"local definition of ${leaks.head.name} escapes as part of block's type ${result.tpe.show}")
+ }
+
+ def typedIf(tree: untpd.If, pt: Type)(implicit ctx: Context) = {
+ val cond1 = typed(tree.cond, defn.BooleanType)
+ val thenp1 = typed(tree.thenp, pt)
+ val elsep1 = typed(tree.elsep, pt)
+ cpy.If(tree, cond1, thenp1, elsep1).withType(thenp1.tpe | elsep1.tpe)
+ }
+
+ def typedFunction(tree: untpd.Function, pt: Type)(implicit ctx: Context) = {
+ val params = tree.args.asInstanceOf[List[ValDef]]
+ val protoFormals: List[Type] = pt match {
+ case _ if pt.typeSymbol == defn.FunctionClass(params.length) =>
+ pt.typeArgs take params.length
+ case MethodType(_, paramTypes) =>
+ paramTypes
+ case _ =>
+ params map Function.const(WildcardType)
+ }
+ val inferredParams =
+ for ((param, formal) <- (params, protoFormals).zipped)
+ if (param.tpt.isEmpty && isFullyDefined(formal))
+ cpy.ValDef(param, param.mods, param.name, untpd.TypeTree(formal), param.rhs)
+ else
+ param
+
???
}
+ def typedClosure(tree: untpd.Closure, pt: Type)(implicit ctx: Context) = {
+ val env1 = tree.env map (typed(_))
+ val meth1 = typed(tree.meth)
+ pt match {
+ case SAMType(meth) if !defn.isFunctionType(pt) =>
+ ???
+ case _ =>
+ val ownType = meth1.tpe.widen match {
+ case mt: MethodType if !mt.isDependent =>
+ closureType(mt)
+ case mt: MethodType =>
+ errorType(s"cannot turn dependent method types into closures", tree.pos)
+ case tp =>
+ errorType(s"internal error: closing over non-method $tp", tree.pos)
+ }
+ cpy.Closure(tree, env1, meth1).withType(ownType)
+ }
+ }
+
def typedModifiers(mods: untpd.Modifiers)(implicit ctx: Context): Modifiers = {
val annotations1 = mods.annotations mapconserve typedAnnotation
if (annotations1 eq mods.annotations) mods.asInstanceOf[Modifiers]
@@ -464,8 +549,10 @@ class Typer extends Namer with Applications with Implicits {
case none => tree
}
case _ => tree
- }
- typedExpanded(xtree, pt)
+ }
+ val tree1 = typedExpanded(xtree, pt)
+ ctx.interpolateUndetVars(tree1.tpe.widen, tree1.pos)
+ adapt(tree1, pt)
}
def typedTrees(trees: List[untpd.Tree])(implicit ctx: Context): List[Tree] =
@@ -482,7 +569,8 @@ class Typer extends Namer with Applications with Implicits {
buf += typed(mdef)
traverse(rest)
case stat :: rest =>
- buf += typed(stat)(ctx.fresh.withOwner(exprOwner))
+ val nestedCtx = if (exprOwner == ctx.owner) ctx else ctx.fresh.withOwner(exprOwner)
+ buf += typed(stat)(nestedCtx)
traverse(rest)
case _ =>
buf.toList
@@ -515,45 +603,44 @@ class Typer extends Namer with Applications with Implicits {
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)
- */
+ /** (-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)
+ */
- /** Perform the following adaptations of expression, pattern or type `tree` wrt to
- * given prototype `pt`:
- * (1) Resolve overloading
- * (2) Apply parameterless functions
- * (3) Apply polymorphic types to fresh instances of their type parameters and
- * store these instances in context.undetparams,
- * unless followed by explicit type application.
- * (4) Do the following to unapplied methods used as values:
- * (4.1) If the method has only implicit parameters pass implicit arguments
- * (4.2) otherwise, if `pt` is a function type and method is not a constructor,
- * convert to function by eta-expansion,
- * (4.3) otherwise, if the method is nullary with a result type compatible to `pt`
- * and it is not a constructor, apply it to ()
- * otherwise issue an error
- * (5) Convert constructors in a pattern as follows:
- * (5.1) If constructor refers to a case class factory, set tree's type to the unique
- * instance of its primary constructor that is a subtype of the expected type.
- * (5.2) If constructor refers to an extractor, convert to application of
- * unapply or unapplySeq method.
- *
- * (6) Convert all other types to TypeTree nodes.
- * (7) When in TYPEmode but not FUNmode or HKmode, check that types are fully parameterized
- * (7.1) In HKmode, higher-kinded types are allowed, but they must have the expected kind-arity
- * (8) When in both EXPRmode and FUNmode, add apply method calls to values of object type.
- * (9) If there are undetermined type variables and not POLYmode, infer expression instance
- * Then, if tree's type is not a subtype of expected type, try the following adaptations:
- * (10) If the expected type is Byte, Short or Char, and the expression
- * is an integer fitting in the range of that type, convert it to that type.
- * (11) Widen numeric literals to their expected type, if necessary
- * (12) When in mode EXPRmode, convert E to { E; () } if expected type is scala.Unit.
- * (13) When in mode EXPRmode, apply AnnotationChecker conversion if expected type is annotated.
- * (14) When in mode EXPRmode, apply a view
- * If all this fails, error
- */
+ /** Perform the following adaptations of expression, pattern or type `tree` wrt to
+ * given prototype `pt`:
+ * (1) Resolve overloading
+ * (2) Apply parameterless functions
+ * (3) Apply polymorphic types to fresh instances of their type parameters and
+ * store these instances in context.undetparams,
+ * unless followed by explicit type application.
+ * (4) Do the following to unapplied methods used as values:
+ * (4.1) If the method has only implicit parameters pass implicit arguments
+ * (4.2) otherwise, if `pt` is a function type and method is not a constructor,
+ * convert to function by eta-expansion,
+ * (4.3) otherwise, if the method is nullary with a result type compatible to `pt`
+ * and it is not a constructor, apply it to ()
+ * otherwise issue an error
+ * (5) Convert constructors in a pattern as follows:
+ * (5.1) If constructor refers to a case class factory, set tree's type to the unique
+ * instance of its primary constructor that is a subtype of the expected type.
+ * (5.2) If constructor refers to an extractor, convert to application of
+ * unapply or unapplySeq method.
+ *
+ * (6) Convert all other types to TypeTree nodes.
+ * (7) When in TYPEmode but not FUNmode or HKmode, check that types are fully parameterized
+ * (7.1) In HKmode, higher-kinded types are allowed, but they must have the expected kind-arity
+ * (8) When in both EXPRmode and FUNmode, add apply method calls to values of object type.
+ * (9) If there are undetermined type variables and not POLYmode, infer expression instance
+ * Then, if tree's type is not a subtype of expected type, try the following adaptations:
+ * (10) If the expected type is Byte, Short or Char, and the expression
+ * is an integer fitting in the range of that type, convert it to that type.
+ * (11) Widen numeric literals to their expected type, if necessary
+ * (12) When in mode EXPRmode, convert E to { E; () } if expected type is scala.Unit.
+ * (13) When in mode EXPRmode, apply AnnotationChecker conversion if expected type is annotated.
+ * (14) When in mode EXPRmode, apply a view
+ * If all this fails, error
+ */
def adapt(tree: Tree, pt: Type)(implicit ctx: Context): Tree = {
def adaptOverloaded(ref: TermRef) = {
@@ -630,7 +717,7 @@ class Typer extends Namer with Applications with Implicits {
if (pt.isInstanceOf[PolyProtoType]) tree
else {
val tracked = ctx.track(poly)
- val tvars = ctx.newTypeVars(tracked)
+ val tvars = ctx.newTypeVars(tracked, tree.pos)
adapt(tpd.TypeApply(tree, tvars map (tpd.TypeTree(_))), pt)
}
case tp =>