aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2013-08-27 14:12:31 +0200
committerMartin Odersky <odersky@gmail.com>2013-08-27 14:12:41 +0200
commite2a05a5ac38647f9727d1e0ec8c3c14ac82b5de7 (patch)
tree78b7e72faf3fd4478c82048c4f65f2528684525e
parenteab2123cd727fad2e0139e63edacfff7307d49f0 (diff)
downloaddotty-e2a05a5ac38647f9727d1e0ec8c3c14ac82b5de7.tar.gz
dotty-e2a05a5ac38647f9727d1e0ec8c3c14ac82b5de7.tar.bz2
dotty-e2a05a5ac38647f9727d1e0ec8c3c14ac82b5de7.zip
Fixed bugs related to typechecking closures.
-rw-r--r--src/dotty/tools/dotc/Main.scala2
-rw-r--r--src/dotty/tools/dotc/ast/Desugar.scala5
-rw-r--r--src/dotty/tools/dotc/ast/Trees.scala4
-rw-r--r--src/dotty/tools/dotc/core/TypeComparer.scala2
-rw-r--r--src/dotty/tools/dotc/printing/RefinedPrinter.scala4
-rw-r--r--src/dotty/tools/dotc/typer/Inferencing.scala13
-rw-r--r--src/dotty/tools/dotc/typer/Namer.scala4
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala13
-rw-r--r--tests/pos/functions1.scala13
-rw-r--r--tests/pos/implicits1.scala16
10 files changed, 57 insertions, 19 deletions
diff --git a/src/dotty/tools/dotc/Main.scala b/src/dotty/tools/dotc/Main.scala
index fb2733c27..9fe580b8a 100644
--- a/src/dotty/tools/dotc/Main.scala
+++ b/src/dotty/tools/dotc/Main.scala
@@ -17,7 +17,7 @@ object Main extends Driver {
override def newCompiler(): Compiler = new Compiler
override def doCompile(compiler: Compiler, fileNames: List[String])(implicit ctx: Context): Unit = {
- if (new config.Settings.Setting.SettingDecorator(ctx.base.settings.resident).value) resident(compiler)
+ if (new config.Settings.Setting.SettingDecorator(ctx.base.settings.resident).value(ctx)) resident(compiler)
else super.doCompile(compiler, fileNames)
}
}
diff --git a/src/dotty/tools/dotc/ast/Desugar.scala b/src/dotty/tools/dotc/ast/Desugar.scala
index 52c9cd187..f998ddec2 100644
--- a/src/dotty/tools/dotc/ast/Desugar.scala
+++ b/src/dotty/tools/dotc/ast/Desugar.scala
@@ -285,7 +285,7 @@ object desugar {
/** Make closure corresponding to function params => body */
def makeClosure(params: List[ValDef], body: Tree) =
Block(
- DefDef(Modifiers(Synthetic), nme.ANON_FUN, Nil, params :: Nil, EmptyTree, body),
+ DefDef(Modifiers(Synthetic), nme.ANON_FUN, Nil, params :: Nil, TypeTree(), body),
Closure(Nil, Ident(nme.ANON_FUN), EmptyTree))
/** Make closure corresponding to partial function { cases } */
@@ -482,8 +482,7 @@ object desugar {
AppliedTypeTree(ref(defn.RepeatedParamType), t)
else {
assert(ctx.mode.isExpr, ctx.mode)
- if (op == nme.WILDCARD) tree // desugar later by eta expansion
- else Select(t, op)
+ Select(t, op)
}
case PrefixOp(op, t) =>
if ((ctx.mode is Mode.Type) && op == nme.ARROWkw)
diff --git a/src/dotty/tools/dotc/ast/Trees.scala b/src/dotty/tools/dotc/ast/Trees.scala
index 254818b27..2392e52be 100644
--- a/src/dotty/tools/dotc/ast/Trees.scala
+++ b/src/dotty/tools/dotc/ast/Trees.scala
@@ -186,7 +186,7 @@ object Trees {
withTypeUnchecked(tpe)
}
- def withTypeUnchecked(tpe: Type): ThisTree[Type] = {
+ def withTypeUnchecked(tpe: Type): ThisTree[Type] = {
val tree =
(if (myTpe == null ||
(myTpe.asInstanceOf[AnyRef] eq tpe.asInstanceOf[AnyRef])) this
@@ -524,6 +524,8 @@ object Trees {
type ThisTree[-T >: Untyped] = TypeTree[T]
override def initialPos = NoPosition
override def isEmpty = !hasType && original.isEmpty
+ override def toString =
+ s"TypeTree${if (hasType) s"[$typeOpt]" else s"($original)"}"
}
/** ref.type */
diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala
index 3cf15479d..b7ae92b46 100644
--- a/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -138,8 +138,6 @@ class TypeComparer(implicit val ctx: Context) extends DotClass {
}
case tp2: AnnotatedType =>
isSubType(tp1, tp2.tpe) // todo: refine?
- case tp2: ProtoType =>
- tp2.isMatchedBy(tp1)
case ErrorType =>
true
case _ =>
diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
index 79641d932..3ee86f665 100644
--- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala
+++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
@@ -171,8 +171,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
"if " ~ toText(cond) ~ (" then" provided !cond.isInstanceOf[Parens]) ~~ toText(thenp) ~ optText(elsep)(" else " ~ _)
}
case Closure(env, ref, _) =>
- if (env.isEmpty) toText(ref)
- else "closure<" ~ toTextGlobal(env, ", ") ~ " | " ~ toTextGlobal(ref) ~ ">"
+ "closure(" ~ (toTextGlobal(env, ", ") ~ " | " provided env.nonEmpty) ~
+ toTextGlobal(ref) ~ ")"
case Match(sel, cases) =>
if (sel.isEmpty) blockText(cases)
else changePrec(GlobalPrec) { toText(sel) ~ " match " ~ blockText(cases) }
diff --git a/src/dotty/tools/dotc/typer/Inferencing.scala b/src/dotty/tools/dotc/typer/Inferencing.scala
index b8f0e245b..a9d0b287a 100644
--- a/src/dotty/tools/dotc/typer/Inferencing.scala
+++ b/src/dotty/tools/dotc/typer/Inferencing.scala
@@ -27,8 +27,8 @@ object Inferencing {
* 3. there is an implicit conversion from `tp` to `pt`.
*/
def isCompatible(tp: Type, pt: Type)(implicit ctx: Context): Boolean = (
- tp <:< pt
- || pt.typeSymbol == defn.ByNameParamClass && tp <:< pt.typeArgs.head
+ conforms(tp, pt)
+ || pt.typeSymbol == defn.ByNameParamClass && conforms(tp, pt.typeArgs.head)
|| viewExists(tp, pt))
}
@@ -83,6 +83,10 @@ object Inferencing {
case class PolyProto(nargs: Int, override val resultType: Type) extends UncachedGroundType
+ object AnyFunctionProto extends UncachedGroundType with ProtoType {
+ def isMatchedBy(tp: Type)(implicit ctx: Context) = true
+ }
+
/** The normalized form of a type
* - unwraps polymorphic types, tracking their parameters in the current constraint
* - skips implicit parameters
@@ -131,6 +135,11 @@ object Inferencing {
case tp => tp
}
+ def conforms(tpe: Type, pt: Type)(implicit ctx: Context): Boolean = pt match {
+ case pt: ProtoType => pt.isMatchedBy(tpe)
+ case _ => tpe <:< pt
+ }
+
def checkBounds(args: List[Tree], poly: PolyType, pos: Position)(implicit ctx: Context): Unit = {
}
diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala
index 6fe6182b4..887970b67 100644
--- a/src/dotty/tools/dotc/typer/Namer.scala
+++ b/src/dotty/tools/dotc/typer/Namer.scala
@@ -71,9 +71,8 @@ class Namer { typer: Typer =>
*/
lazy val symOfTree = new mutable.HashMap[Tree, Symbol]
- /** A map from expanded trees their typed versions.
+ /** A map from expanded trees to their typed versions.
* Populated when trees are typechecked during completion (using method typedAhead).
- * Emptied during typer.
*/
lazy val typedTree = new mutable.HashMap[Tree, tpd.Tree]
@@ -189,6 +188,7 @@ class Namer { typer: Typer =>
/** The expansion of a member def */
def expansion(mdef: DefTree)(implicit ctx: Context): Tree = {
val expanded = desugar.defTree(mdef)
+ println(i"Expansion: $mdef expands to $expanded")
if (expanded ne mdef) expandedTree(mdef) = expanded
expanded
}
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index a904aea69..32c7bbea4 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -483,7 +483,7 @@ class Typer extends Namer with Applications with Implicits {
def typedClosure(tree: untpd.Closure, pt: Type)(implicit ctx: Context) = {
val env1 = tree.env mapconserve (typed(_))
- val meth1 = typed(tree.meth)
+ val meth1 = typedExpanded(tree.meth)
val ownType = meth1.tpe.widen match {
case mt: MethodType if !mt.isDependent =>
mt.toFunctionType
@@ -806,7 +806,8 @@ class Typer extends Namer with Applications with Implicits {
case tree: untpd.Bind => typedBind(tree, pt)
case tree: untpd.Alternative => typedAlternative(tree, pt)
case tree: untpd.ValDef =>
- typedValDef(tree, sym)(localContext)
+ if (tree.isEmpty) tpd.EmptyValDef
+ else typedValDef(tree, sym)(localContext)
case tree: untpd.DefDef =>
val typer1 = nestedTyper.remove(sym).get
typer1.typedDefDef(tree, sym)(localContext.withTyper(typer1))
@@ -817,6 +818,7 @@ class Typer extends Namer with Applications with Implicits {
case tree: untpd.PackageDef => typedPackageDef(tree)
case tree: untpd.Annotated => typedAnnotated(tree, pt)
case tree: untpd.TypedSplice => tree.tree
+ case untpd.PostfixOp(tree, nme.WILDCARD) => typed(tree, AnyFunctionProto)
case untpd.EmptyTree => tpd.EmptyTree
case _ => typed(desugar(tree), pt)
}
@@ -971,7 +973,7 @@ class Typer extends Namer with Applications with Implicits {
case wtp: ExprType =>
adapt(tree.withType(wtp.resultType), pt)
case wtp: ImplicitMethodType =>
- val args = (wtp.paramNames, wtp.paramTypes).zipped map { (pname, formal) =>
+ val args = (wtp.paramNames, wtp.paramTypes).zipped(identity, identity) map { (pname, formal) =>
val arg = inferImplicit(formal, EmptyTree, tree.pos.endPos)
if (arg.isEmpty)
ctx.error(i"no implicit argument of type $formal found for parameter $pname of $methodStr", tree.pos.endPos)
@@ -979,7 +981,8 @@ class Typer extends Namer with Applications with Implicits {
}
adapt(tpd.Apply(tree, args), pt)
case wtp: MethodType =>
- if (defn.isFunctionType(pt) && !tree.symbol.isConstructor)
+ if ((defn.isFunctionType(pt) || (pt eq AnyFunctionProto)) &&
+ !tree.symbol.isConstructor)
etaExpand(tree, wtp)
else if (wtp.paramTypes.isEmpty)
adapt(tpd.Apply(tree, Nil), pt)
@@ -988,7 +991,7 @@ class Typer extends Namer with Applications with Implicits {
i"""missing arguments for $methodStr
|follow this method with `_' if you want to treat it as a partially applied function""".stripMargin)
case _ =>
- if (tree.tpe <:< pt) tree
+ if (conforms(tree.tpe, pt)) tree
else if (ctx.mode is Mode.Pattern) tree // no subtype check for patterns
else if (ctx.mode is Mode.Type) err.typeMismatch(tree, pt)
else adaptToSubType(wtp)
diff --git a/tests/pos/functions1.scala b/tests/pos/functions1.scala
new file mode 100644
index 000000000..72686ca15
--- /dev/null
+++ b/tests/pos/functions1.scala
@@ -0,0 +1,13 @@
+class X(val elem: Int) extends Object {
+ def foo(y: String): Int = y.length + elem
+}
+
+object Functions {
+
+ val x = new X(2)
+ val xe = x.elem
+ val xf: String => Int = x.foo(_)
+ val x2: String => Int = x.foo
+ val x3 = x.foo _
+
+}
diff --git a/tests/pos/implicits1.scala b/tests/pos/implicits1.scala
index 4eae69325..2f0399b74 100644
--- a/tests/pos/implicits1.scala
+++ b/tests/pos/implicits1.scala
@@ -1,4 +1,6 @@
-class X(elem: Int) extends Object
+class X(val elem: Int) {
+ def foo(y: String): Int = y.length + elem
+}
object Implicits {
@@ -6,6 +8,12 @@ object Implicits {
implicit def conv(x: Int): X = new X(x)
+ class Xdecorator(x: X) extends Object {
+ def foo(cond: Boolean): Int = if (cond) x.foo("abc") else 0
+ }
+
+ implicit def XDecorator(x: X) = new Xdecorator(x)
+
val a: Object = "abc"
val b: Any = "abc"
@@ -18,4 +26,10 @@ object Implicits {
val z: X = 3
+ val c: Int = y.elem
+
+ val d: Int = z.foo("abc")
+
+ // val e: Int = z.foo(true) not yet
+
}