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
VerifyError with separate compilation and method/Object flattening #6493
Comments
Imported From: https://issues.scala-lang.org/browse/SI-6493?orig=1
|
@paulp said: scala> def foo = { class Foo { class Bar { val b = 2 }}; val f = new Foo; new f.Bar }
foo: Object{type Bar <: Object{val b: Int}}#Bar |
Kartik Subramanian (selfification) said (edited by @paulp on Feb 1, 2013 6:57:34 AM UTC): scala> def foo() = { object Foo { class Bar { val x = 1} }; new Foo.Bar }
foo: ()Object{type Bar <: Object{val x: Int}}#Bar
scala> foo()
java.lang.NoSuchMethodError: .foo()Ljava/lang/Object;
at .<init>(<console>:9)
at .<clinit>(<console>)
at .<init>(<console>:7) Now it typechecks.. but doesn't run. Is this expected? Sorry I elided the "new Foo" bit and just made an object Foo. Doing it the long way also raises an exception. |
@paulp said: // a.scala
object one {
def foo() = { object Foo { class Bar } ; new Foo.Bar }
}
// b.scala
object Test {
def main(args: Array[String]): Unit = one.foo
}
% scalac210 a.scala && scalac210 b.scala && scala210 Test
java.lang.NoSuchMethodError: one$.foo()Lone/foo$Foo$Bar;
at Test$.main(b.scala:2)
at Test.main(b.scala) Affects all versions back to at least 2.8. |
@paulp said: |
@retronym said: // end of uncurry
<method> def foo(): lang.this.Object{type Bar <: lang.this.Object}#Bar = {
// end of erasure
<method> def foo(): Foo.Bar = { I'd expect the return type to erase to Seems like we get away with this under joint compilation. |
@retronym said:
It should be:
I believe that this assumption is incorrect: // only need to rebind type aliases, as typeRef already handles abstract types
// (they are allowed to be rebound more liberally)
def coevolveSym(pre1: Type): Symbol = sym Compare with the override in // #3731: return sym1 for which holds: pre bound sym.name to sym and
// pre1 now binds sym.name to sym1, conceptually exactly the same
// symbol as sym. The selection of sym on pre must be updated to the
// selection of sym1 on pre1, since sym's info was probably updated
// by the TypeMap to yield a new symbol, sym1 with transformed info.
// @returns sym1
override def coevolveSym(pre1: Type): Symbol =
if (pre eq pre1) sym else (pre, pre1) match {
// don't look at parents -- it would be an error to override alias types anyway
case (RefinedType(_, _), RefinedType(_, decls1)) => decls1 lookup sym.name
// TODO: is there another way a typeref's symbol can refer to a symbol defined in its pre?
case _ => sym
} |
@retronym said (edited on May 31, 2013 12:12:23 PM UTC): |
@retronym said: |
@adriaanm said: def doSubst(info: Type) = info.substSym(rawSyms, typeParams) // don't use subst, as it won't update pre.sym[args] to pre.newSym[args] unless pre == NoPrefix! |
@adriaanm said: |
@adriaanm said (edited on Feb 11, 2014 10:14:56 PM UTC): |
@adriaanm said: scala> class Test {
| def c: x.X forSome { val x : {type X <: C}; type C } = ???
| lazy val x = c // lazy vals are borked when dealing with existentials
| }
<console>:9: error: type mismatch;
found : x.type(in lazy value x)#X(in <refinement of AnyRef>)(in <refinement of AnyRef>) where type x.type(in lazy value x) <: AnyRef{type X(in <refinement of AnyRef>)(in <refinement of AnyRef>) <: C} with Singleton
required: (some other)x.type(in lazy value x)#X(in <refinement of AnyRef>)(in <refinement of AnyRef>) forSome { type (some other)x.type(in lazy value x) <: AnyRef{type X(in <refinement of AnyRef>)(in <refinement of AnyRef>) <: C} with Singleton; type C }
lazy val x = c // lazy vals are borked when dealing with existentials
^
<console>:9: error: type mismatch;
found : x.type(in value x)#X(in <refinement of AnyRef>)(in <refinement of AnyRef>) where type x.type(in value x) <: AnyRef{type X(in <refinement of AnyRef>)(in <refinement of AnyRef>) <: C} with Singleton
required: x.type(in lazy value x)#X(in <refinement of AnyRef>)(in <refinement of AnyRef>) forSome { type x.type(in lazy value x) <: AnyRef{type X(in <refinement of AnyRef>)(in <refinement of AnyRef>) <: C} with Singleton; type C }
lazy val x = c // lazy vals are borked when dealing with existentials
^
|
@paulp said (edited on Feb 12, 2014 7:29:55 AM UTC): class Test {
val c: x.X forSome { val x : { type X <: AnyRef with C }; type C } = ???
} |
@paulp said: case class Getter(tree: ValDef) extends BaseGetter(tree) {
override def derivedSym = if (mods.isDeferred) basisSym else basisSym.getter(enclClass)
private def derivedRhs = if (mods.isDeferred) EmptyTree else fieldSelection
private def derivedTpt = {
// For existentials, don't specify a type for the getter, even one derived
// from the symbol! This leads to incompatible existentials for the field and
// the getter. Let the typer do all the work. You might think "why only for
// existentials, why not always," and you would be right, except: a single test
// fails, but it looked like some work to deal with it. Test neg/t0606.scala
// starts compiling (instead of failing like it's supposed to) because the typer
// expects to be able to identify escaping locals in typedDefDef, and fails to
// spot that brand of them. In other words it's an artifact of the implementation.
val tpt = derivedSym.tpe_*.finalResultType.widen match {
// Range position errors ensue if we don't duplicate this in some
// circumstances (at least: concrete vals with existential types.)
case ExistentialType(_, _) => TypeTree() setOriginal (tree.tpt.duplicate setPos tree.tpt.pos.focus)
case _ if mods.isDeferred => TypeTree() setOriginal tree.tpt // keep type tree of original abstract field
case tp => TypeTree(tp)
}
tpt setPos tree.tpt.pos.focus
}
override def derivedTree: DefDef = newDefDef(derivedSym, derivedRhs)(tpt = derivedTpt)
} |
@adriaanm said: val underlying1 = underlying.instantiateTypeParams(quantified, tvars) // fuse subst quantified -> quantifiedFresh -> tvars does not go into symbol infos, thus the C in X's bound is not replaced by a type var |
@paulp said: |
@adriaanm said: scala> type T = X forSome { type X <: U ; type U <: String }
scala> typeOf[T].dealias.skolemizeExistential.typeSymbol.info
res7: $r.intp.global.Type = <: String If you disable that bound rewriting (as I'm doing), this will yield false: scala> :power
scala> class C { type T = X.T forSome { val X : U ; type U <: {type T} } }
scala> typeOf[C].member("T": TypeName)
scala> res0.info.skolemizeExistential <:< res0.info |
@adriaanm said: |
@adriaanm said: the remainder of my saga turned out to be #2071, which I hope to fix in 2.12 (https://github.com/adriaanm/scala/compare/t2071 |
@adriaanm said: |
@adriaanm said: |
Here is the smallest case I could generate:
I was originally playing around in the interpreter trying to understand the Currency examples in Ordersky Ch.20 and ran into this by doing the following. Note how it accepts the definition once and then break when I attempt to redefine it in exactly the same way. I'm still trying to wrap my head around path dependent types - so I don't have much more useful debugging info.
The text was updated successfully, but these errors were encountered: