aboutsummaryrefslogtreecommitdiff
path: root/src/dotty
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2016-09-15 12:08:42 +0200
committerMartin Odersky <odersky@gmail.com>2016-10-02 16:12:28 +0200
commitb5132e87afe1a98467369d2f91ba4483a6a88ea4 (patch)
treef8fca34ccef6c3b9ff5d9d7f971f30aabd84a2e1 /src/dotty
parent84bc770bb7bcac2fe09a13c62c24aac1e3fda582 (diff)
downloaddotty-b5132e87afe1a98467369d2f91ba4483a6a88ea4.tar.gz
dotty-b5132e87afe1a98467369d2f91ba4483a6a88ea4.tar.bz2
dotty-b5132e87afe1a98467369d2f91ba4483a6a88ea4.zip
Change owner as necessary when typing a TypedSplice
When typing an untpd.TypedSplice it could be that the owner at the time the tree is originally typed is different from the owner at the time the tree is unwrapped. In that case the owner needs to be changed. Problem was noticed in Course-2002-02 after changing Closure to be a pure expression. This means that TypedSplices containing closures are no longer lifted out from containing closures during eta expansion, and the owner chain got corrupted.
Diffstat (limited to 'src/dotty')
-rw-r--r--src/dotty/tools/dotc/ast/untpd.scala11
-rw-r--r--src/dotty/tools/dotc/typer/Checking.scala3
-rw-r--r--src/dotty/tools/dotc/typer/EtaExpansion.scala2
-rw-r--r--src/dotty/tools/dotc/typer/ProtoTypes.scala2
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala19
5 files changed, 28 insertions, 9 deletions
diff --git a/src/dotty/tools/dotc/ast/untpd.scala b/src/dotty/tools/dotc/ast/untpd.scala
index 114c13684..a0a353c13 100644
--- a/src/dotty/tools/dotc/ast/untpd.scala
+++ b/src/dotty/tools/dotc/ast/untpd.scala
@@ -21,10 +21,15 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
}
/** A typed subtree of an untyped tree needs to be wrapped in a TypedSlice */
- case class TypedSplice(tree: tpd.Tree) extends ProxyTree {
+ abstract case class TypedSplice(tree: tpd.Tree)(val owner: Symbol) extends ProxyTree {
def forwardTo = tree
}
+ object TypedSplice {
+ def apply(tree: tpd.Tree)(implicit ctx: Context): TypedSplice =
+ new TypedSplice(tree)(ctx.owner) {}
+ }
+
/** mods object name impl */
case class ModuleDef(name: TermName, impl: Template)
extends MemberDef {
@@ -232,7 +237,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
case AppliedTypeTree(tycon, targs) =>
(tycon, targs)
case TypedSplice(AppliedTypeTree(tycon, targs)) =>
- (TypedSplice(tycon), targs map TypedSplice)
+ (TypedSplice(tycon), targs map (TypedSplice(_)))
case TypedSplice(tpt1: Tree) =>
val argTypes = tpt1.tpe.argTypes
val tycon = tpt1.tpe.withoutArgs(argTypes)
@@ -260,7 +265,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
def AppliedTypeTree(tpt: Tree, arg: Tree): AppliedTypeTree =
AppliedTypeTree(tpt, arg :: Nil)
- def TypeTree(tpe: Type): TypedSplice = TypedSplice(TypeTree().withTypeUnchecked(tpe))
+ def TypeTree(tpe: Type)(implicit ctx: Context): TypedSplice = TypedSplice(TypeTree().withTypeUnchecked(tpe))
def TypeDef(name: TypeName, tparams: List[TypeDef], rhs: Tree): TypeDef =
if (tparams.isEmpty) TypeDef(name, rhs) else new PolyTypeDef(name, tparams, rhs)
diff --git a/src/dotty/tools/dotc/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala
index 42eede5e9..b02b0ad21 100644
--- a/src/dotty/tools/dotc/typer/Checking.scala
+++ b/src/dotty/tools/dotc/typer/Checking.scala
@@ -484,7 +484,8 @@ trait Checking {
def checkInlineConformant(tree: Tree, what: => String)(implicit ctx: Context): Unit =
tree.tpe.widenTermRefExpr match {
case tp: ConstantType if isPureExpr(tree) => // ok
- case _ => ctx.error(em"$what must be a constant expression", tree.pos)
+ case tp if defn.isFunctionType(tp) && isPureExpr(tree) => // ok
+ case _ => ctx.error(em"$what must be a constant expression or a function", tree.pos)
}
/** Check that class does not define same symbol twice */
diff --git a/src/dotty/tools/dotc/typer/EtaExpansion.scala b/src/dotty/tools/dotc/typer/EtaExpansion.scala
index 7cbe70b47..397b6d95b 100644
--- a/src/dotty/tools/dotc/typer/EtaExpansion.scala
+++ b/src/dotty/tools/dotc/typer/EtaExpansion.scala
@@ -148,7 +148,7 @@ object EtaExpansion {
case _ =>
}
val fn = untpd.Function(params, body)
- if (defs.nonEmpty) untpd.Block(defs.toList map untpd.TypedSplice, fn) else fn
+ if (defs.nonEmpty) untpd.Block(defs.toList map (untpd.TypedSplice(_)), fn) else fn
}
}
diff --git a/src/dotty/tools/dotc/typer/ProtoTypes.scala b/src/dotty/tools/dotc/typer/ProtoTypes.scala
index 80f0fd186..0e6697fb7 100644
--- a/src/dotty/tools/dotc/typer/ProtoTypes.scala
+++ b/src/dotty/tools/dotc/typer/ProtoTypes.scala
@@ -299,7 +299,7 @@ object ProtoTypes {
}
class UnapplyFunProto(argType: Type, typer: Typer)(implicit ctx: Context) extends FunProto(
- untpd.TypedSplice(dummyTreeOfType(argType)) :: Nil, WildcardType, typer)
+ untpd.TypedSplice(dummyTreeOfType(argType))(ctx) :: Nil, WildcardType, typer)
/** A prototype for expressions [] that are type-parameterized:
*
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index 85102841e..18b609f8d 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -513,8 +513,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
val rawUpdate: untpd.Tree = untpd.Select(untpd.TypedSplice(fn), nme.update)
val wrappedUpdate =
if (targs.isEmpty) rawUpdate
- else untpd.TypeApply(rawUpdate, targs map untpd.TypedSplice)
- val appliedUpdate = cpy.Apply(fn)(wrappedUpdate, (args map untpd.TypedSplice) :+ tree.rhs)
+ else untpd.TypeApply(rawUpdate, targs map (untpd.TypedSplice(_)))
+ val appliedUpdate = cpy.Apply(fn)(wrappedUpdate, (args map (untpd.TypedSplice(_))) :+ tree.rhs)
typed(appliedUpdate, pt)
case lhs =>
val lhsCore = typedUnadapted(lhs, AssignProto)
@@ -1357,6 +1357,19 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
}
}
+ def typedTypedSplice(tree: untpd.TypedSplice)(implicit ctx: Context): Tree =
+ tree.tree match {
+ case tree1: TypeTree => tree1 // no change owner necessary here ...
+ case tree1: Ident => tree1 // ... or here
+ case tree1 =>
+ if (ctx.owner ne tree.owner) {
+ println(i"changing owner of $tree1 from ${tree.owner} to ${ctx.owner}")
+ tree1.changeOwner(tree.owner, ctx.owner)
+ }
+ else tree1
+ }
+
+
def typedAsFunction(tree: untpd.PostfixOp, pt: Type)(implicit ctx: Context): Tree = {
val untpd.PostfixOp(qual, nme.WILDCARD) = tree
val pt1 = if (defn.isFunctionType(pt)) pt else AnyFunctionProto
@@ -1456,7 +1469,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
case tree: untpd.Alternative => typedAlternative(tree, pt)
case tree: untpd.PackageDef => typedPackageDef(tree)
case tree: untpd.Annotated => typedAnnotated(tree, pt)
- case tree: untpd.TypedSplice => tree.tree
+ case tree: untpd.TypedSplice => typedTypedSplice(tree)
case tree: untpd.UnApply => typedUnApply(tree, pt)
case tree @ untpd.PostfixOp(qual, nme.WILDCARD) => typedAsFunction(tree, pt)
case untpd.EmptyTree => tpd.EmptyTree