Aladdin - Scala Bugtracking
[#1210] project: compiler priority: low category: bug
submitter assigned to status date submitted
Nikolay Adriaan fixed 2007-07-12 12:04:22.0
subject [contrib #687] stack overflow in symtab.Types$TypeRef.normalize
code
object Test
{
    def f[T](recurse: T => List[T]): List[T] =
    {
        Nil
    }

    abstract class M
    { self =>
    	type Settings
    	type selfType = M {type Settings = self.Settings}

        val v: List[selfType] = f[selfType](_.v)
    }

    abstract class M2
    { self =>
    	type Settings
    	type selfType = M2 {type Settings = self.Settings}

        def g: List[selfType] = Nil

        {
			f[selfType](_.g)
        }
    }
}

/*
With 2.5.1-final

Exception in thread "main" java.lang.StackOverflowError
	at scala.tools.nsc.symtab.Symbols$Symbol.rawInfo(Symbols.scala:457)
	at scala.tools.nsc.symtab.Symbols$Symbol.info(Symbols.scala:428)
	at scala.tools.nsc.symtab.Types$TypeRef.normalize(Types.scala:1247)
	at scala.tools.nsc.symtab.Types$TypeRef.normalize(Types.scala:1250)
	at scala.tools.nsc.symtab.Types$TypeRef.normalize(Types.scala:1250)
	at scala.tools.nsc.symtab.Types$TypeRef.normalize(Types.scala:1250)

If we comment out abstract class M, the same stack trace occurs but without the line
	at scala.tools.nsc.symtab.Types$TypeRef.normalize(Types.scala:1247)



With  scala-2.5.1.12278.20070712-044543

Exception in thread "main" java.lang.StackOverflowError
	at scala.tools.nsc.symtab.Types$SubstMap.apply(Types.scala:2153)
	at scala.tools.nsc.symtab.Types$Type.subst(Types.scala:361)
	at scala.tools.nsc.symtab.Types$Type.instantiateTypeParams(Types.scala:244)
	at scala.tools.nsc.symtab.Types$TypeRef.instantiateTypeParams(Types.scala:1271)
	at scala.tools.nsc.symtab.Types$TypeRef.transform(Types.scala:1200)
	at scala.tools.nsc.symtab.Types$TypeRef.normalize(Types.scala:1283)
	at scala.tools.nsc.symtab.Types$TypeRef.normalize(Types.scala:1283)
	at scala.tools.nsc.symtab.Types$TypeRef.normalize(Types.scala:1283)
*/
what happened
stack overflow during compilation
what expected simple error message or successful compilation
[back to overview]
Changes of this bug report
Nikolay  edited on  2007-07-12 12:09:03.0
Adriaan  edited on  2007-07-12 15:11:02.0
well, first off, this looks like an erroneous program, but anyway, I must've made a mistake somewhere in normalize... :-( Furthermore, it looks like two bugs in one. First, it can be simplified to:
object Test {
  def id[T](f: T => T): T = error("bla")
  
  abstract class M { self =>
  	type Settings
  	type selfType = M {type Settings = self.Settings}

    val v: selfType = id[M.this.selfType](_.v)
  }
}
Then, if I apply a quick fix to normalize in TypeRef:
    override def normalize = { 
      if (sym.isAliasType) {
        if (sym.info.typeParams.length == args.length) { 
          var xform=transform(sym.info.resultType)
          if(xform eq this) this // bug1210 -- why is this necessary?  I thought for tp=TypeRef(_, sym, _) 
           // sym.isAliasType implies !(sym.info.resultType eq tp)
          else xform.normalize // cycles have been checked in typeRef (?)
The compiler doesn't crash anymore, but gives the following error
/Users/adriaan/src/scala/trunk/test/files/neg/bug1210.scala:8: error: type mismatch;
 found   : x$0.selfType
 required: M.this.selfType
    val v: selfType = id[M.this.selfType](_.v)
                                           ^
one error found
Note that x$0 seems to escape its scope! If we rewrite using type parameters instead of type members:
object Test {
  def id[T](f: T => T): T = error("bla")
  
  abstract class M[Settings] {
  	type selfType = M[Settings]

    val v: selfType = id[M.this.selfType](_.v)
  }
}
the compiler crashes like this:
Exception in thread "main" java.lang.Error: Settings in class M cannot be instantiated from ?*x$0.type
        at scala.tools.nsc.symtab.Types$AsSeenFromMap.throwError$0(Types.scala:2114)
        at scala.tools.nsc.symtab.Types$AsSeenFromMap.toInstance$0(Types.scala:2136)
$x0 tries to escape its scope again, but here it crashes asSeenFrom...
Adriaan  edited on  2007-07-20 11:32:28.0
I committed the quick fix mentioned above in r12373, so the error wrt the escaping variable becomes apparent (test file in pending/neg/bug1210.scala)
Martin  edited on  2007-07-26 01:04:39.0
Martin  edited on  2007-07-26 11:00:15.0
Stephane  edited on  2007-07-27 13:19:47.0
fixed in rev 12431
Adriaan  edited on  2007-08-20 10:29:31.0
re-opened based on discussion with Martin @ ECOOP (fix is pending)
Adriaan  edited on  2007-08-21 00:06:29.0
proposed fix is in r12604, Martin: please review
Adriaan  edited on  2007-08-21 10:35:05.0
fixed bug in bug fix... see r12605 new implementation of mapOver:
    /** Map this function over given list of symbols */
    def mapOver(origSyms: List[Symbol]): List[Symbol] = { 
      val origInfos = origSyms map (_.info)
      val newInfos = List.mapConserve(origInfos)(this)
      if (newInfos eq origInfos) origSyms // fast path in case nothing changes due to map
      else { // map is not the identity --> do cloning properly
        val clonedSyms = origSyms map (_.cloneSymbol)
        val clonedInfos = clonedSyms map (_.info.substSym(origSyms, clonedSyms))
        val transformedInfos = List.mapConserve(clonedInfos)(this)
        List.map2(clonedSyms, transformedInfos) { 
          ((newSym, newInfo) => newSym.setInfo(newInfo)) 
        }
        clonedSyms
      }
    }
Adriaan  edited on  2007-08-22 15:20:34.0
fixed in r12605