Skip to content

Commit 28edec9

Browse files
oderskyfelixmulder
authored andcommitted
Make Context#moreProperties strongly typed
To do this, factor out Key from Attachment into a new type, Property.Key.
1 parent 10a3970 commit 28edec9

File tree

9 files changed

+238
-24
lines changed

9 files changed

+238
-24
lines changed

src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._
88
import Decorators._
99
import language.higherKinds
1010
import collection.mutable.ListBuffer
11-
import util.Attachment
11+
import util.Property
1212
import config.Printers._
1313

1414
object desugar {
@@ -21,7 +21,7 @@ object desugar {
2121
/** Tags a .withFilter call generated by desugaring a for expression.
2222
* Such calls can alternatively be rewritten to use filter.
2323
*/
24-
val MaybeFilter = new Attachment.Key[Unit]
24+
val MaybeFilter = new Property.Key[Unit]
2525

2626
/** Info of a variable in a pattern: The named tree and its type */
2727
private type VarInfo = (NameTree, Tree)

src/dotty/tools/dotc/ast/Trees.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import collection.immutable.IndexedSeq
1212
import collection.mutable.ListBuffer
1313
import parsing.Tokens.Token
1414
import printing.Printer
15-
import util.{Stats, Attachment, DotClass}
15+
import util.{Stats, Attachment, Property, DotClass}
1616
import annotation.unchecked.uncheckedVariance
1717
import language.implicitConversions
1818

@@ -29,8 +29,8 @@ object Trees {
2929
/** The total number of created tree nodes, maintained if Stats.enabled */
3030
@sharable var ntrees = 0
3131

32-
/** Attachment key for trees with documentation strings attached */
33-
val DocComment = new Attachment.Key[Comment]
32+
/** Property key for trees with documentation strings attached */
33+
val DocComment = new Property.Key[Comment]
3434

3535
/** Modifiers and annotations for definitions
3636
* @param flags The set flags

src/dotty/tools/dotc/ast/untpd.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import core._
66
import util.Positions._, Types._, Contexts._, Constants._, Names._, NameOps._, Flags._
77
import Denotations._, SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._
88
import Decorators._
9-
import util.Attachment
9+
import util.Property
1010
import language.higherKinds
1111
import collection.mutable.ListBuffer
1212

@@ -92,17 +92,17 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
9292
def derivedType(originalSym: Symbol)(implicit ctx: Context): Type
9393
}
9494

95-
/** Attachment key containing TypeTrees whose type is computed
95+
/** Property key containing TypeTrees whose type is computed
9696
* from the symbol in this type. These type trees have marker trees
9797
* TypeRefOfSym or InfoOfSym as their originals.
9898
*/
99-
val References = new Attachment.Key[List[Tree]]
99+
val References = new Property.Key[List[Tree]]
100100

101-
/** Attachment key for TypeTrees marked with TypeRefOfSym or InfoOfSym
101+
/** Property key for TypeTrees marked with TypeRefOfSym or InfoOfSym
102102
* which contains the symbol of the original tree from which this
103103
* TypeTree is derived.
104104
*/
105-
val OriginalSymbol = new Attachment.Key[Symbol]
105+
val OriginalSymbol = new Property.Key[Symbol]
106106

107107
// ------ Creation methods for untyped only -----------------
108108

src/dotty/tools/dotc/core/Contexts.scala

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ import printing._
3030
import config.{Settings, ScalaSettings, Platform, JavaPlatform, SJSPlatform}
3131
import language.implicitConversions
3232
import DenotTransformers.DenotTransformer
33+
import parsing.Scanners.Comment
34+
import util.Property.Key
3335
import xsbti.AnalysisCallback
3436

3537
object Contexts {
@@ -177,9 +179,12 @@ object Contexts {
177179
def freshName(prefix: Name): String = freshName(prefix.toString)
178180

179181
/** A map in which more contextual properties can be stored */
180-
private var _moreProperties: Map[String, Any] = _
181-
protected def moreProperties_=(moreProperties: Map[String, Any]) = _moreProperties = moreProperties
182-
def moreProperties: Map[String, Any] = _moreProperties
182+
private var _moreProperties: Map[Key[Any], Any] = _
183+
protected def moreProperties_=(moreProperties: Map[Key[Any], Any]) = _moreProperties = moreProperties
184+
def moreProperties: Map[Key[Any], Any] = _moreProperties
185+
186+
def property[T](key: Key[T]): Option[T] =
187+
moreProperties.get(key).asInstanceOf[Option[T]]
183188

184189
private var _typeComparer: TypeComparer = _
185190
protected def typeComparer_=(typeComparer: TypeComparer) = _typeComparer = typeComparer
@@ -459,9 +464,10 @@ object Contexts {
459464
def setTypeComparerFn(tcfn: Context => TypeComparer): this.type = { this.typeComparer = tcfn(this); this }
460465
def setSearchHistory(searchHistory: SearchHistory): this.type = { this.searchHistory = searchHistory; this }
461466
def setFreshNames(freshNames: FreshNameCreator): this.type = { this.freshNames = freshNames; this }
462-
def setMoreProperties(moreProperties: Map[String, Any]): this.type = { this.moreProperties = moreProperties; this }
467+
def setMoreProperties(moreProperties: Map[Key[Any], Any]): this.type = { this.moreProperties = moreProperties; this }
463468

464-
def setProperty(prop: (String, Any)): this.type = setMoreProperties(moreProperties + prop)
469+
def setProperty[T](key: Key[T], value: T): this.type =
470+
setMoreProperties(moreProperties.updated(key, value))
465471

466472
def setPhase(pid: PhaseId): this.type = setPeriod(Period(runId, pid))
467473
def setPhase(phase: Phase): this.type = setPeriod(Period(runId, phase.start, phase.end))

src/dotty/tools/dotc/transform/ExplicitOuter.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import ast.Trees._
1515
import SymUtils._
1616
import dotty.tools.dotc.ast.tpd
1717
import dotty.tools.dotc.core.Phases.Phase
18-
import util.Attachment
18+
import util.Property
1919
import collection.mutable
2020

2121
/** This phase adds outer accessors to classes and traits that need them.
@@ -36,7 +36,7 @@ class ExplicitOuter extends MiniPhaseTransform with InfoTransformer { thisTransf
3636
import ExplicitOuter._
3737
import ast.tpd._
3838

39-
val Outer = new Attachment.Key[Tree]
39+
val Outer = new Property.Key[Tree]
4040

4141
override def phaseName: String = "explicitOuter"
4242

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
package dotty.tools
2+
package dotc
3+
package typer
4+
5+
import dotty.tools.dotc.ast.Trees.NamedArg
6+
import dotty.tools.dotc.ast.{Trees, untpd, tpd, TreeTypeMap}
7+
import Trees._
8+
import core._
9+
import Flags._
10+
import Symbols._
11+
import Types._
12+
import Decorators._
13+
import StdNames.nme
14+
import Contexts.Context
15+
import Names.Name
16+
import SymDenotations.SymDenotation
17+
import Annotations.Annotation
18+
import transform.ExplicitOuter
19+
import config.Printers.inlining
20+
import ErrorReporting.errorTree
21+
import util.Property
22+
import collection.mutable
23+
24+
object Inliner {
25+
import tpd._
26+
27+
private class InlinedBody(tree: => Tree) {
28+
lazy val body = tree
29+
}
30+
31+
private val InlinedBody = new Property.Key[InlinedBody] // to be used as attachment
32+
33+
def attachBody(inlineAnnot: Annotation, tree: => Tree)(implicit ctx: Context): Unit =
34+
inlineAnnot.tree.putAttachment(InlinedBody, new InlinedBody(tree))
35+
36+
def inlinedBody(sym: SymDenotation)(implicit ctx: Context): Tree =
37+
sym.getAnnotation(defn.InlineAnnot).get.tree
38+
.attachment(InlinedBody).body
39+
40+
private class Typer extends ReTyper {
41+
override def typedSelect(tree: untpd.Select, pt: Type)(implicit ctx: Context): Tree = {
42+
val acc = tree.symbol
43+
super.typedSelect(tree, pt) match {
44+
case res @ Select(qual, name) =>
45+
if (name.endsWith(nme.OUTER)) {
46+
val outerAcc = tree.symbol
47+
println(i"selecting $tree / ${acc} / ${qual.tpe.normalizedPrefix}")
48+
res.withType(qual.tpe.widen.normalizedPrefix)
49+
}
50+
else {
51+
ensureAccessible(res.tpe, qual.isInstanceOf[Super], tree.pos)
52+
res
53+
}
54+
case res => res
55+
}
56+
}
57+
}
58+
59+
def inlineCall(tree: Tree, pt: Type)(implicit ctx: Context): Tree = {
60+
if (ctx.inlineCount < ctx.settings.xmaxInlines.value) {
61+
ctx.inlineCount += 1
62+
val rhs = inlinedBody(tree.symbol)
63+
val inlined = new Inliner(tree, rhs).inlined
64+
try new Typer().typedUnadapted(inlined, pt)
65+
finally ctx.inlineCount -= 1
66+
} else errorTree(tree,
67+
i"""Maximal number of successive inlines (${ctx.settings.xmaxInlines.value}) exceeded,
68+
| Maybe this is caused by a recursive inline method?
69+
| You can use -Xmax:inlines to change the limit.""")
70+
}
71+
}
72+
73+
class Inliner(call: tpd.Tree, rhs: tpd.Tree)(implicit ctx: Context) {
74+
import tpd._
75+
76+
private val meth = call.symbol
77+
78+
private def decomposeCall(tree: Tree): (Tree, List[Tree], List[List[Tree]]) = tree match {
79+
case Apply(fn, args) =>
80+
val (meth, targs, argss) = decomposeCall(fn)
81+
(meth, targs, argss :+ args)
82+
case TypeApply(fn, targs) =>
83+
val (meth, Nil, Nil) = decomposeCall(fn)
84+
(meth, targs, Nil)
85+
case _ =>
86+
(tree, Nil, Nil)
87+
}
88+
89+
private val (methPart, targs, argss) = decomposeCall(call)
90+
91+
private lazy val prefix = methPart match {
92+
case Select(qual, _) => qual
93+
case _ => tpd.This(ctx.owner.enclosingClass.asClass)
94+
}
95+
96+
private val replacement = new mutable.HashMap[Type, NamedType]
97+
98+
private val paramBindings = paramBindingsOf(meth.info, targs, argss)
99+
100+
private def paramBindingsOf(tp: Type, targs: List[Tree], argss: List[List[Tree]]): List[MemberDef] = tp match {
101+
case tp: PolyType =>
102+
val bindings =
103+
(tp.paramNames, targs).zipped.map { (name, arg) =>
104+
val tparam = newSym(name, EmptyFlags, TypeAlias(arg.tpe.stripTypeVar)).asType
105+
TypeDef(tparam)
106+
}
107+
bindings ::: paramBindingsOf(tp.resultType, Nil, argss)
108+
case tp: MethodType =>
109+
val bindings =
110+
(tp.paramNames, tp.paramTypes, argss.head).zipped.map { (name, paramtp, arg) =>
111+
def isByName = paramtp.dealias.isInstanceOf[ExprType]
112+
val (paramFlags, paramType) =
113+
if (isByName) (Method, ExprType(arg.tpe)) else (EmptyFlags, arg.tpe)
114+
val vparam = newSym(name, paramFlags, paramType).asTerm
115+
if (isByName) DefDef(vparam, arg) else ValDef(vparam, arg)
116+
}
117+
bindings ::: paramBindingsOf(tp.resultType, targs, argss.tail)
118+
case _ =>
119+
assert(targs.isEmpty)
120+
assert(argss.isEmpty)
121+
Nil
122+
}
123+
124+
private def newSym(name: Name, flags: FlagSet, info: Type): Symbol =
125+
ctx.newSymbol(ctx.owner, name, flags, info, coord = call.pos)
126+
127+
private def registerType(tpe: Type): Unit =
128+
if (!replacement.contains(tpe)) tpe match {
129+
case tpe: ThisType =>
130+
if (!ctx.owner.isContainedIn(tpe.cls) && !tpe.cls.is(Package))
131+
if (tpe.cls.isStaticOwner)
132+
replacement(tpe) = tpe.cls.sourceModule.termRef
133+
else {
134+
def outerDistance(cls: Symbol): Int = {
135+
assert(cls.exists, i"not encl: ${meth.owner.enclosingClass} ${tpe.cls}")
136+
if (tpe.cls eq cls) 0
137+
else outerDistance(cls.owner.enclosingClass) + 1
138+
}
139+
val n = outerDistance(meth.owner)
140+
replacement(tpe) = newSym(nme.SELF ++ n.toString, EmptyFlags, tpe.widen).termRef
141+
}
142+
case tpe: NamedType if tpe.symbol.is(Param) && tpe.symbol.owner == meth =>
143+
val Some(binding) = paramBindings.find(_.name == tpe.name)
144+
replacement(tpe) =
145+
if (tpe.name.isTypeName) binding.symbol.typeRef else binding.symbol.termRef
146+
case _ =>
147+
}
148+
149+
private def registerLeaf(tree: Tree): Unit = tree match {
150+
case _: This | _: Ident => registerType(tree.tpe)
151+
case _ =>
152+
}
153+
154+
private def outerLevel(sym: Symbol) = sym.name.drop(nme.SELF.length).toString.toInt
155+
156+
val inlined = {
157+
rhs.foreachSubTree(registerLeaf)
158+
159+
val accessedSelfSyms =
160+
(for ((tp: ThisType, ref) <- replacement) yield ref.symbol.asTerm).toSeq.sortBy(outerLevel)
161+
162+
val outerBindings = new mutable.ListBuffer[MemberDef]
163+
for (selfSym <- accessedSelfSyms) {
164+
val rhs =
165+
if (outerBindings.isEmpty) prefix
166+
else {
167+
val lastSelf = outerBindings.last.symbol
168+
val outerDelta = outerLevel(selfSym) - outerLevel(lastSelf)
169+
def outerSelect(ref: Tree, dummy: Int): Tree = ???
170+
//ref.select(ExplicitOuter.outerAccessorTBD(ref.tpe.widen.classSymbol.asClass))
171+
(ref(lastSelf) /: (0 until outerDelta))(outerSelect)
172+
}
173+
outerBindings += ValDef(selfSym, rhs.ensureConforms(selfSym.info))
174+
}
175+
outerBindings ++= paramBindings
176+
177+
val typeMap = new TypeMap {
178+
def apply(t: Type) = t match {
179+
case _: SingletonType => replacement.getOrElse(t, t)
180+
case _ => mapOver(t)
181+
}
182+
}
183+
184+
def treeMap(tree: Tree) = tree match {
185+
case _: This | _: Ident =>
186+
replacement.get(tree.tpe) match {
187+
case Some(t) => ref(t)
188+
case None => tree
189+
}
190+
case _ => tree
191+
}
192+
193+
val inliner = new TreeTypeMap(typeMap, treeMap, meth :: Nil, ctx.owner :: Nil)
194+
195+
val result = inliner(Block(outerBindings.toList, rhs)).withPos(call.pos)
196+
197+
inlining.println(i"inlining $call\n --> \n$result")
198+
result
199+
}
200+
}

src/dotty/tools/dotc/typer/Namer.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import Contexts._, Symbols._, Types._, SymDenotations._, Names._, NameOps._, Fla
99
import ast.desugar, ast.desugar._
1010
import ProtoTypes._
1111
import util.Positions._
12-
import util.{Attachment, SourcePosition, DotClass}
12+
import util.{Property, SourcePosition, DotClass}
1313
import collection.mutable
1414
import annotation.tailrec
1515
import ErrorReporting._
@@ -160,9 +160,9 @@ class Namer { typer: Typer =>
160160

161161
import untpd._
162162

163-
val TypedAhead = new Attachment.Key[tpd.Tree]
164-
val ExpandedTree = new Attachment.Key[Tree]
165-
val SymOfTree = new Attachment.Key[Symbol]
163+
val TypedAhead = new Property.Key[tpd.Tree]
164+
val ExpandedTree = new Property.Key[Tree]
165+
val SymOfTree = new Property.Key[Symbol]
166166

167167
/** A partial map from unexpanded member and pattern defs and to their expansions.
168168
* Populated during enterSyms, emptied during typer.

src/dotty/tools/dotc/util/Attachment.scala

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@ package dotty.tools.dotc.util
44
* adding, removing and lookup of attachments. Attachments are typed key/value pairs.
55
*/
66
object Attachment {
7-
8-
/** The class of keys for attachments yielding values of type V */
9-
class Key[+V]
7+
import Property.Key
108

119
/** An implementation trait for attachments.
1210
* Clients should inherit from Container instead.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package dotty.tools.dotc.util
2+
3+
/** Defines a key type with which to tag properties, such as attachments
4+
* or context properties
5+
*/
6+
object Property {
7+
8+
/** The class of keys for properties of type V */
9+
class Key[+V]
10+
}

0 commit comments

Comments
 (0)