Skip to content

Topic/virt sourcecontext #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 2, 2012
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 3 additions & 145 deletions src/compiler/scala/tools/nsc/typechecker/Implicits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import util.Statistics._
* @author Martin Odersky
* @version 1.0
*/
trait Implicits {
trait Implicits extends SourceContextUtils {
self: Analyzer =>

import global._
Expand Down Expand Up @@ -1112,126 +1112,6 @@ trait Implicits {
implicitInfoss1
}

def contextSourceInfoChain(ctx: Context,
stopAt: Context,
prevValDef: Option[String]): List[(String, Int)] = {
if (ctx == stopAt)
List()
else ctx.tree match {
case vd @ ValDef(_, name, _, _) if prevValDef.isEmpty || (!prevValDef.get.equals(name.toString)) =>
(name.toString, vd.pos.line) :: contextSourceInfoChain(ctx.outer, stopAt, Some(name.toString))
//case app @ Apply(fun, args) if fun.symbol.isMethod =>
// (fun.symbol.nameString, fun.pos.line) :: contextSourceInfoChain(ctx.outer, stopAt)
case _ =>
contextSourceInfoChain(ctx.outer, stopAt, None)
}
}

def contextInfoChain = context0.tree match {
case vd @ ValDef(_, name, _, _) =>
//println("current context tree is ValDef "+name)
contextSourceInfoChain(context0, context0.enclClass, None)
case _ =>
//println("current context tree: "+context0.tree)
val l = tree.pos match {
case NoPosition => 0
case _ => tree.pos.line
}
(null, l) :: contextSourceInfoChain(context0.outer, context0.outer.enclClass, None)
}

def sourceInfoTree(chain: List[(String, Int)]): Tree = chain match {
case (name, line) :: rest =>
val pairTree = gen.mkTuple(List(Literal(Constant(name)), Literal(Constant(line))))
Apply(Select(gen.mkAttributedRef(ListModule), nme.apply), List(pairTree))
case List() =>
gen.mkNil
}

/** Creates a tree that calls the factory method called constructor in object reflect.SourceContext */
def sourceInfoFactoryCall(constructor: String, args: Tree*): Tree =
if (args contains EmptyTree) EmptyTree
else typedPos(tree.pos.focus) {
Apply(
Select(gen.mkAttributedRef(SourceContextModule), constructor),
args.toList
)
}

private def methodNameOf(tree: Tree) = {
tree match {
case Apply(TypeApply(s, _), _) => s.symbol.name
case Apply(s@Select(_, _), _) => s.symbol.name
case Apply(s@Ident(_), _) => s.symbol.name
case Apply(Apply(s, _), _) => s.symbol.name
case s@Select(_, _) => s.symbol.name
case other => ""
}
}

private def receiverOptOf(tree: Tree) = {
try {
tree match {
case Apply(TypeApply(Select(recv, _), _), _) => Some(recv.symbol.name)
case Apply(Select(recv, _), _) => Some(recv.symbol.name)
case Select(recv, _) => Some(recv.symbol.name)
case _ => None
}
} catch {
case npe: NullPointerException =>
None
}
}

private def sourceInfo(): SearchResult = {
def srcInfo()(implicit from: List[Symbol] = List(), to: List[Type] = List()): SearchResult = {
implicit def wrapResult(tree: Tree): SearchResult =
if (tree == EmptyTree) SearchFailure else new SearchResult(tree, new TreeTypeSubstituter(from, to))

val methodName = methodNameOf(tree)
val receiver = receiverOptOf(tree)

//println("context source info chain:")
//println(contextInfoChain)
//println("source info tree:")
//println(sourceInfoTree(contextInfoChain))

val position = tree.pos.focus
val fileName = if (position.isDefined) position.source.file.absolute.path
else "<unknown file>"
if (receiver.isEmpty)
sourceInfoFactoryCall("apply", Literal(Constant(fileName)), Literal(Constant(methodName.toString)), sourceInfoTree(contextInfoChain))
else
sourceInfoFactoryCall("apply", Literal(Constant(fileName)), Literal(Constant(methodName.toString)), Literal(Constant(receiver.get.toString)), sourceInfoTree(contextInfoChain))
}

srcInfo()
}

private def sourceLocation(): SearchResult = {
/** Creates a tree that calls the factory method called constructor in object reflect.SourceLocation */
def sourceLocationFactoryCall(constructor: String, args: Tree*): Tree =
if (args contains EmptyTree) EmptyTree
else typedPos(tree.pos.focus) {
Apply(
Select(gen.mkAttributedRef(SourceLocationModule), constructor),
args.toList
)
}

def srcLocation()(implicit from: List[Symbol] = List(), to: List[Type] = List()): SearchResult = {
implicit def wrapResult(tree: Tree): SearchResult =
if (tree == EmptyTree) SearchFailure else new SearchResult(tree, new TreeTypeSubstituter(from, to))

val position = tree.pos.focus
val fileName = if (position.isDefined) position.source.file.absolute.path
else "<unknown file>"
sourceLocationFactoryCall("apply", Literal(Constant(position.line)), Literal(Constant(position.point)), Literal(Constant(fileName)))
}

srcLocation()
}

/** Creates a tree that calls the relevant factory method in object
* reflect.Manifest for type 'tp'. An EmptyTree is returned if
* no manifest is found. todo: make this instantiate take type params as well?
Expand Down Expand Up @@ -1382,7 +1262,7 @@ trait Implicits {
pt.dealias match {
case TypeRef(_, SourceContextClass, _) =>
// construct new SourceContext instance
result = sourceInfo()
result = sourceInfo(this, context0, tree)
// there is no existing SourceContext to chain with
updateSourceContext = false
case _ =>
Expand All @@ -1397,29 +1277,7 @@ trait Implicits {
if (result == SearchFailure && settings.debug.value)
log("no implicits found for "+pt+" "+pt.typeSymbol.info.baseClasses+" "+implicitsOfExpectedType)

val updatedRes = pt/*.dealias*/ match {
case TypeRef(_, SourceContextClass, _) if updateSourceContext =>
val position = tree.pos.focus
val fileName = if (position.isDefined) position.source.file.absolute.path
else "<unknown file>"
val methodName = methodNameOf(tree)
val receiver = receiverOptOf(tree)
new SearchResult(typedPos(position) {
// use sourceInfoFactoryCall to construct SourceContext
val factoryCall = if (receiver.isEmpty)
sourceInfoFactoryCall("apply", Literal(Constant(fileName)), Literal(Constant(methodName.toString)), sourceInfoTree(contextInfoChain))
else
sourceInfoFactoryCall("apply", Literal(Constant(fileName)), Literal(Constant(methodName.toString)), Literal(Constant(receiver.get.toString)), sourceInfoTree(contextInfoChain))
Apply(Select(result.tree, "update"), List(factoryCall))
}, result.subst)
case TypeRef(_, SourceLocationClass, _) =>
val position = tree.pos.focus
new SearchResult(typedPos(position) {
sourceLocation().tree
}, result.subst)
case _ => result
}
updatedRes
updatedWithSourceContext(this, tree, pt, context0, result, updateSourceContext)
}

def allImplicits: List[SearchResult] = {
Expand Down
165 changes: 165 additions & 0 deletions src/compiler/scala/tools/nsc/typechecker/SourceContextUtils.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
/* NSC -- new Scala compiler
* Copyright 2005-2011 LAMP/EPFL
* @author Martin Odersky
*/

package scala.tools.nsc
package typechecker

/* Utilities for generating SourceLocations and SourceContexts.
*
* @author Philipp Haller
*/
trait SourceContextUtils {
self: Analyzer =>

import global._
import definitions._

def contextSourceInfoChain(ctx: Context,
stopAt: Context,
prevValDef: Option[String]): List[(String, Int)] = {
if (ctx == stopAt)
List()
else ctx.tree match {
case vd @ ValDef(_, name, _, _) if prevValDef.isEmpty || (!prevValDef.get.equals(name.toString)) =>
(name.toString, vd.pos.line) :: contextSourceInfoChain(ctx.outer, stopAt, Some(name.toString))
//case app @ Apply(fun, args) if fun.symbol.isMethod =>
// (fun.symbol.nameString, fun.pos.line) :: contextSourceInfoChain(ctx.outer, stopAt)
case _ =>
contextSourceInfoChain(ctx.outer, stopAt, None)
}
}

def contextInfoChain(ctx: Context, tree: Tree) = ctx.tree match {
case vd @ ValDef(_, name, _, _) =>
//println("current context tree is ValDef "+name)
contextSourceInfoChain(ctx, ctx.enclClass, None)
case _ =>
//println("current context tree: "+ctx.tree)
val l = tree.pos match {
case NoPosition => 0
case _ => tree.pos.line
}
(null, l) :: contextSourceInfoChain(ctx.outer, ctx.outer.enclClass, None)
}

def sourceInfoTree(chain: List[(String, Int)]): Tree = chain match {
case (name, line) :: rest =>
val pairTree = gen.mkTuple(List(Literal(Constant(name)), Literal(Constant(line))))
Apply(Select(gen.mkAttributedRef(ListModule), nme.apply), List(pairTree))
case List() =>
gen.mkNil
}

/** Creates a tree that calls the factory method called constructor in object reflect.SourceContext */
def sourceInfoFactoryCall(typer: Typer, infoTree: Tree, constructor: String, args: Tree*): Tree =
if (args contains EmptyTree) EmptyTree
else typer.typedPos(infoTree.pos.focus) {
Apply(
Select(gen.mkAttributedRef(SourceContextModule), constructor),
args.toList
)
}

def methodNameOf(tree: Tree) = {
tree match {
case Apply(TypeApply(s, _), _) => s.symbol.name
case Apply(s@Select(_, _), _) => s.symbol.name
case Apply(s@Ident(_), _) => s.symbol.name
case Apply(Apply(s, _), _) => s.symbol.name
case s@Select(_, _) => s.symbol.name
case other => ""
}
}

def receiverOptOf(tree: Tree) = {
try {
tree match {
case Apply(TypeApply(Select(recv, _), _), _) => Some(recv.symbol.name)
case Apply(Select(recv, _), _) => Some(recv.symbol.name)
case Select(recv, _) => Some(recv.symbol.name)
case _ => None
}
} catch {
case npe: NullPointerException =>
None
}
}

def sourceInfo(typer: Typer, infoContext: Context, infoTree: Tree): SearchResult = {
def srcInfo()(implicit from: List[Symbol] = List(), to: List[Type] = List()): SearchResult = {
implicit def wrapResult(tree: Tree): SearchResult =
if (tree == EmptyTree) SearchFailure else new SearchResult(tree, new TreeTypeSubstituter(from, to))

val methodName = methodNameOf(infoTree)
val receiver = receiverOptOf(infoTree)

//println("context source info chain:")
//println(contextInfoChain)
//println("source info tree:")
//println(sourceInfoTree(contextInfoChain))

val position = infoTree.pos.focus
val fileName = if (position.isDefined) position.source.file.absolute.path
else "<unknown file>"
if (receiver.isEmpty)
sourceInfoFactoryCall(typer, infoTree, "apply", Literal(Constant(fileName)), Literal(Constant(methodName.toString)), sourceInfoTree(contextInfoChain(infoContext, infoTree)))
else
sourceInfoFactoryCall(typer, infoTree, "apply", Literal(Constant(fileName)), Literal(Constant(methodName.toString)), Literal(Constant(receiver.get.toString)), sourceInfoTree(contextInfoChain(infoContext, infoTree)))
}

srcInfo()
}

def sourceLocation(typer: Typer, infoTree: Tree): SearchResult = {
/** Creates a tree that calls the factory method called constructor in object reflect.SourceLocation */
def sourceLocationFactoryCall(constructor: String, args: Tree*): Tree =
if (args contains EmptyTree) EmptyTree
else typer.typedPos(infoTree.pos.focus) {
Apply(
Select(gen.mkAttributedRef(SourceLocationModule), constructor),
args.toList
)
}

def srcLocation()(implicit from: List[Symbol] = List(), to: List[Type] = List()): SearchResult = {
implicit def wrapResult(tree: Tree): SearchResult =
if (tree == EmptyTree) SearchFailure else new SearchResult(tree, new TreeTypeSubstituter(from, to))

val position = infoTree.pos.focus
val fileName = if (position.isDefined) position.source.file.absolute.path
else "<unknown file>"
sourceLocationFactoryCall("apply", Literal(Constant(position.line)), Literal(Constant(position.point)), Literal(Constant(fileName)))
}

srcLocation()
}

/** Update search result, so that it has the correct source position.
* Invoke `update` on SourceContexts for chaining.
*/
def updatedWithSourceContext(typer: Typer, tree: Tree, pt: Type, context: Context, previous: SearchResult, updateSourceContext: Boolean): SearchResult = pt/*.dealias*/ match {
case TypeRef(_, SourceContextClass, _) if updateSourceContext =>
val position = tree.pos.focus
val fileName = if (position.isDefined) position.source.file.absolute.path
else "<unknown file>"
val methodName = methodNameOf(tree)
val receiver = receiverOptOf(tree)
new SearchResult(typer.typedPos(position) {
// use sourceInfoFactoryCall to construct SourceContext
val factoryCall = if (receiver.isEmpty)
sourceInfoFactoryCall(typer, tree, "apply", Literal(Constant(fileName)), Literal(Constant(methodName.toString)), sourceInfoTree(contextInfoChain(context, tree)))
else
sourceInfoFactoryCall(typer, tree, "apply", Literal(Constant(fileName)), Literal(Constant(methodName.toString)), Literal(Constant(receiver.get.toString)), sourceInfoTree(contextInfoChain(context, tree)))
Apply(Select(previous.tree, "update"), List(factoryCall))
}, previous.subst)
case TypeRef(_, SourceLocationClass, _) =>
val position = tree.pos.focus
new SearchResult(typer.typedPos(position) {
sourceLocation(typer, tree).tree
}, previous.subst)
case _ => previous
}

}