Skip to content

WIP trace logging for as-seen-from #124

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

Open
wants to merge 1 commit into
base: 2.13.x
Choose a base branch
from
Open
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
8 changes: 4 additions & 4 deletions src/reflect/scala/reflect/internal/tpe/TypeMaps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@ private[internal] trait TypeMaps {
* @param lhs its symbol is a type parameter of `clazz`
* @param rhs a type application constructed from `clazz`
*/
private def correspondingTypeArgument(lhs: Type, rhs: Type): Type = {
protected def correspondingTypeArgument(lhs: Type, rhs: Type): Type = {
val TypeRef(_, lhsSym, lhsArgs) = lhs: @unchecked
val TypeRef(_, rhsSym, rhsArgs) = rhs: @unchecked
require(lhsSym.owner == rhsSym, s"$lhsSym is not a type parameter of $rhsSym")
Expand Down Expand Up @@ -551,7 +551,7 @@ private[internal] trait TypeMaps {
// are not influenced by the prefix through which they are seen. Note that type params of
// anonymous type functions, which currently can only arise from normalising type aliases, are
// owned by the type alias of which they are the eta-expansion.
private def classParameterAsSeen(classParam: TypeRef): Type = {
protected def classParameterAsSeen(classParam: TypeRef): Type = {
val tparam = classParam.sym

@tailrec
Expand All @@ -574,7 +574,7 @@ private[internal] trait TypeMaps {
}

// Does the candidate symbol match the given prefix and class?
private def matchesPrefixAndClass(pre: Type, clazz: Symbol)(candidate: Symbol) = (clazz == candidate) && {
protected def matchesPrefixAndClass(pre: Type, clazz: Symbol)(candidate: Symbol) = (clazz == candidate) && {
val pre1 = pre match {
case tv: TypeVar =>
// Needed with existentials in prefixes, e.g. test/files/pos/typevar-in-prefix.scala
Expand Down Expand Up @@ -633,7 +633,7 @@ private[internal] trait TypeMaps {
}
}

private def thisTypeAsSeen(tp: ThisType): Type = {
protected def thisTypeAsSeen(tp: ThisType): Type = {
@tailrec
def loop(pre: Type, clazz: Symbol): Type = {
val pre1 = pre match {
Expand Down
152 changes: 152 additions & 0 deletions test/junit/scala/reflect/internal/AsSeenFromTest.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
package scala.reflect.internal

import org.junit.Assert._
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.junit.{After, Assert, Before, Test}

import scala.annotation.StaticAnnotation
import scala.collection.mutable
import scala.language.existentials
import scala.tools.nsc.settings.ScalaVersion
import scala.tools.nsc.symtab.SymbolTableForUnitTesting

@RunWith(classOf[JUnit4])
class AsSeenFromTest {

object symbolTable extends SymbolTableForUnitTesting

import symbolTable._
import definitions._

type EmptyList[A] = Nil.type

class ann[A] extends StaticAnnotation

trait A[B] {
def foo: B
trait A_I {
def foo: B
}
}

trait B extends A[Int] {
trait B_I extends A_I
}

trait C extends A[Int] {
trait B_I extends A[String]
}
@Test
def asSeenFrom(): Unit = {
assertEquals(typeOf[Int], fooResult(typeOf[B]))
assertEquals(typeOf[Int], fooResult(typeOf[B#B_I]))
assertEquals(typeOf[String], fooResult(typeOf[C#B_I]))
}

object asSeenFrom2Types {

trait O1[O1_A] {
type O1_A_Alias = O1_A
trait I1[I1_A] {
type I1_A_Alias = I1_A
def foo: O1_A_Alias
def bar(x: O1_A_Alias): Unit
}
}

trait O2 extends O1[Int] {
trait I2 extends I1[String] with O1[Nothing] {
self: X =>
bar(self.foo)
}
}
trait X
val o2: O2 = ???
val pre: o2.I2 with X = ???
}

@Test def asSeenFrom2(): Unit = {
import asSeenFrom2Types._
val seenFronTyoe = fooResult(ThisType(symbolOf[O2#I2]))
assertEquals(TypeRef(ThisType(symbolOf[O2]), typeOf[O1[_]].member(TypeName("O1_A_Alias")), Nil), seenFronTyoe)
assertTrue(typeOf[Int] =:= seenFronTyoe)
}

@Test def t21585(): Unit = {
import t21585Types._

// apply(O1.this.O1_A_Alias : NullaryMethodType)
// apply(O1.this.O1_A_Alias : AliasNoArgsTypeRef)
// apply(O1.this.type : UniqueThisType)
// thisTypeAsSeen(O1.this.type)
// matchesPrefixAndClass(pre=I2.this.type, class=trait I1)(candidate=trait O1)
// = false
// matchesPrefixAndClass(pre=O2.this.type, class=trait O1)(candidate=trait O1)
// = true
// = O2.this.type
// = O2.this.type
// = O2.this.O1_A_Alias
//= O2.this.O1_A_Alias
val seenFromType = fooResult(ThisType(typeOf[O2].member(TypeName("I2"))))
assertEquals(TypeRef(ThisType(symbolOf[O2]), typeOf[O1[_]].member(TypeName("O1_A_Alias")), Nil), seenFromType)
assertTrue(typeOf[Int] =:= seenFromType)
}

private def fooResult(pre: Type) = {
val member = pre.member(TermName("foo"))
val tpe = member.info
class LoggingAsSeenFromMap(seenFromPrefix: Type, seenFromClass: Symbol, debug: Boolean = false, var indentLevel: Int = 0)
extends AsSeenFromMap(seenFromPrefix, seenFromClass) {

def logged[T](message: String, op: => T): T = if (debug) {
println(s"${" " * indentLevel}${message.replace('\n', ' ')}")
indentLevel += 1
val result = op
indentLevel -= 1
println(s"${" " * indentLevel}= $result")
result
} else op

override def apply(tp: Type): Type = {
logged(s"apply($tp : ${tp.getClass.getSimpleName})", super.apply(tp))
}

override protected def correspondingTypeArgument(lhs: Type, rhs: Type): Type =
logged(s"correspondingTypeArgument($lhs, $rhs)", super.correspondingTypeArgument(lhs, rhs))
override protected def matchesPrefixAndClass(pre: Type, clazz: Symbol)(candidate: Symbol): Boolean =
logged(s"matchesPrefixAndClass(pre=$pre, class=$clazz)(candidate=$candidate)", super.matchesPrefixAndClass(pre, clazz)(candidate))
override protected def classParameterAsSeen(classParam: TypeRef): Type =
logged(s"classParameterAsSeen($classParam)", super.classParameterAsSeen(classParam))
override protected def thisTypeAsSeen(tp: ThisType): Type =
logged(s"thisTypeAsSeen($tp)", super.thisTypeAsSeen(tp))
}
new LoggingAsSeenFromMap(pre, member.owner, debug = true).apply(tpe).resultType
}
}
object t21585Types {

trait O1[O1_A] {
type O1_A_Alias = O1_A
trait I1 {
def foo: O1_A_Alias
def bar(p: O1_A_Alias): Unit = ()
}
}

trait O2 extends O1[Int] {
trait I2 extends I1 with O1[String] {
def goodCodeRed = {
var x = this.foo
x = 1 // good code red
this.bar(1) // good code red
}

// def badCodeGreen = {
// var x = this.foo
// x = "" // bad code green
// this.bar("") // bad code green
// }
}
}
}