Skip to content

Commit d0cf9c3

Browse files
committed
Merge pull request #1 from phaller/topic/virt_sourcecontext
refactoring sourcecontext support into its own trait
2 parents 65e3436 + 1ef4ad2 commit d0cf9c3

File tree

2 files changed

+168
-145
lines changed

2 files changed

+168
-145
lines changed

src/compiler/scala/tools/nsc/typechecker/Implicits.scala

Lines changed: 3 additions & 145 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import util.Statistics._
2323
* @author Martin Odersky
2424
* @version 1.0
2525
*/
26-
trait Implicits {
26+
trait Implicits extends SourceContextUtils {
2727
self: Analyzer =>
2828

2929
import global._
@@ -1112,126 +1112,6 @@ trait Implicits {
11121112
implicitInfoss1
11131113
}
11141114

1115-
def contextSourceInfoChain(ctx: Context,
1116-
stopAt: Context,
1117-
prevValDef: Option[String]): List[(String, Int)] = {
1118-
if (ctx == stopAt)
1119-
List()
1120-
else ctx.tree match {
1121-
case vd @ ValDef(_, name, _, _) if prevValDef.isEmpty || (!prevValDef.get.equals(name.toString)) =>
1122-
(name.toString, vd.pos.line) :: contextSourceInfoChain(ctx.outer, stopAt, Some(name.toString))
1123-
//case app @ Apply(fun, args) if fun.symbol.isMethod =>
1124-
// (fun.symbol.nameString, fun.pos.line) :: contextSourceInfoChain(ctx.outer, stopAt)
1125-
case _ =>
1126-
contextSourceInfoChain(ctx.outer, stopAt, None)
1127-
}
1128-
}
1129-
1130-
def contextInfoChain = context0.tree match {
1131-
case vd @ ValDef(_, name, _, _) =>
1132-
//println("current context tree is ValDef "+name)
1133-
contextSourceInfoChain(context0, context0.enclClass, None)
1134-
case _ =>
1135-
//println("current context tree: "+context0.tree)
1136-
val l = tree.pos match {
1137-
case NoPosition => 0
1138-
case _ => tree.pos.line
1139-
}
1140-
(null, l) :: contextSourceInfoChain(context0.outer, context0.outer.enclClass, None)
1141-
}
1142-
1143-
def sourceInfoTree(chain: List[(String, Int)]): Tree = chain match {
1144-
case (name, line) :: rest =>
1145-
val pairTree = gen.mkTuple(List(Literal(Constant(name)), Literal(Constant(line))))
1146-
Apply(Select(gen.mkAttributedRef(ListModule), nme.apply), List(pairTree))
1147-
case List() =>
1148-
gen.mkNil
1149-
}
1150-
1151-
/** Creates a tree that calls the factory method called constructor in object reflect.SourceContext */
1152-
def sourceInfoFactoryCall(constructor: String, args: Tree*): Tree =
1153-
if (args contains EmptyTree) EmptyTree
1154-
else typedPos(tree.pos.focus) {
1155-
Apply(
1156-
Select(gen.mkAttributedRef(SourceContextModule), constructor),
1157-
args.toList
1158-
)
1159-
}
1160-
1161-
private def methodNameOf(tree: Tree) = {
1162-
tree match {
1163-
case Apply(TypeApply(s, _), _) => s.symbol.name
1164-
case Apply(s@Select(_, _), _) => s.symbol.name
1165-
case Apply(s@Ident(_), _) => s.symbol.name
1166-
case Apply(Apply(s, _), _) => s.symbol.name
1167-
case s@Select(_, _) => s.symbol.name
1168-
case other => ""
1169-
}
1170-
}
1171-
1172-
private def receiverOptOf(tree: Tree) = {
1173-
try {
1174-
tree match {
1175-
case Apply(TypeApply(Select(recv, _), _), _) => Some(recv.symbol.name)
1176-
case Apply(Select(recv, _), _) => Some(recv.symbol.name)
1177-
case Select(recv, _) => Some(recv.symbol.name)
1178-
case _ => None
1179-
}
1180-
} catch {
1181-
case npe: NullPointerException =>
1182-
None
1183-
}
1184-
}
1185-
1186-
private def sourceInfo(): SearchResult = {
1187-
def srcInfo()(implicit from: List[Symbol] = List(), to: List[Type] = List()): SearchResult = {
1188-
implicit def wrapResult(tree: Tree): SearchResult =
1189-
if (tree == EmptyTree) SearchFailure else new SearchResult(tree, new TreeTypeSubstituter(from, to))
1190-
1191-
val methodName = methodNameOf(tree)
1192-
val receiver = receiverOptOf(tree)
1193-
1194-
//println("context source info chain:")
1195-
//println(contextInfoChain)
1196-
//println("source info tree:")
1197-
//println(sourceInfoTree(contextInfoChain))
1198-
1199-
val position = tree.pos.focus
1200-
val fileName = if (position.isDefined) position.source.file.absolute.path
1201-
else "<unknown file>"
1202-
if (receiver.isEmpty)
1203-
sourceInfoFactoryCall("apply", Literal(Constant(fileName)), Literal(Constant(methodName.toString)), sourceInfoTree(contextInfoChain))
1204-
else
1205-
sourceInfoFactoryCall("apply", Literal(Constant(fileName)), Literal(Constant(methodName.toString)), Literal(Constant(receiver.get.toString)), sourceInfoTree(contextInfoChain))
1206-
}
1207-
1208-
srcInfo()
1209-
}
1210-
1211-
private def sourceLocation(): SearchResult = {
1212-
/** Creates a tree that calls the factory method called constructor in object reflect.SourceLocation */
1213-
def sourceLocationFactoryCall(constructor: String, args: Tree*): Tree =
1214-
if (args contains EmptyTree) EmptyTree
1215-
else typedPos(tree.pos.focus) {
1216-
Apply(
1217-
Select(gen.mkAttributedRef(SourceLocationModule), constructor),
1218-
args.toList
1219-
)
1220-
}
1221-
1222-
def srcLocation()(implicit from: List[Symbol] = List(), to: List[Type] = List()): SearchResult = {
1223-
implicit def wrapResult(tree: Tree): SearchResult =
1224-
if (tree == EmptyTree) SearchFailure else new SearchResult(tree, new TreeTypeSubstituter(from, to))
1225-
1226-
val position = tree.pos.focus
1227-
val fileName = if (position.isDefined) position.source.file.absolute.path
1228-
else "<unknown file>"
1229-
sourceLocationFactoryCall("apply", Literal(Constant(position.line)), Literal(Constant(position.point)), Literal(Constant(fileName)))
1230-
}
1231-
1232-
srcLocation()
1233-
}
1234-
12351115
/** Creates a tree that calls the relevant factory method in object
12361116
* reflect.Manifest for type 'tp'. An EmptyTree is returned if
12371117
* no manifest is found. todo: make this instantiate take type params as well?
@@ -1382,7 +1262,7 @@ trait Implicits {
13821262
pt.dealias match {
13831263
case TypeRef(_, SourceContextClass, _) =>
13841264
// construct new SourceContext instance
1385-
result = sourceInfo()
1265+
result = sourceInfo(this, context0, tree)
13861266
// there is no existing SourceContext to chain with
13871267
updateSourceContext = false
13881268
case _ =>
@@ -1397,29 +1277,7 @@ trait Implicits {
13971277
if (result == SearchFailure && settings.debug.value)
13981278
log("no implicits found for "+pt+" "+pt.typeSymbol.info.baseClasses+" "+implicitsOfExpectedType)
13991279

1400-
val updatedRes = pt/*.dealias*/ match {
1401-
case TypeRef(_, SourceContextClass, _) if updateSourceContext =>
1402-
val position = tree.pos.focus
1403-
val fileName = if (position.isDefined) position.source.file.absolute.path
1404-
else "<unknown file>"
1405-
val methodName = methodNameOf(tree)
1406-
val receiver = receiverOptOf(tree)
1407-
new SearchResult(typedPos(position) {
1408-
// use sourceInfoFactoryCall to construct SourceContext
1409-
val factoryCall = if (receiver.isEmpty)
1410-
sourceInfoFactoryCall("apply", Literal(Constant(fileName)), Literal(Constant(methodName.toString)), sourceInfoTree(contextInfoChain))
1411-
else
1412-
sourceInfoFactoryCall("apply", Literal(Constant(fileName)), Literal(Constant(methodName.toString)), Literal(Constant(receiver.get.toString)), sourceInfoTree(contextInfoChain))
1413-
Apply(Select(result.tree, "update"), List(factoryCall))
1414-
}, result.subst)
1415-
case TypeRef(_, SourceLocationClass, _) =>
1416-
val position = tree.pos.focus
1417-
new SearchResult(typedPos(position) {
1418-
sourceLocation().tree
1419-
}, result.subst)
1420-
case _ => result
1421-
}
1422-
updatedRes
1280+
updatedWithSourceContext(this, tree, pt, context0, result, updateSourceContext)
14231281
}
14241282

14251283
def allImplicits: List[SearchResult] = {
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
/* NSC -- new Scala compiler
2+
* Copyright 2005-2011 LAMP/EPFL
3+
* @author Martin Odersky
4+
*/
5+
6+
package scala.tools.nsc
7+
package typechecker
8+
9+
/* Utilities for generating SourceLocations and SourceContexts.
10+
*
11+
* @author Philipp Haller
12+
*/
13+
trait SourceContextUtils {
14+
self: Analyzer =>
15+
16+
import global._
17+
import definitions._
18+
19+
def contextSourceInfoChain(ctx: Context,
20+
stopAt: Context,
21+
prevValDef: Option[String]): List[(String, Int)] = {
22+
if (ctx == stopAt)
23+
List()
24+
else ctx.tree match {
25+
case vd @ ValDef(_, name, _, _) if prevValDef.isEmpty || (!prevValDef.get.equals(name.toString)) =>
26+
(name.toString, vd.pos.line) :: contextSourceInfoChain(ctx.outer, stopAt, Some(name.toString))
27+
//case app @ Apply(fun, args) if fun.symbol.isMethod =>
28+
// (fun.symbol.nameString, fun.pos.line) :: contextSourceInfoChain(ctx.outer, stopAt)
29+
case _ =>
30+
contextSourceInfoChain(ctx.outer, stopAt, None)
31+
}
32+
}
33+
34+
def contextInfoChain(ctx: Context, tree: Tree) = ctx.tree match {
35+
case vd @ ValDef(_, name, _, _) =>
36+
//println("current context tree is ValDef "+name)
37+
contextSourceInfoChain(ctx, ctx.enclClass, None)
38+
case _ =>
39+
//println("current context tree: "+ctx.tree)
40+
val l = tree.pos match {
41+
case NoPosition => 0
42+
case _ => tree.pos.line
43+
}
44+
(null, l) :: contextSourceInfoChain(ctx.outer, ctx.outer.enclClass, None)
45+
}
46+
47+
def sourceInfoTree(chain: List[(String, Int)]): Tree = chain match {
48+
case (name, line) :: rest =>
49+
val pairTree = gen.mkTuple(List(Literal(Constant(name)), Literal(Constant(line))))
50+
Apply(Select(gen.mkAttributedRef(ListModule), nme.apply), List(pairTree))
51+
case List() =>
52+
gen.mkNil
53+
}
54+
55+
/** Creates a tree that calls the factory method called constructor in object reflect.SourceContext */
56+
def sourceInfoFactoryCall(typer: Typer, infoTree: Tree, constructor: String, args: Tree*): Tree =
57+
if (args contains EmptyTree) EmptyTree
58+
else typer.typedPos(infoTree.pos.focus) {
59+
Apply(
60+
Select(gen.mkAttributedRef(SourceContextModule), constructor),
61+
args.toList
62+
)
63+
}
64+
65+
def methodNameOf(tree: Tree) = {
66+
tree match {
67+
case Apply(TypeApply(s, _), _) => s.symbol.name
68+
case Apply(s@Select(_, _), _) => s.symbol.name
69+
case Apply(s@Ident(_), _) => s.symbol.name
70+
case Apply(Apply(s, _), _) => s.symbol.name
71+
case s@Select(_, _) => s.symbol.name
72+
case other => ""
73+
}
74+
}
75+
76+
def receiverOptOf(tree: Tree) = {
77+
try {
78+
tree match {
79+
case Apply(TypeApply(Select(recv, _), _), _) => Some(recv.symbol.name)
80+
case Apply(Select(recv, _), _) => Some(recv.symbol.name)
81+
case Select(recv, _) => Some(recv.symbol.name)
82+
case _ => None
83+
}
84+
} catch {
85+
case npe: NullPointerException =>
86+
None
87+
}
88+
}
89+
90+
def sourceInfo(typer: Typer, infoContext: Context, infoTree: Tree): SearchResult = {
91+
def srcInfo()(implicit from: List[Symbol] = List(), to: List[Type] = List()): SearchResult = {
92+
implicit def wrapResult(tree: Tree): SearchResult =
93+
if (tree == EmptyTree) SearchFailure else new SearchResult(tree, new TreeTypeSubstituter(from, to))
94+
95+
val methodName = methodNameOf(infoTree)
96+
val receiver = receiverOptOf(infoTree)
97+
98+
//println("context source info chain:")
99+
//println(contextInfoChain)
100+
//println("source info tree:")
101+
//println(sourceInfoTree(contextInfoChain))
102+
103+
val position = infoTree.pos.focus
104+
val fileName = if (position.isDefined) position.source.file.absolute.path
105+
else "<unknown file>"
106+
if (receiver.isEmpty)
107+
sourceInfoFactoryCall(typer, infoTree, "apply", Literal(Constant(fileName)), Literal(Constant(methodName.toString)), sourceInfoTree(contextInfoChain(infoContext, infoTree)))
108+
else
109+
sourceInfoFactoryCall(typer, infoTree, "apply", Literal(Constant(fileName)), Literal(Constant(methodName.toString)), Literal(Constant(receiver.get.toString)), sourceInfoTree(contextInfoChain(infoContext, infoTree)))
110+
}
111+
112+
srcInfo()
113+
}
114+
115+
def sourceLocation(typer: Typer, infoTree: Tree): SearchResult = {
116+
/** Creates a tree that calls the factory method called constructor in object reflect.SourceLocation */
117+
def sourceLocationFactoryCall(constructor: String, args: Tree*): Tree =
118+
if (args contains EmptyTree) EmptyTree
119+
else typer.typedPos(infoTree.pos.focus) {
120+
Apply(
121+
Select(gen.mkAttributedRef(SourceLocationModule), constructor),
122+
args.toList
123+
)
124+
}
125+
126+
def srcLocation()(implicit from: List[Symbol] = List(), to: List[Type] = List()): SearchResult = {
127+
implicit def wrapResult(tree: Tree): SearchResult =
128+
if (tree == EmptyTree) SearchFailure else new SearchResult(tree, new TreeTypeSubstituter(from, to))
129+
130+
val position = infoTree.pos.focus
131+
val fileName = if (position.isDefined) position.source.file.absolute.path
132+
else "<unknown file>"
133+
sourceLocationFactoryCall("apply", Literal(Constant(position.line)), Literal(Constant(position.point)), Literal(Constant(fileName)))
134+
}
135+
136+
srcLocation()
137+
}
138+
139+
/** Update search result, so that it has the correct source position.
140+
* Invoke `update` on SourceContexts for chaining.
141+
*/
142+
def updatedWithSourceContext(typer: Typer, tree: Tree, pt: Type, context: Context, previous: SearchResult, updateSourceContext: Boolean): SearchResult = pt/*.dealias*/ match {
143+
case TypeRef(_, SourceContextClass, _) if updateSourceContext =>
144+
val position = tree.pos.focus
145+
val fileName = if (position.isDefined) position.source.file.absolute.path
146+
else "<unknown file>"
147+
val methodName = methodNameOf(tree)
148+
val receiver = receiverOptOf(tree)
149+
new SearchResult(typer.typedPos(position) {
150+
// use sourceInfoFactoryCall to construct SourceContext
151+
val factoryCall = if (receiver.isEmpty)
152+
sourceInfoFactoryCall(typer, tree, "apply", Literal(Constant(fileName)), Literal(Constant(methodName.toString)), sourceInfoTree(contextInfoChain(context, tree)))
153+
else
154+
sourceInfoFactoryCall(typer, tree, "apply", Literal(Constant(fileName)), Literal(Constant(methodName.toString)), Literal(Constant(receiver.get.toString)), sourceInfoTree(contextInfoChain(context, tree)))
155+
Apply(Select(previous.tree, "update"), List(factoryCall))
156+
}, previous.subst)
157+
case TypeRef(_, SourceLocationClass, _) =>
158+
val position = tree.pos.focus
159+
new SearchResult(typer.typedPos(position) {
160+
sourceLocation(typer, tree).tree
161+
}, previous.subst)
162+
case _ => previous
163+
}
164+
165+
}

0 commit comments

Comments
 (0)