This page is no longer maintained — Please continue to the home page at www.scala-lang.org

How to use <:< on 'more sophisticated' types

2 replies
Johannes Rudolph
Joined: 2008-12-17,
User offline. Last seen 29 weeks 22 hours ago.

Hi Scala experts,

I'm currently experimenting with the Scala compiler. I'm trying to
reuse the compiler infrastructure to - roughly spoken - answer queries
about objects (packages, classes, modules, methods) in the namespace.
For example, I would want to extract all methods which return a
particular type. Of course, I don't want to recreate the complete type
system and the class loader infrastructure, so reusing the compiler
seems like the best solution.

For now, I want at least such a system:

* Parse a candidate type given as String into symtab.Type
* Enumerate the complete namespace (I think I figured that out, at
least partly)
* Match elements of the namespace according to the candidate type

My playground was the interpreter and I used a script along these lines:

:power
val c = interpreter.compiler
def s(str:String) = {
val Ana = c.analyzer

val unit = new c.CompilationUnit(new
scala.tools.nsc.util.BatchSourceFile("",str))
val scanner = new c.syntaxAnalyzer.UnitParser(unit)
val root = Ana.rootContext(unit)
val namer = Ana.newNamer(root)
val tpt = scanner.typ

val ctx = namer.enterSym(tpt)

val typer = Ana.newTyper(root)
//typer.typedType(tpt,4)
(typer,tpt)
}
s("_root_.scala.String")

Hand-feeding the parser, namer and typer is probably not such a glad
idea, especially because I'm just working with TypeTrees and I didn't
manage to convert a TypeTree into a Type (one try ended with a
StackOverflowError in the typer, another try just didn't find the
names in the namespace, I'm probably doing something wrong with the
Contexts). But I think that are not my biggest problems, since I could
just use the type in the interpreter (e.g. "val x: = null")
and extract the type information from the compilation result just as
the interpreter is doing itself.

My current stumbling-block and what this question is about, is mainly
how to get a Type value which works correctly with the <:< operation.
What I wanted to do is check if this relation is checked correctly:

scala.collection.Seq[Int] <:< scala.collection.Iterable[Int]

So, as explained before I extracted such a type from the interpreter
result and ran that expression and it returned false. I've lost the
exact output of explainTypes, so this is just as I remember:

scala.collection.Seq[Int] <:< scala.collection.Iterable[Int]
scala.collection.Iterable[Int] <:< scala.collection.Iterable => false
=> false

So my questions:
1.) Is my premise right: this relation should be true? (I'm working
with 2.8 r19722 for no particular reason)
2.) Is <:< the standard way in the compiler to check if two types are
compatible or is there some other kind of more sophisticated mechanism
which is there at play?
3.) My guess was, that the Type values I've used are just rawTypeRefs
which I assumed to be 'types without full type information, yet' and
that's why it isn't working. Is this correct? If yes, how can I create
type objects with full featured <:<?

Who can give some hints to enlarge my amateurish Scala compiler
know-how? If you think I could have known things better and should
read some information first, feel free to point me in the right
direction and I'll do more research before bugging you further :)

Thank you!

Adriaan Moors
Joined: 2009-04-03,
User offline. Last seen 42 years 45 weeks ago.
Re: How to use <:< on 'more sophisticated' types
Hi Johannes,
While :power is very cool, you don't really need it for this kind of experiment. Here's a script that I hope will get you on your way. 
import scala.tools.nsc._ import interactive._import reporters._import util._
val settings = new Settings()settings.Ytyperdebug.value = truesettings.debug.value = true
val reporter = new ConsoleReporter(settings)val compiler = new interactive.Global(settings, reporter)
import compiler._
val src = new BatchSourceFile("<test>","object Test { type X = List[String]; type Y = Iterable[String]}")
typedTree(src, true)
res0: compiler.Tree = package <empty> {  final <module> object Test extends lang.this.Object with scala.this.ScalaObject {     <method> def this(): object <empty>.this.Test = {      Test.super.this();      ()    };    type X = <root>.this.scala.package.List[scala.this.Predef.String];     type Y = <root>.this.scala.package.Iterable[scala.this.Predef.String]  }}
scala> res0.children flatMap (_.children) flatMap (_.children)          res1: List[compiler.Tree] = List(lang.this.Object, scala.this.ScalaObject, private val _ = _, <method> def this(): object <empty>.this.Test = {  Test.super.this();  () }, type X = <root>.this.scala.package.List[scala.this.Predef.String], type Y = <root>.this.scala.package.Iterable[scala.this.Predef.String])

scala> res1(4) match {case TypeDef(mods: Modifiers, name: Name, tparams: List[TypeDef], rhs: Tree)  => rhs.tpe} res2: compiler.Type = <root>.this.scala.package.List[scala.this.Predef.String]
scala> res1(5) match {case TypeDef(mods: Modifiers, name: Name, tparams: List[TypeDef], rhs: Tree)  => rhs.tpe} res3: compiler.Type = <root>.this.scala.package.Iterable[scala.this.Predef.String]
scala> res2 <:< res3res4: Boolean = true

cheers adriaan
On Sat, Nov 28, 2009 at 1:55 PM, Johannes Rudolph <johannes.rudolph@googlemail.com> wrote:
Hi Scala experts,

I'm currently experimenting with the Scala compiler. I'm trying to
reuse the compiler infrastructure to - roughly spoken - answer queries
about objects (packages, classes, modules, methods) in the namespace.
For example, I would want to extract all methods which return a
particular type. Of course, I don't want to recreate the complete type
system and the class loader infrastructure, so reusing the compiler
seems like the best solution.

For now, I want at least such a system:

 * Parse a candidate type given as String into symtab.Type
 * Enumerate the complete namespace (I think I figured that out, at
least partly)
 * Match elements of the namespace according to the candidate type

My playground was the interpreter and I used a script along these lines:

:power
val c = interpreter.compiler
def s(str:String) = {
 val Ana = c.analyzer

 val unit = new c.CompilationUnit(new
scala.tools.nsc.util.BatchSourceFile("<test>",str))
 val scanner = new c.syntaxAnalyzer.UnitParser(unit)
 val root = Ana.rootContext(unit)
 val namer = Ana.newNamer(root)
 val tpt = scanner.typ

 val ctx = namer.enterSym(tpt)

 val typer = Ana.newTyper(root)
 //typer.typedType(tpt,4)
 (typer,tpt)
}
s("_root_.scala.String")

Hand-feeding the parser, namer and typer is probably not such a glad
idea, especially because I'm just working with TypeTrees and I didn't
manage to convert a TypeTree into a Type (one try ended with a
StackOverflowError in the typer, another try just didn't find the
names in the namespace, I'm probably doing something wrong with the
Contexts). But I think that are not my biggest problems, since I could
just use the type in the interpreter (e.g. "val x:<my type> = null")
and extract the type information from the compilation result just as
the interpreter is doing itself.

My current stumbling-block and what this question is about, is mainly
how to get a Type value which works correctly with the <:< operation.
What I wanted to do is check if this relation is checked correctly:

scala.collection.Seq[Int] <:< scala.collection.Iterable[Int]

So, as explained before I extracted such a type from the interpreter
result and ran that expression and it returned false. I've lost the
exact output of explainTypes, so this is just as I remember:

scala.collection.Seq[Int] <:< scala.collection.Iterable[Int]
  scala.collection.Iterable[Int] <:< scala.collection.Iterable => false
=> false

So my questions:
 1.) Is my premise right: this relation should be true? (I'm working
with 2.8 r19722 for no particular reason)
 2.) Is <:< the standard way in the compiler to check if two types are
compatible or is there some other kind of more sophisticated mechanism
which is there at play?
 3.) My guess was, that the Type values I've used are just rawTypeRefs
which I assumed to be 'types without full type information, yet' and
that's why it isn't working. Is this correct? If yes, how can I create
type objects with full featured <:<?

Who can give some hints to enlarge my amateurish Scala compiler
know-how? If you think I could have known things better and should
read some information first, feel free to point me in the right
direction and I'll do more research before bugging you further :)

Thank you!
--
Johannes

-----------------------------------------------
Johannes Rudolph
http://virtual-void.net


Disclaimer: http://www.kuleuven.be/cwis/email_disclaimer.htm

Johannes Rudolph
Joined: 2008-12-17,
User offline. Last seen 29 weeks 22 hours ago.
Re: How to use <:< on 'more sophisticated' types

Hi Adriaan,

that's a perfect starting point I can build upon.

Thanks
Johannes

On Mon, Nov 30, 2009 at 12:17 PM, Adriaan Moors
wrote:
> Hi Johannes,
> While :power is very cool, you don't really need it for this kind of
> experiment. Here's a script that I hope will get you on your way.
> import scala.tools.nsc._
> import interactive._
> import reporters._
> import util._
> val settings = new Settings()
> settings.Ytyperdebug.value = true
> settings.debug.value = true
> val reporter = new ConsoleReporter(settings)
> val compiler = new interactive.Global(settings, reporter)
> import compiler._
> val src = new BatchSourceFile("","object Test { type X = List[String];
> type Y = Iterable[String]}")
> typedTree(src, true)
> res0: compiler.Tree =
> package {
>   final object Test extends lang.this.Object with
> scala.this.ScalaObject {
>      def this(): object .this.Test = {
>       Test.super.this();
>       ()
>     };
>     type X = .this.scala.package.List[scala.this.Predef.String];
>     type Y = .this.scala.package.Iterable[scala.this.Predef.String]
>   }
> }
> scala> res0.children flatMap (_.children) flatMap (_.children)
> res1: List[compiler.Tree] =
> List(lang.this.Object, scala.this.ScalaObject, private val _ = _,
> def this(): object .this.Test = {
>   Test.super.this();
>   ()
> }, type X = .this.scala.package.List[scala.this.Predef.String], type Y
> = .this.scala.package.Iterable[scala.this.Predef.String])
>
> scala> res1(4) match {case TypeDef(mods: Modifiers, name: Name, tparams:
> List[TypeDef], rhs: Tree)  => rhs.tpe}
> res2: compiler.Type =
> .this.scala.package.List[scala.this.Predef.String]
> scala> res1(5) match {case TypeDef(mods: Modifiers, name: Name, tparams:
> List[TypeDef], rhs: Tree)  => rhs.tpe}
> res3: compiler.Type =
> .this.scala.package.Iterable[scala.this.Predef.String]
> scala> res2 <:< res3
> res4: Boolean = true
>
> cheers
> adriaan
> On Sat, Nov 28, 2009 at 1:55 PM, Johannes Rudolph
> wrote:
>>
>> Hi Scala experts,
>>
>> I'm currently experimenting with the Scala compiler. I'm trying to
>> reuse the compiler infrastructure to - roughly spoken - answer queries
>> about objects (packages, classes, modules, methods) in the namespace.
>> For example, I would want to extract all methods which return a
>> particular type. Of course, I don't want to recreate the complete type
>> system and the class loader infrastructure, so reusing the compiler
>> seems like the best solution.
>>
>> For now, I want at least such a system:
>>
>>  * Parse a candidate type given as String into symtab.Type
>>  * Enumerate the complete namespace (I think I figured that out, at
>> least partly)
>>  * Match elements of the namespace according to the candidate type
>>
>> My playground was the interpreter and I used a script along these lines:
>>
>> :power
>> val c = interpreter.compiler
>> def s(str:String) = {
>>  val Ana = c.analyzer
>>
>>  val unit = new c.CompilationUnit(new
>> scala.tools.nsc.util.BatchSourceFile("",str))
>>  val scanner = new c.syntaxAnalyzer.UnitParser(unit)
>>  val root = Ana.rootContext(unit)
>>  val namer = Ana.newNamer(root)
>>  val tpt = scanner.typ
>>
>>  val ctx = namer.enterSym(tpt)
>>
>>  val typer = Ana.newTyper(root)
>>  //typer.typedType(tpt,4)
>>  (typer,tpt)
>> }
>> s("_root_.scala.String")
>>
>> Hand-feeding the parser, namer and typer is probably not such a glad
>> idea, especially because I'm just working with TypeTrees and I didn't
>> manage to convert a TypeTree into a Type (one try ended with a
>> StackOverflowError in the typer, another try just didn't find the
>> names in the namespace, I'm probably doing something wrong with the
>> Contexts). But I think that are not my biggest problems, since I could
>> just use the type in the interpreter (e.g. "val x: = null")
>> and extract the type information from the compilation result just as
>> the interpreter is doing itself.
>>
>> My current stumbling-block and what this question is about, is mainly
>> how to get a Type value which works correctly with the <:< operation.
>> What I wanted to do is check if this relation is checked correctly:
>>
>> scala.collection.Seq[Int] <:< scala.collection.Iterable[Int]
>>
>> So, as explained before I extracted such a type from the interpreter
>> result and ran that expression and it returned false. I've lost the
>> exact output of explainTypes, so this is just as I remember:
>>
>> scala.collection.Seq[Int] <:< scala.collection.Iterable[Int]
>>   scala.collection.Iterable[Int] <:< scala.collection.Iterable => false
>> => false
>>
>> So my questions:
>>  1.) Is my premise right: this relation should be true? (I'm working
>> with 2.8 r19722 for no particular reason)
>>  2.) Is <:< the standard way in the compiler to check if two types are
>> compatible or is there some other kind of more sophisticated mechanism
>> which is there at play?
>>  3.) My guess was, that the Type values I've used are just rawTypeRefs
>> which I assumed to be 'types without full type information, yet' and
>> that's why it isn't working. Is this correct? If yes, how can I create
>> type objects with full featured <:<?
>>
>> Who can give some hints to enlarge my amateurish Scala compiler
>> know-how? If you think I could have known things better and should
>> read some information first, feel free to point me in the right
>> direction and I'll do more research before bugging you further :)
>>
>> Thank you!
>> --
>> Johannes
>>
>> -----------------------------------------------
>> Johannes Rudolph
>> http://virtual-void.net
>>
>>
>> Disclaimer: http://www.kuleuven.be/cwis/email_disclaimer.htm
>
>

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland