-
Notifications
You must be signed in to change notification settings - Fork 122
Include used types in the set of used names #87
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
Conversation
The only way I can think of fixing this would be to change class A
class B[T] extends A
class X
class C extends B[Int] with X object Test {
val x: C = new C
} then when you process the type @gkossakowski : What do you think? |
I've just pushed a commit that attempts to fix this by adding type names to the set of used names, let's see how many tests that break. |
36cbb31
to
cdbbb9e
Compare
cdbbb9e
to
8acfe3c
Compare
Looks like it works! I'll try to add more tricky test cases tomorrow. Note that when rebasing this on top of #86, I also need to add class dependencies on used types, this might severely affect the benefits of #86, I'll have to run some tests, see https://github.com/smarter/zinc/commits/class-dependencies |
This is necessary to get sbt#87 to work on top of sbt#86 Compared to sbt#86, this branch: - Does not seem to impact the performance gains in incremental compilation - Makes scala/scala non-incremental compilation 15% slower, but sbt#86 is 60% slower than 0.13.11 (see sbt/sbt#1104 (comment)), so that needs to be fixed first before we analysis this. TODO: - More tests similar to inv-subtyping - Abstract types - Singleton types - Tests to verify if we need to use `symbolsInType` or if `typeSymbol` enough. - ...
Hi @smarter! Thanks for the test case and a PR. It's a good find. I've stumbled across similar problem before but I thought the problem was limited to structural types: sbt/sbt#1545. Regarding the fix, what you pushed looks different than what you described in #87 (comment) right? |
Is the problem is that we don't capture all of used names? |
Oh, I see you answered my question in the commit message. I think your observation about us not extracting all necessary used names is spot on. Your example from the test after typechecking becomes // AB.scala
class A0
class A1 extends A0
object B {
val x: A1 = { (new A).();A::<init>() }
}
// Test.scala
object Test {
val a: A0 = B.;A1::x
} I used the |
Yes, that seems like a good way to think about it, my patch probably misses some of these names like formal parameter types which may be important. |
Would you like to refine your patch to cover the missing cases? I think you Also, it would be good to add more cases to tests. On 22 March 2016 at 14:19, Guillaume Martres [email protected]
Grzegorz Kossakowski |
Yes, I'll try to do that this evening or tomorrow. |
c03bb84
to
a07de41
Compare
dd4866b
to
a1ecf51
Compare
Code fixed, tests added! |
I can rebase this on top of #86 if you prefer, assuming it will be merged soon |
This is a backport of sbt/zinc#87 When `B2.scala` replaces `B.scala` in the new test `source-dependencies/types-in-used-names`, the name hash of `listb` does not change because the signature of `C.listb` is still `List[B]`, however users of `C.listb` have to be recompiled since the subtyping relationships of its type have changed. This commit does this by extending the definition of "used names" to also include the names of the types of trees, even if these types do not appear in the source like `List[B]` in `D.scala` (since `B` has been invalidated, this will force the recompilation of `D.scala`).
0.13 backport: sbt/sbt#2523 |
If you compile your example with |
I see:
With Scala version 2.11.8. Do you use the same Scala version? |
Yes, and I don't see any |
That's the |
I tried outside of sbt and without
|
Weird, here's what I'm doing: % scalac -version
Scala compiler version 2.11.8 -- Copyright 2002-2016, LAMP/EPFL
% cat sbt87.scala
class X
class A {
type T
class Foo { def t(x: T): T = x }
val f: Foo = ???
}
class B extends A { type T = X }
class C extends B
object Test {
val c = new C
val x = new X
val x2 = c.f.t(x)
}
% scalac -Xprint:typer -Xprint-types sbt87.scala
[[syntax trees at end of typer]] // sbt87.scala
package <empty>{<empty>.type} {
class X extends scala.AnyRef {
def <init>(): X = {
X.super{X.super.type}.<init>{()Object}(){Object};
(){Unit}
}{Unit}
};
class A extends scala.AnyRef {
def <init>(): A = {
A.super{A.super.type}.<init>{()Object}(){Object};
(){Unit}
}{Unit};
type T;
class Foo extends scala.AnyRef {
def <init>(): A.this.Foo = {
Foo.super{Foo.super.type}.<init>{()Object}(){Object};
(){Unit}
}{Unit};
def t(x: A.this.T): A.this.T = x{A.this.T}
};
private[this] val f: A.this.Foo = scala.this{scala.type}.Predef.???{Nothing};
<stable> <accessor> def f: A.this.Foo = A.this{A.this.type}.f{A.this.Foo}
};
class B extends A {
def <init>(): B = {
B.super{B.super.type}.<init>{()A}(){A};
(){Unit}
}{Unit};
type T = X
};
class C extends B {
def <init>(): C = {
C.super{C.super.type}.<init>{()B}(){B};
(){Unit}
}{Unit}
};
object Test extends scala.AnyRef {
def <init>(): Test.type = {
Test.super{Test.type}.<init>{()Object}(){Object};
(){Unit}
}{Unit};
private[this] val c: C = new C{C}{()C}(){C};
<stable> <accessor> def c: C = Test.this{Test.type}.c{C};
private[this] val x: X = new X{X}{()X}(){X};
<stable> <accessor> def x: X = Test.this{Test.type}.x{X};
private[this] val x2: Test.c.T = Test.this{Test.type}.c.f.t{(x: Test.c.T)Test.c.T}(Test.this{Test.type}.x{X}){Test.c.T};
<stable> <accessor> def x2: Test.c.T = Test.this{Test.type}.x2{Test.c.T}
}
} |
Ah, I was using the variant with a type parameter: class X
class A[T] {
class Foo { def t(x: T): T = x }
val f: Foo = ???
}
class B extends A[X]
class C extends B
object Test {
val c = new C
val x = new X
val x2 = c.f.t(x)
} Sorry for the confusion. However, that leads me to another question: how do you detect dependency on
|
Good catch, I thought that this would work in dotty since type parameters are encoded as type members but it behaves similarly, this might be something we can fix. Meanwhile, I think we can workaround this by also explicitly looking at the info of the symbols of methods. |
This is definitely something we should have a pending test for. |
Which symbol points at dependency on |
None, on the other hand we have |
Ah, I spoke too soon on the dotty case, I was fooled by the pretty-printer which dealiases type parameters, the type is actually Anyway in both dotty and scalac, prefixes have singleton types, and one of the underlying type of those is |
Do you propose to depend on all super classes of all classes mentioned anywhere in a type? |
Do we need to? If |
Aren't we referring to |
class C extends this#B with this#A[this#X] with java.lang.this#Object with scala.this#Any {
...
} So if anything changes in the |
Ok, good point on base classes. But what if we change object Bla {
type T = X
}
class B extends A[Bla.T] We'll refer to |
Could you make a complete example that illustrates the issue? If we just do: class X
class A[T] {
class Foo { def t(x: T): T = x }
val f: Foo = ???
}
object Bla {
type T = X
}
class B extends A[Bla.T]
class C extends B
object Test {
val c = new C
val x = new X
val x2 = c.f.t(x)
} Then we're fine because |
Ok, I'll think of a complete example. The worry I'm trying to express is that hash sums do not include all necessary information so with enough of indirection you can hide changes that should trigger a recompilation. |
This is a backport of sbt/zinc#87 When `B2.scala` replaces `B.scala` in the new test `types-in-used-names-a`, the name hash of `listb` does not change because the signature of `C.listb` is still `List[B]`, however users of `C.listb` have to be recompiled since the subtyping relationships of its type have changed. This commit does this by extending the definition of "used names" to also include the names of the types of trees, even if these types do not appear in the source like `List[B]` in `D.scala` (since `B` has been invalidated, this will force the recompilation of `D.scala`). This commit does not fix every issue with used types as illustrated by the pending test `types-in-used-names-b`, `B.scala` is not recompiled because it uses the type `T` whose hash has not changed, but `T` is bounded by `S` and `S` has changed, so it should be recompiled. This should be fixable by including the type bounds underlying a `TypeRef` in `symbolsInType`. The test `as-seen-from-a` that did not work before shows that we may not have to worry about tracking prefixes in `ExtractAPI` anymore, see the discussion in sbt/zinc#87 for more information.
This is a backport of sbt/zinc#87 When `B2.scala` replaces `B.scala` in the new test `types-in-used-names-a`, the name hash of `listb` does not change because the signature of `C.listb` is still `List[B]`, however users of `C.listb` have to be recompiled since the subtyping relationships of its type have changed. This commit does this by extending the definition of "used names" to also include the names of the types of trees, even if these types do not appear in the source like `List[B]` in `D.scala` (since `B` has been invalidated, this will force the recompilation of `D.scala`). This commit does not fix every issue with used types as illustrated by the pending test `types-in-used-names-b`, `B.scala` is not recompiled because it uses the type `T` whose hash has not changed, but `T` is bounded by `S` and `S` has changed, so it should be recompiled. This should be fixable by including the type bounds underlying a `TypeRef` in `symbolsInType`. The test `as-seen-from-a` that did not work before shows that we may not have to worry about tracking prefixes in `ExtractAPI` anymore, see the discussion in sbt/zinc#87 for more information.
This is a backport of sbt/zinc#87 When `B2.scala` replaces `B.scala` in the new test `types-in-used-names-a`, the name hash of `listb` does not change because the signature of `C.listb` is still `List[B]`, however users of `C.listb` have to be recompiled since the subtyping relationships of its type have changed. This commit does this by extending the definition of "used names" to also include the names of the types of trees, even if these types do not appear in the source like `List[B]` in `D.scala` (since `B` has been invalidated, this will force the recompilation of `D.scala`). This commit does not fix every issue with used types as illustrated by the pending test `types-in-used-names-b`, `B.scala` is not recompiled because it uses the type `T` whose hash has not changed, but `T` is bounded by `S` and `S` has changed, so it should be recompiled. This should be fixable by including the type bounds underlying a `TypeRef` in `symbolsInType`. The test `as-seen-from-a` that did not work before shows that we may not have to worry about tracking prefixes in `ExtractAPI` anymore, see the discussion in sbt/zinc#87 for more information.
This is a backport of sbt/zinc#87 When `B2.scala` replaces `B.scala` in the new test `types-in-used-names-a`, the name hash of `listb` does not change because the signature of `C.listb` is still `List[B]`, however users of `C.listb` have to be recompiled since the subtyping relationships of its type have changed. This commit does this by extending the definition of "used names" to also include the names of the types of trees, even if these types do not appear in the source like `List[B]` in `D.scala` (since `B` has been invalidated, this will force the recompilation of `D.scala`). This commit does not fix every issue with used types as illustrated by the pending test `types-in-used-names-b`, `B.scala` is not recompiled because it uses the type `T` whose hash has not changed, but `T` is bounded by `S` and `S` has changed, so it should be recompiled. This should be fixable by including the type bounds underlying a `TypeRef` in `symbolsInType`. The test `as-seen-from-a` that did not work before shows that we may not have to worry about tracking prefixes in `ExtractAPI` anymore, see the discussion in sbt/zinc#87 for more information.
This is a backport of sbt/zinc#87 When `B2.scala` replaces `B.scala` in the new test `types-in-used-names-a`, the name hash of `listb` does not change because the signature of `C.listb` is still `List[B]`, however users of `C.listb` have to be recompiled since the subtyping relationships of its type have changed. This commit does this by extending the definition of "used names" to also include the names of the types of trees, even if these types do not appear in the source like `List[B]` in `D.scala` (since `B` has been invalidated, this will force the recompilation of `D.scala`). This commit does not fix every issue with used types as illustrated by the pending test `types-in-used-names-b`, `B.scala` is not recompiled because it uses the type `T` whose hash has not changed, but `T` is bounded by `S` and `S` has changed, so it should be recompiled. This should be fixable by including the type bounds underlying a `TypeRef` in `symbolsInType`. The test `as-seen-from-a` that did not work before shows that we may not have to worry about tracking prefixes in `ExtractAPI` anymore, see the discussion in sbt/zinc#87 for more information.
This is a backport of sbt/zinc#87 When `B2.scala` replaces `B.scala` in the new test `types-in-used-names-a`, the name hash of `listb` does not change because the signature of `C.listb` is still `List[B]`, however users of `C.listb` have to be recompiled since the subtyping relationships of its type have changed. This commit does this by extending the definition of "used names" to also include the names of the types of trees, even if these types do not appear in the source like `List[B]` in `D.scala` (since `B` has been invalidated, this will force the recompilation of `D.scala`). This commit does not fix every issue with used types as illustrated by the pending test `types-in-used-names-b`, `B.scala` is not recompiled because it uses the type `T` whose hash has not changed, but `T` is bounded by `S` and `S` has changed, so it should be recompiled. This should be fixable by including the type bounds underlying a `TypeRef` in `symbolsInType`. The test `as-seen-from-a` that did not work before shows that we may not have to worry about tracking prefixes in `ExtractAPI` anymore, see the discussion in sbt/zinc#87 for more information.
This is a backport of sbt/zinc#87 When `B2.scala` replaces `B.scala` in the new test `types-in-used-names-a`, the name hash of `listb` does not change because the signature of `C.listb` is still `List[B]`, however users of `C.listb` have to be recompiled since the subtyping relationships of its type have changed. This commit does this by extending the definition of "used names" to also include the names of the types of trees, even if these types do not appear in the source like `List[B]` in `D.scala` (since `B` has been invalidated, this will force the recompilation of `D.scala`). This commit does not fix every issue with used types as illustrated by the pending test `types-in-used-names-b`, `B.scala` is not recompiled because it uses the type `T` whose hash has not changed, but `T` is bounded by `S` and `S` has changed, so it should be recompiled. This should be fixable by including the type bounds underlying a `TypeRef` in `symbolsInType`. The test `as-seen-from-a` that did not work before shows that we may not have to worry about tracking prefixes in `ExtractAPI` anymore, see the discussion in sbt/zinc#87 for more information.
This is a backport of sbt/zinc#87 When `B2.scala` replaces `B.scala` in the new test `types-in-used-names-a`, the name hash of `listb` does not change because the signature of `C.listb` is still `List[B]`, however users of `C.listb` have to be recompiled since the subtyping relationships of its type have changed. This commit does this by extending the definition of "used names" to also include the names of the types of trees, even if these types do not appear in the source like `List[B]` in `D.scala` (since `B` has been invalidated, this will force the recompilation of `D.scala`). This commit does not fix every issue with used types as illustrated by the pending test `types-in-used-names-b`, `B.scala` is not recompiled because it uses the type `T` whose hash has not changed, but `T` is bounded by `S` and `S` has changed, so it should be recompiled. This should be fixable by including the type bounds underlying a `TypeRef` in `symbolsInType`. The test `as-seen-from-a` that did not work before shows that we may not have to worry about tracking prefixes in `ExtractAPI` anymore, see the discussion in sbt/zinc#87 for more information.
This is a backport of sbt/zinc#87 When `B2.scala` replaces `B.scala` in the new test `types-in-used-names-a`, the name hash of `listb` does not change because the signature of `C.listb` is still `List[B]`, however users of `C.listb` have to be recompiled since the subtyping relationships of its type have changed. This commit does this by extending the definition of "used names" to also include the names of the types of trees, even if these types do not appear in the source like `List[B]` in `D.scala` (since `B` has been invalidated, this will force the recompilation of `D.scala`). This commit does not fix every issue with used types as illustrated by the pending test `types-in-used-names-b`, `B.scala` is not recompiled because it uses the type `T` whose hash has not changed, but `T` is bounded by `S` and `S` has changed, so it should be recompiled. This should be fixable by including the type bounds underlying a `TypeRef` in `symbolsInType`. The test `as-seen-from-a` that did not work before shows that we may not have to worry about tracking prefixes in `ExtractAPI` anymore, see the discussion in sbt/zinc#87 for more information.
This test demonstrate that name hashing as implemented in sbt is
incorrect: When
AB2.scala
replacesAB.scala
the hash ofx
does notchange, it only contains the syntactic signature of
B.x
which isthis#A1
, the supertypes of the type ofB.x
are not recorded.Therefore,
Test
is not recompiled and compilation succeeds when itshouldn't.