aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorodersky <odersky@gmail.com>2016-09-16 19:51:44 +0300
committerGitHub <noreply@github.com>2016-09-16 19:51:44 +0300
commit9ae9a20e6c1b349728d8b0ecd2144ed613cd0ef2 (patch)
tree18fcd1a7eeb5f3ad61bf8dae52daba45cdab8272 /src
parent5d8f132b98ca10e47773275c7048ce132f5f197c (diff)
parent0ee74cc0f8252caa189f0a7aaf8a274df486f971 (diff)
downloaddotty-9ae9a20e6c1b349728d8b0ecd2144ed613cd0ef2.tar.gz
dotty-9ae9a20e6c1b349728d8b0ecd2144ed613cd0ef2.tar.bz2
dotty-9ae9a20e6c1b349728d8b0ecd2144ed613cd0ef2.zip
Merge pull request #1469 from dotty-staging/fix-scala.Dynamic
Fixes for scala.Dynamic
Diffstat (limited to 'src')
-rw-r--r--src/dotty/tools/dotc/ast/TreeInfo.scala14
-rw-r--r--src/dotty/tools/dotc/typer/Applications.scala15
-rw-r--r--src/dotty/tools/dotc/typer/Dynamic.scala85
-rw-r--r--src/dotty/tools/dotc/typer/TypeAssigner.scala4
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala15
5 files changed, 73 insertions, 60 deletions
diff --git a/src/dotty/tools/dotc/ast/TreeInfo.scala b/src/dotty/tools/dotc/ast/TreeInfo.scala
index a48651ebf..7c3f7f385 100644
--- a/src/dotty/tools/dotc/ast/TreeInfo.scala
+++ b/src/dotty/tools/dotc/ast/TreeInfo.scala
@@ -630,20 +630,6 @@ object TreeInfo {
}
}
- def isApplyDynamicName(name: Name) = (name == nme.updateDynamic) || (name == nme.selectDynamic) || (name == nme.applyDynamic) || (name == nme.applyDynamicNamed)
-
- class DynamicApplicationExtractor(nameTest: Name => Boolean) {
- def unapply(tree: Tree) = tree match {
- case Apply(TypeApply(Select(qual, oper), _), List(Literal(Constant(name)))) if nameTest(oper) => Some((qual, name))
- case Apply(Select(qual, oper), List(Literal(Constant(name)))) if nameTest(oper) => Some((qual, name))
- case Apply(Ident(oper), List(Literal(Constant(name)))) if nameTest(oper) => Some((EmptyTree(), name))
- case _ => None
- }
- }
- object DynamicUpdate extends DynamicApplicationExtractor(_ == nme.updateDynamic)
- object DynamicApplication extends DynamicApplicationExtractor(isApplyDynamicName)
- object DynamicApplicationNamed extends DynamicApplicationExtractor(_ == nme.applyDynamicNamed)
-
object MacroImplReference {
private def refPart(tree: Tree): Tree = tree match {
case TypeApply(fun, _) => refPart(fun)
diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala
index 1fff14cc6..a9212e5d6 100644
--- a/src/dotty/tools/dotc/typer/Applications.scala
+++ b/src/dotty/tools/dotc/typer/Applications.scala
@@ -591,13 +591,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
fun1.tpe match {
case ErrorType => tree.withType(ErrorType)
- case TryDynamicCallType =>
- tree match {
- case tree @ Apply(Select(qual, name), args) if !isDynamicMethod(name) =>
- typedDynamicApply(qual, name, args, pt)(tree)
- case _ =>
- handleUnexpectedFunType(tree, fun1)
- }
+ case TryDynamicCallType => typedDynamicApply(tree, pt)
case _ =>
tryEither {
implicit ctx => simpleApply(fun1, proto)
@@ -679,7 +673,12 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
}
case _ =>
}
- assignType(cpy.TypeApply(tree)(typedFn, typedArgs), typedFn, typedArgs)
+ def tryDynamicTypeApply(): Tree = typedFn match {
+ case typedFn: Select if !pt.isInstanceOf[FunProto] => typedDynamicSelect(typedFn, typedArgs, pt)
+ case _ => tree.withType(TryDynamicCallType)
+ }
+ if (typedFn.tpe eq TryDynamicCallType) tryDynamicTypeApply()
+ else assignType(cpy.TypeApply(tree)(typedFn, typedArgs), typedFn, typedArgs)
}
/** Rewrite `new Array[T](....)` if T is an unbounded generic to calls to newGenericArray.
diff --git a/src/dotty/tools/dotc/typer/Dynamic.scala b/src/dotty/tools/dotc/typer/Dynamic.scala
index aeb3cca8c..b5ace87d3 100644
--- a/src/dotty/tools/dotc/typer/Dynamic.scala
+++ b/src/dotty/tools/dotc/typer/Dynamic.scala
@@ -2,15 +2,14 @@ package dotty.tools
package dotc
package typer
-import dotty.tools.dotc.ast.Trees.NamedArg
-import dotty.tools.dotc.ast.tpd._
+import dotty.tools.dotc.ast.Trees._
+import dotty.tools.dotc.ast.tpd
import dotty.tools.dotc.ast.untpd
import dotty.tools.dotc.core.Constants.Constant
import dotty.tools.dotc.core.Contexts.Context
import dotty.tools.dotc.core.Names.Name
import dotty.tools.dotc.core.StdNames._
import dotty.tools.dotc.core.Types._
-import dotty.tools.dotc.core.Mode
import dotty.tools.dotc.core.Decorators._
object Dynamic {
@@ -28,44 +27,78 @@ object Dynamic {
* The first matching rule of is applied.
*/
trait Dynamic { self: Typer with Applications =>
+ import Dynamic._
+ import tpd._
/** Translate selection that does not typecheck according to the normal rules into a applyDynamic/applyDynamicNamed.
- * foo.bar(baz0, baz1, ...) ~~> foo.applyDynamic(bar)(baz0, baz1, ...)
- * foo.bar(x = bazX, y = bazY, baz, ...) ~~> foo.applyDynamicNamed("bar")(("x", bazX), ("y", bazY), ("", baz), ...)
+ * foo.bar(baz0, baz1, ...) ~~> foo.applyDynamic(bar)(baz0, baz1, ...)
+ * foo.bar[T0, ...](baz0, baz1, ...) ~~> foo.applyDynamic[T0, ...](bar)(baz0, baz1, ...)
+ * foo.bar(x = bazX, y = bazY, baz, ...) ~~> foo.applyDynamicNamed("bar")(("x", bazX), ("y", bazY), ("", baz), ...)
+ * foo.bar[T0, ...](x = bazX, y = bazY, baz, ...) ~~> foo.applyDynamicNamed[T0, ...]("bar")(("x", bazX), ("y", bazY), ("", baz), ...)
*/
- def typedDynamicApply(qual: untpd.Tree, name: Name, args: List[untpd.Tree], pt: Type)(original: untpd.Apply)(
- implicit ctx: Context): Tree = {
- def isNamedArg(arg: untpd.Tree): Boolean = arg match { case NamedArg(_, _) => true; case _ => false }
- val dynName = if (args.exists(isNamedArg)) nme.applyDynamicNamed else nme.applyDynamic
- if (dynName == nme.applyDynamicNamed && untpd.isWildcardStarArgList(args)) {
- ctx.error("applyDynamicNamed does not support passing a vararg parameter", original.pos)
- original.withType(ErrorType)
- } else {
- def namedArgTuple(name: String, arg: untpd.Tree) = untpd.Tuple(List(Literal(Constant(name)), arg))
- def namedArgs = args.map {
- case NamedArg(argName, arg) => namedArgTuple(argName.toString, arg)
- case arg => namedArgTuple("", arg)
+ def typedDynamicApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = {
+ def typedDynamicApply(qual: untpd.Tree, name: Name, targs: List[untpd.Tree]): Tree = {
+ def isNamedArg(arg: untpd.Tree): Boolean = arg match { case NamedArg(_, _) => true; case _ => false }
+ val args = tree.args
+ val dynName = if (args.exists(isNamedArg)) nme.applyDynamicNamed else nme.applyDynamic
+ if (dynName == nme.applyDynamicNamed && untpd.isWildcardStarArgList(args)) {
+ ctx.error("applyDynamicNamed does not support passing a vararg parameter", tree.pos)
+ tree.withType(ErrorType)
+ } else {
+ def namedArgTuple(name: String, arg: untpd.Tree) = untpd.Tuple(List(Literal(Constant(name)), arg))
+ def namedArgs = args.map {
+ case NamedArg(argName, arg) => namedArgTuple(argName.toString, arg)
+ case arg => namedArgTuple("", arg)
+ }
+ val args1 = if (dynName == nme.applyDynamic) args else namedArgs
+ typedApply(untpd.Apply(coreDynamic(qual, dynName, name, targs), args1), pt)
}
- val args1 = if (dynName == nme.applyDynamic) args else namedArgs
- typedApply(untpd.Apply(coreDynamic(qual, dynName, name), args1), pt)
+ }
+
+ tree.fun match {
+ case Select(qual, name) if !isDynamicMethod(name) =>
+ typedDynamicApply(qual, name, Nil)
+ case TypeApply(Select(qual, name), targs) if !isDynamicMethod(name) =>
+ typedDynamicApply(qual, name, targs)
+ case TypeApply(fun, targs) =>
+ typedDynamicApply(fun, nme.apply, targs)
+ case fun =>
+ typedDynamicApply(fun, nme.apply, Nil)
}
}
/** Translate selection that does not typecheck according to the normal rules into a selectDynamic.
- * foo.bar ~~> foo.selectDynamic(bar)
+ * foo.bar ~~> foo.selectDynamic(bar)
+ * foo.bar[T0, ...] ~~> foo.selectDynamic[T0, ...](bar)
*
* Note: inner part of translation foo.bar(baz) = quux ~~> foo.selectDynamic(bar).update(baz, quux) is achieved
* through an existing transformation of in typedAssign [foo.bar(baz) = quux ~~> foo.bar.update(baz, quux)].
*/
- def typedDynamicSelect(tree: untpd.Select, pt: Type)(implicit ctx: Context): Tree =
- typedApply(coreDynamic(tree.qualifier, nme.selectDynamic, tree.name), pt)
+ def typedDynamicSelect(tree: untpd.Select, targs: List[Tree], pt: Type)(implicit ctx: Context): Tree =
+ typedApply(coreDynamic(tree.qualifier, nme.selectDynamic, tree.name, targs), pt)
/** Translate selection that does not typecheck according to the normal rules into a updateDynamic.
* foo.bar = baz ~~> foo.updateDynamic(bar)(baz)
*/
- def typedDynamicAssign(qual: untpd.Tree, name: Name, rhs: untpd.Tree, pt: Type)(implicit ctx: Context): Tree =
- typedApply(untpd.Apply(coreDynamic(qual, nme.updateDynamic, name), rhs), pt)
+ def typedDynamicAssign(tree: untpd.Assign, pt: Type)(implicit ctx: Context): Tree = {
+ def typedDynamicAssign(qual: untpd.Tree, name: Name, targs: List[untpd.Tree]): Tree =
+ typedApply(untpd.Apply(coreDynamic(qual, nme.updateDynamic, name, targs), tree.rhs), pt)
+ tree.lhs match {
+ case Select(qual, name) if !isDynamicMethod(name) =>
+ typedDynamicAssign(qual, name, Nil)
+ case TypeApply(Select(qual, name), targs) if !isDynamicMethod(name) =>
+ typedDynamicAssign(qual, name, targs)
+ case _ =>
+ ctx.error("reassignment to val", tree.pos)
+ tree.withType(ErrorType)
+ }
+ }
- private def coreDynamic(qual: untpd.Tree, dynName: Name, name: Name)(implicit ctx: Context): untpd.Apply =
- untpd.Apply(untpd.Select(qual, dynName), Literal(Constant(name.toString)))
+ private def coreDynamic(qual: untpd.Tree, dynName: Name, name: Name, targs: List[untpd.Tree])(implicit ctx: Context): untpd.Apply = {
+ val select = untpd.Select(qual, dynName)
+ val selectWithTypes =
+ if (targs.isEmpty) select
+ else untpd.TypeApply(select, targs)
+ untpd.Apply(selectWithTypes, Literal(Constant(name.toString)))
+ }
}
diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala
index 36404a68f..6023bfcd0 100644
--- a/src/dotty/tools/dotc/typer/TypeAssigner.scala
+++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala
@@ -168,7 +168,9 @@ trait TypeAssigner {
val d2 = pre.nonPrivateMember(name)
if (reallyExists(d2) && firstTry)
test(tpe.shadowed.withDenot(d2), false)
- else {
+ else if (pre.derivesFrom(defn.DynamicClass)) {
+ TryDynamicCallType
+ } else {
val alts = tpe.denot.alternatives.map(_.symbol).filter(_.exists)
val what = alts match {
case Nil =>
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index fdcfe347b..2cfc5f411 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -317,12 +317,9 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
val qual1 = typedExpr(tree.qualifier, selectionProto(tree.name, pt, this))
if (tree.name.isTypeName) checkStable(qual1.tpe, qual1.pos)
val select = typedSelect(tree, pt, qual1)
- pt match {
- case _: FunProto | AssignProto => select
- case _ =>
- if (select.tpe eq TryDynamicCallType) typedDynamicSelect(tree, pt)
- else select
- }
+ if (select.tpe ne TryDynamicCallType) select
+ else if (pt.isInstanceOf[PolyProto] || pt.isInstanceOf[FunProto] || pt == AssignProto) select
+ else typedDynamicSelect(tree, Nil, pt)
}
def asJavaSelectFromTypeTree(implicit ctx: Context): Tree = {
@@ -518,11 +515,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
reassignmentToVal
}
case TryDynamicCallType =>
- tree match {
- case Assign(Select(qual, name), rhs) if !isDynamicMethod(name) =>
- typedDynamicAssign(qual, name, rhs, pt)
- case _ => reassignmentToVal
- }
+ typedDynamicAssign(tree, pt)
case tpe =>
reassignmentToVal
}