Skip to content
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

Include ONLY nonpublic vars in API hash of traits #2441

Merged
merged 7 commits into from
Feb 10, 2016

Conversation

Duhemm
Copy link
Contributor

@Duhemm Duhemm commented Feb 4, 2016

The previous logic was wrong and included all members of traits in their
API hash, which degraded the performance of the incremental compiler.

This commit changes this logic so that only the non-public members of
traits are included into their API hash.

Fixes #2436

gkossakowski and others added 3 commits February 4, 2016 16:32
The test shows that name hashing optimization is broken for members
defined in traits. The problem is that modification of a member of a trait
triggers change of a hash of trait's name.

The behavior covered by this test regressed in
40ebc82
The bug is tracked in sbt#2436.
It's not clear what the distinction between compiler-project and
source-dependencies scripted tests is so let's stick to the one that has
the biggest number of tests for incremental compiler.
The previous logic was wrong and included all members of traits in their
API hash, which degraded the performance of the incremental compiler.

This commit changes this logic so that only the non-public members of
traits are included into their API hash.

Fixes sbt#2436
@typesafe-tools
Copy link

Can one of the admins verify this patch?

@eed3si9n
Copy link
Member

eed3si9n commented Feb 8, 2016

@gkossakowski Could you review this?

@gkossakowski
Copy link
Contributor

What happens in situation like this:

// A.scala
trait A {
  private type Foo = Int // (1) change Int to String
  private def foo: Int = 12 // (2) change Int to String and constant to a string constant
}
// B.scala
class B extends A

Will (1) or (2) trigger recompilation of B.scala? What should be the right behavior?

@eed3si9n
Copy link
Member

eed3si9n commented Feb 9, 2016

See also #2155 and c6b0043

@Duhemm
Copy link
Contributor Author

Duhemm commented Feb 9, 2016

@gkossakowski In both cases, A.scala and B.scala will be recompiled, which is not required. If we revert #2160 then B.scala is not recompiled. Should we only include private vars in traits?

@Duhemm Duhemm changed the title Include ONLY nonpublic members in API hash of traits Include ONLY nonpublic vars in API hash of traits Feb 9, 2016
@Duhemm
Copy link
Contributor Author

Duhemm commented Feb 9, 2016

@gkossakowski I've added a new commit that fixes the problems you exposed and behaves correctly on the following scenario:

// A.scala
trait A {
  private var a: Int = 0 // change to String, B gets recompiled and runs fine
}
// B.scala
object B extends A {
  def main(args: Array[String]): Unit = println("Hello")
}

@gkossakowski
Copy link
Contributor

I think you need to cover both private vars and vals. For the val, you have to generate a backing field. Try out changing a var to val.

@Duhemm
Copy link
Contributor Author

Duhemm commented Feb 9, 2016

You're right, it still crashes if we use vals.

@smarter
Copy link
Contributor

smarter commented Feb 9, 2016

It would be interesting to know how much of this is still valid in Scala 2.12 with the new trait encoding.

@gkossakowski
Copy link
Contributor

Let's cover vals by the existing test.

@Duhemm
Copy link
Contributor Author

Duhemm commented Feb 9, 2016

Let's cover vals by the existing test.

What do you mean?

@eed3si9n
Copy link
Member

eed3si9n commented Feb 9, 2016

@Duhemm I think he's asking you to test this in a scripted test by adding more changes to https://github.com/sbt/sbt/tree/0.13/sbt/src/sbt-test/source-dependencies/trait-private-var

Private vars and private vals defined in a trait impact the bytecode
generated for the implementors of these traits. The scripted test
`source-dependencies/trait-private-var` only accounted for private vars.

It now tries the same scenario both with private vars and private vals.
@Duhemm
Copy link
Contributor Author

Duhemm commented Feb 9, 2016

I updated the scripted test

@gkossakowski
Copy link
Contributor

Ok, so let's systematically go over the list of different private members we can have:

  • private var
  • private val
  • private lazy val
  • private type
  • private class
  • private trait
  • private object
  • private def

I checked the ones we discussed so far. What about the rest? Should the hash code of a trait include private hashes of any remaining members from the list?

@eed3si9n
Copy link
Member

eed3si9n commented Feb 9, 2016

source-dependencies / trait-super failed.

@Duhemm
Copy link
Contributor Author

Duhemm commented Feb 10, 2016

Private objects must be included as well in the API hash:

// A.scala
trait A {
  val foo = 0 // + X.a  Run once and then uncomment these two lines
//  private object X { val a = 1 }    
}
// B.scala
object B extends A {
  def main(args: Array[String]): Unit = {
    println("Hello " + foo)
  }
}
> run
[info] Updating {file:/Users/martin/Desktop/trait/}trait...
[info] Resolving jline#jline;2.12.1 ...
[info] Done updating.
[info] Compiling 2 Scala sources to /Users/martin/Desktop/trait/target/scala-2.11/classes...
[info] Running B 
Hello 0
[success] Total time: 1 s, completed Feb 10, 2016 12:02:39 PM
> run
[info] Compiling 1 Scala source to /Users/martin/Desktop/trait/target/scala-2.11/classes...
[info] Running B 
[error] (run-main-9) java.lang.AbstractMethodError: B$.A$$X()LA$X$;
java.lang.AbstractMethodError: B$.A$$X()LA$X$;
    at A$class.$init$(A.scala:2)
    at B$.<init>(B.scala:1)
    at B$.<clinit>(B.scala)
    at B.main(B.scala)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
[trace] Stack trace suppressed: run last compile:run for the full output.
java.lang.RuntimeException: Nonzero exit code: 1
    at scala.sys.package$.error(package.scala:27)
[trace] Stack trace suppressed: run last compile:run for the full output.
[error] (compile:run) Nonzero exit code: 1
[error] Total time: 1 s, completed Feb 10, 2016 12:02:44 PM

We get exactly the same result by replacing the private object by a private lazy val

@gkossakowski
Copy link
Contributor

Yes, objects are resembling closely lazy vals at their encoding. The type checking rules are different (objects introduce singleton types) but here we are mostly worried about what's going on at the byte code level.
I checked private objects for you, what do you think should happen to the rest? Also, it's good idea to try out closing something from the outer scope (e.g. constructor parameter) and see what happens. I suspect you don't need to include hashes of private defs defined in the source but you may need to include the hash of a synthetic member like $init$. Or, even better, just treat $init$ as non private.

@eed3si9n
Copy link
Member

Assuming this is a 0.13.10-RC show stopper, and we need to 0.13.10-RC3, how much more time do you guys need to settle this? Could we fix the most common cases for now, and accept some perf regression?

@dwijnand dwijnand added this to the 0.13.10 milestone Feb 10, 2016
@Duhemm
Copy link
Contributor Author

Duhemm commented Feb 10, 2016

@eed3si9n To fix source-dependencies/trait-super, we need to include some private defs, like B$$super$x in the case of this test. Maybe we should include all private methods whose name contains $?

@gkossakowski If I try with something coming from outside of the trait, then this something will be part of the API of the trait and once modified the clients of the trait will be recompiled. I guess I misunderstood what you meant?

I have been trying to add private inner traits and classes and looking at the resulting byte code in the implementing classes, but I do not see any mention of these classes in them.

What I have now is:

def isTraitBreaker(d: Definition): Boolean = {
  d match {
    case fl: FieldLike => true
    case cl: ClassLike => cl.definitionType == DefinitionType.Module
    case d: Def        => d.name contains "$"
    case _             => false
  }
}

@eed3si9n
Copy link
Member

Maybe we should include all private methods whose name contains $?

That feels hacky, but I don't have any good alternative.

@gkossakowski
Copy link
Contributor

That feels hacky, but I don't have any good alternative.

I think you want to check if a method symbol has the SUPERACCESSOR flag set and treat it as non-private in that case. Checking for dollars is fragile, e.g. dollars are used to encode names of identifiers that have spaces or unicode characters in them.

@eed3si9n
Copy link
Member

LGTM

@gkossakowski
Copy link
Contributor

LGTM

Good work!

@gkossakowski
Copy link
Contributor

And thanks for the recap.

@gkossakowski
Copy link
Contributor

Shall commits be squashed a little bit?

@eed3si9n
Copy link
Member

I'm not too fussy about the git history. I'll just merge this as is

eed3si9n added a commit that referenced this pull request Feb 10, 2016
Include ONLY nonpublic vars in API hash of traits
@eed3si9n eed3si9n merged commit d3962a0 into sbt:0.13.10 Feb 10, 2016
@Duhemm Duhemm deleted the wip/fix-2436 branch February 11, 2016 11:36
case _ => false
}
val includedPrivateDefinitions =
if (!includePrivate && !topLevel && isTrait) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Duhemm why is !topLevel here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gkossakowski Because if topLevel is true, then we have defs == ds.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I don't understand the original logic. Why do we care about whether definitions are enclosed by a top level class or not? Or is it about top level classes themselves?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding is that topLevel = true for definitions that are only enclosed in a package.

jvican added a commit to scalacenter/zinc that referenced this pull request May 10, 2018
This is still work in progress as more tests need to be added.  Note
that this is still WIP and the implementation may change in the next
days.

This pull request builds upon @Duhemm's work on
sbt/sbt#2441, but changes slightly the way it's
solved. It instead adds a specific api change that only invalidates
changes via inheritance (both global and local) and doesn't invalidate
member references, which gives us more correctness and precision.

As explained in sbt/sbt#2490, the previous fix
violated some of the invariants of the incremental algorithm. As such,
we introduce the notion of an extra api hash which is independent of the
normal one. This extra hash, in the case of traits, is computed from the
private definitions found, and otherwise it's the same as the normal
hash. As a result, we can tell apart the cases where there are changes
in the normal public API hash and the extra one. I've called it extra
instead of `trait private hash` or something similar because it can
accommodate other fixes in the future and we cannot afford adding a new
hash per `AnalyzedClass` every time we need to have `HashAPI` be special
cased for a particular encoding.

Fixes:

1. `source-dependencies/trait-private-val`
1. `source-dependencies/trait-private-var`
1. `source-dependencies/trait-super`
jvican added a commit to scalacenter/zinc that referenced this pull request May 11, 2018
This pull request builds upon @Duhemm's work on
sbt/sbt#2441, but changes slightly the way it's
solved. It instead adds a specific api change that only invalidates
changes via inheritance (both global and local) and doesn't invalidate
member references, which gives us more correctness and precision.

As explained in sbt/sbt#2490, the previous fix
violated some of the invariants of the incremental algorithm. As such,
we introduce the notion of an extra api hash which is independent of the
normal one. This extra hash, in the case of traits, is computed from the
private definitions found, and otherwise it's the same as the normal
hash. As a result, we can tell apart the cases where there are changes
in the normal public API hash and the extra one. I've called it extra
instead of `trait private hash` or something similar because it can
accommodate other fixes in the future and we cannot afford adding a new
hash per `AnalyzedClass` every time we need to have `HashAPI` be special
cased for a particular encoding.

Fixes:

1. `source-dependencies/trait-private-val`
1. `source-dependencies/trait-private-var`
1. `source-dependencies/trait-private-object`
1. `source-dependencies/trait-super`

And it also adds another two tests to complement
`source-dependencies/trait-member-modified` in checking that member
references to private trait definitions do not trigger unnecessary
compilations and that local inheritance does trigger an extra compile.

This is still *work in progress* as more tests need to be added. I'm
open to changing some details of the implementation since I'm not still
100% sure that the `apiExtraHash` route is the best choice. Maybe we
should go for something more explicit in name?
jvican added a commit to scalacenter/zinc that referenced this pull request May 12, 2018
This pull request builds upon @Duhemm's work on
sbt/sbt#2441, but changes slightly the way it's
solved. It instead adds a specific api change that only invalidates
changes via inheritance (both global and local) and doesn't invalidate
member references, which gives us more correctness and precision.

As explained in sbt/sbt#2490, the previous fix
violated some of the invariants of the incremental algorithm. As such,
we introduce the notion of an extra api hash which is independent of the
normal one. This extra hash, in the case of traits, is computed from the
private definitions found, and otherwise it's the same as the normal
hash. As a result, we can tell apart the cases where there are changes
in the normal public API hash and the extra one. I've called it extra
instead of `trait private hash` or something similar because it can
accommodate other fixes in the future and we cannot afford adding a new
hash per `AnalyzedClass` every time we need to have `HashAPI` be special
cased for a particular encoding.

Fixes:

1. `source-dependencies/trait-private-val`
1. `source-dependencies/trait-private-var`
1. `source-dependencies/trait-private-object`
1. `source-dependencies/trait-super`

And it also adds another two tests to complement
`source-dependencies/trait-member-modified` in checking that member
references to private trait definitions do not trigger unnecessary
compilations and that local inheritance does trigger an extra compile.

This is still *work in progress* as more tests need to be added. I'm
open to changing some details of the implementation since I'm not still
100% sure that the `apiExtraHash` route is the best choice. Maybe we
should go for something more explicit in name?
jvican added a commit to scalacenter/zinc that referenced this pull request Aug 10, 2018
This pull request builds upon @Duhemm's work on
sbt/sbt#2441, but changes slightly the way it's
solved. It instead adds a specific api change that only invalidates
changes via inheritance (both global and local) and doesn't invalidate
member references, which gives us more correctness and precision.

As explained in sbt/sbt#2490, the previous fix
violated some of the invariants of the incremental algorithm. As such,
we introduce the notion of an extra api hash which is independent of the
normal one. This extra hash, in the case of traits, is computed from the
private definitions found, and otherwise it's the same as the normal
hash. As a result, we can tell apart the cases where there are changes
in the normal public API hash and the extra one. I've called it extra
instead of `trait private hash` or something similar because it can
accommodate other fixes in the future and we cannot afford adding a new
hash per `AnalyzedClass` every time we need to have `HashAPI` be special
cased for a particular encoding.

Fixes:

1. `source-dependencies/trait-private-val`
1. `source-dependencies/trait-private-var`
1. `source-dependencies/trait-private-object`
1. `source-dependencies/trait-super`

And it also adds another two tests to complement
`source-dependencies/trait-member-modified` in checking that member
references to private trait definitions do not trigger unnecessary
compilations and that local inheritance does trigger an extra compile.

This is still *work in progress* as more tests need to be added. I'm
open to changing some details of the implementation since I'm not still
100% sure that the `apiExtraHash` route is the best choice. Maybe we
should go for something more explicit in name?
jvican added a commit to scalacenter/zinc that referenced this pull request Aug 10, 2018
This pull request builds upon @Duhemm's work on
sbt/sbt#2441, but changes slightly the way it's
solved. It instead adds a specific api change that only invalidates
changes via inheritance (both global and local) and doesn't invalidate
member references, which gives us more correctness and precision.

As explained in sbt/sbt#2490, the previous fix
violated some of the invariants of the incremental algorithm. As such,
we introduce the notion of an extra hash which is independent of the
normal one. This extra hash, in the case of traits, is computed from the
private definitions found, and otherwise its value is the empty hash (-1).

As a result, we can tell apart the cases where there are changes
in the normal public API hash and the extra one. I've called it extra
instead of `trait private hash` or something similar because it can
accommodate other fixes in the future and we cannot afford adding a new
hash per `AnalyzedClass` every time we need to have `HashAPI` be special
cased for a particular encoding. Right now, when the extra hash is
different and the classes involved in the hash computations are traits
we treat it as a breakage in the trait encoding and recompile
appropriately. If the classes involved are not hash computations, we
fail because no more cases have been added yet.

Fixes:

1. `source-dependencies/trait-private-val`
1. `source-dependencies/trait-private-var`
1. `source-dependencies/trait-private-object`
1. `source-dependencies/trait-super`

And it also adds another two tests to complement
`source-dependencies/trait-member-modified` in checking that member
references to private trait definitions do not trigger unnecessary
compilations and that local inheritance does trigger an extra compile.

Note that the code in `SameAPI` is rotten and will need to go at some
point in the future. It's outdated and the only one-liners used in the
incremental compiler should be inlined, and the rest of the code
ditched. Right now, it tries to emulate the semantics of `HashAPI` but
it hasn't been up-to-date ever since we released Zinc 1.0.

WIp tests

asdf
jvican added a commit to scalacenter/zinc that referenced this pull request Aug 10, 2018
This pull request builds upon @Duhemm's work on
sbt/sbt#2441, but changes slightly the way it's
solved. It instead adds a specific api change that only invalidates
changes via inheritance (both global and local) and doesn't invalidate
member references, which gives us more correctness and precision.

As explained in sbt/sbt#2490, the previous fix
violated some of the invariants of the incremental algorithm. As such,
we introduce the notion of an extra hash which is independent of the
normal one. This extra hash, in the case of traits, is computed from the
private definitions found, and otherwise its value is the empty hash (-1).

As a result, we can tell apart the cases where there are changes
in the normal public API hash and the extra one. I've called it extra
instead of `trait private hash` or something similar because it can
accommodate other fixes in the future and we cannot afford adding a new
hash per `AnalyzedClass` every time we need to have `HashAPI` be special
cased for a particular encoding. Right now, when the extra hash is
different and the classes involved in the hash computations are traits
we treat it as a breakage in the trait encoding and recompile
appropriately. If the classes involved are not hash computations, we
fail because no more cases have been added yet.

Fixes:

1. `source-dependencies/trait-private-val`
1. `source-dependencies/trait-private-var`
1. `source-dependencies/trait-private-object`
1. `source-dependencies/trait-super`

And it also adds another two tests to complement
`source-dependencies/trait-member-modified` in checking that member
references to private trait definitions do not trigger unnecessary
compilations and that local inheritance does trigger an extra compile.

Note that the code in `SameAPI` is rotten and will need to go at some
point in the future. It's outdated and the only one-liners used in the
incremental compiler should be inlined, and the rest of the code
ditched. Right now, it tries to emulate the semantics of `HashAPI` but
it hasn't been up-to-date ever since we released Zinc 1.0.

WIp tests

asdf
jvican added a commit to scalacenter/zinc that referenced this pull request Aug 10, 2018
This pull request builds upon @Duhemm's work on
sbt/sbt#2441, but changes slightly the way it's
solved. It instead adds a specific api change that only invalidates
changes via inheritance (both global and local) and doesn't invalidate
member references, which gives us more correctness and precision.

As explained in sbt/sbt#2490, the previous fix
violated some of the invariants of the incremental algorithm. As such,
we introduce the notion of an extra hash which is independent of the
normal one. This extra hash, in the case of traits, is computed from the
private definitions found, and otherwise its value is the empty hash (-1).

As a result, we can tell apart the cases where there are changes
in the normal public API hash and the extra one. I've called it extra
instead of `trait private hash` or something similar because it can
accommodate other fixes in the future and we cannot afford adding a new
hash per `AnalyzedClass` every time we need to have `HashAPI` be special
cased for a particular encoding. Right now, when the extra hash is
different and the classes involved in the hash computations are traits
we treat it as a breakage in the trait encoding and recompile
appropriately. If the classes involved are not hash computations, we
fail because no more cases have been added yet.

Fixes:

1. `source-dependencies/trait-private-val`
1. `source-dependencies/trait-private-var`
1. `source-dependencies/trait-private-object`
1. `source-dependencies/trait-super`

And it also adds another two tests to complement
`source-dependencies/trait-member-modified` in checking that member
references to private trait definitions do not trigger unnecessary
compilations and that local inheritance does trigger an extra compile.

Note that the code in `SameAPI` is rotten and will need to go at some
point in the future. It's outdated and the only one-liners used in the
incremental compiler should be inlined, and the rest of the code
ditched. Right now, it tries to emulate the semantics of `HashAPI` but
it hasn't been up-to-date ever since we released Zinc 1.0.

WIp tests

asdf
jvican added a commit to scalacenter/zinc that referenced this pull request Aug 10, 2018
This pull request builds upon @Duhemm's work on
sbt/sbt#2441, but changes slightly the way it's
solved. It instead adds a specific api change that only invalidates
changes via inheritance (both global and local) and doesn't invalidate
member references, which gives us more correctness and precision.

As explained in sbt/sbt#2490, the previous fix
violated some of the invariants of the incremental algorithm. As such,
we introduce the notion of an extra hash which is independent of the
normal one. This extra hash, in the case of traits, is computed from the
private definitions found, and otherwise its value defaults to the
public api hash (which represents the emptiness).

As a result, we can tell apart the cases where there are changes
in the normal public API hash and the extra one. I've called it extra
instead of `trait private hash` or something similar because it can
accommodate other fixes in the future and we cannot afford adding a new
hash per `AnalyzedClass` every time we need to have `HashAPI` be special
cased for a particular encoding. Right now, when the extra hash is
different and the classes involved in the hash computations are traits
we treat it as a breakage in the trait encoding and recompile
appropriately. If the classes involved are not hash computations, we
fail because no more cases have been added yet.

Fixes:

1. `source-dependencies/trait-private-val`
1. `source-dependencies/trait-private-var`
1. `source-dependencies/trait-private-object`
1. `source-dependencies/trait-super`

And it also adds another two tests to complement
`source-dependencies/trait-member-modified` in checking that member
references to private trait definitions do not trigger unnecessary
compilations and that local inheritance does trigger an extra compile.

Note that the code in `SameAPI` is rotten and will need to go at some
point in the future. It's outdated and the only one-liners used in the
incremental compiler should be inlined, and the rest of the code
ditched. Right now, it tries to emulate the semantics of `HashAPI` but
it hasn't been up-to-date ever since we released Zinc 1.0.
jvican added a commit to scalacenter/zinc that referenced this pull request Aug 10, 2018
This pull request builds upon @Duhemm's work on
sbt/sbt#2441, but changes slightly the way it's
solved. It instead adds a specific api change that only invalidates
changes via inheritance (both global and local) and doesn't invalidate
member references, which gives us more correctness and precision.

As explained in sbt/sbt#2490, the previous fix
violated some of the invariants of the incremental algorithm. As such,
we introduce the notion of an extra hash which is independent of the
normal one. This extra hash, in the case of traits, is computed from the
private definitions found, and otherwise its value defaults to the
public api hash (which represents the emptiness).

As a result, we can tell apart the cases where there are changes
in the normal public API hash and the extra one. I've called it extra
instead of `trait private hash` or something similar because it can
accommodate other fixes in the future and we cannot afford adding a new
hash per `AnalyzedClass` every time we need to have `HashAPI` be special
cased for a particular encoding. Right now, when the extra hash is
different and the classes involved in the hash computations are traits
we treat it as a breakage in the trait encoding and recompile
appropriately. If the classes involved are not hash computations, we
fail because no more cases have been added yet.

Fixes:

1. `source-dependencies/trait-private-val`
1. `source-dependencies/trait-private-var`
1. `source-dependencies/trait-private-object`
1. `source-dependencies/trait-super`

And it also adds another two tests to complement
`source-dependencies/trait-member-modified` in checking that member
references to private trait definitions do not trigger unnecessary
compilations and that local inheritance does trigger an extra compile.

Note that the code in `SameAPI` is rotten and will need to go at some
point in the future. It's outdated and the only one-liners used in the
incremental compiler should be inlined, and the rest of the code
ditched. Right now, it tries to emulate the semantics of `HashAPI` but
it hasn't been up-to-date ever since we released Zinc 1.0.
eed3si9n pushed a commit to eed3si9n/zinc that referenced this pull request Sep 20, 2018
This pull request builds upon @Duhemm's work on
sbt/sbt#2441, but changes slightly the way it's
solved. It instead adds a specific api change that only invalidates
changes via inheritance (both global and local) and doesn't invalidate
member references, which gives us more correctness and precision.

As explained in sbt/sbt#2490, the previous fix
violated some of the invariants of the incremental algorithm. As such,
we introduce the notion of an extra hash which is independent of the
normal one. This extra hash, in the case of traits, is computed from the
private definitions found, and otherwise its value defaults to the
public api hash (which represents the emptiness).

As a result, we can tell apart the cases where there are changes
in the normal public API hash and the extra one. I've called it extra
instead of `trait private hash` or something similar because it can
accommodate other fixes in the future and we cannot afford adding a new
hash per `AnalyzedClass` every time we need to have `HashAPI` be special
cased for a particular encoding. Right now, when the extra hash is
different and the classes involved in the hash computations are traits
we treat it as a breakage in the trait encoding and recompile
appropriately. If the classes involved are not hash computations, we
fail because no more cases have been added yet.

Fixes:

1. `source-dependencies/trait-private-val`
1. `source-dependencies/trait-private-var`
1. `source-dependencies/trait-private-object`
1. `source-dependencies/trait-super`

And it also adds another two tests to complement
`source-dependencies/trait-member-modified` in checking that member
references to private trait definitions do not trigger unnecessary
compilations and that local inheritance does trigger an extra compile.

Note that the code in `SameAPI` is rotten and will need to go at some
point in the future. It's outdated and the only one-liners used in the
incremental compiler should be inlined, and the rest of the code
ditched. Right now, it tries to emulate the semantics of `HashAPI` but
it hasn't been up-to-date ever since we released Zinc 1.0.
eed3si9n pushed a commit to scala/compiler-interface that referenced this pull request Apr 23, 2019
This pull request builds upon @Duhemm's work on
sbt/sbt#2441, but changes slightly the way it's
solved. It instead adds a specific api change that only invalidates
changes via inheritance (both global and local) and doesn't invalidate
member references, which gives us more correctness and precision.

As explained in sbt/sbt#2490, the previous fix
violated some of the invariants of the incremental algorithm. As such,
we introduce the notion of an extra hash which is independent of the
normal one. This extra hash, in the case of traits, is computed from the
private definitions found, and otherwise its value defaults to the
public api hash (which represents the emptiness).

As a result, we can tell apart the cases where there are changes
in the normal public API hash and the extra one. I've called it extra
instead of `trait private hash` or something similar because it can
accommodate other fixes in the future and we cannot afford adding a new
hash per `AnalyzedClass` every time we need to have `HashAPI` be special
cased for a particular encoding. Right now, when the extra hash is
different and the classes involved in the hash computations are traits
we treat it as a breakage in the trait encoding and recompile
appropriately. If the classes involved are not hash computations, we
fail because no more cases have been added yet.

Fixes:

1. `source-dependencies/trait-private-val`
1. `source-dependencies/trait-private-var`
1. `source-dependencies/trait-private-object`
1. `source-dependencies/trait-super`

And it also adds another two tests to complement
`source-dependencies/trait-member-modified` in checking that member
references to private trait definitions do not trigger unnecessary
compilations and that local inheritance does trigger an extra compile.

Note that the code in `SameAPI` is rotten and will need to go at some
point in the future. It's outdated and the only one-liners used in the
incremental compiler should be inlined, and the rest of the code
ditched. Right now, it tries to emulate the semantics of `HashAPI` but
it hasn't been up-to-date ever since we released Zinc 1.0.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants