Skip to content

Implicit scope caching: bug fixes and performance improvements #1288

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

Merged
merged 8 commits into from
Jun 3, 2016

Conversation

smarter
Copy link
Member

@smarter smarter commented May 31, 2016

Review by @odersky

smarter added 7 commits May 31, 2016 16:53
The issue is subtle: the `tp` in scope in `def ofTypeImplicits` is the
`tp` passed to the top-level `implicitScope` method, not the `tp` passed
to the recursively called `iscope`, this means that before this commit,
all intermediate `OfTypeImplicit` scopes cached while computing an
implicit scope had their `tp` field incorrectly set, which means that we
could miss implicits in later implicit searches.

Note that the `implicit_cache.scala` test worked before this commit
because of the restrictions on caching that exist since
b8b0f38, it is included anyway because
our caching strategy might change in the future.
This did not work before because we incorrectly looked for their value
in the prefix of the type instead of the type itself.
According to SLS § 7.2, self types are not a named part of a type,
so they're not part of the implicit scope. Before this commit, this was
usually the case because we normally refer to a class using a TypeRef,
but in some cases a class might appear as a ThisType, and
ThisType#underlying returns the self type, we now use ThisType#tref
instead which just returns a TypeRef corresponding to the class.
Many intermediate `OfTypeImplicits` are created during a call to
`implicitScope`, but they won't all be used so there is no need to
compute `OfTypeImplicits#refs` unless it's actually used.
This reduces the number of implicit scopes we cache.
isApplicable(alt, targs, args, resultType)
)
else
alts2
Copy link
Contributor

Choose a reason for hiding this comment

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

That changes the logic of overloading resolution. With the change, we prefer methods that are applicable without implicit conversions to other methods. That's not as specced I think. What is the motivation for the change?

Copy link
Member Author

Choose a reason for hiding this comment

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

From the commit message of 7a060ba:

If a directly applicable alternative exists, there is no need to try
every alternative (which would require searching for implicit
conversions for every argument that doesn't directly match). This should
not affect semantics since applicable overloads that require some
implicit conversions are dismissed in narrowMostSpecific

The motivation for this change is that I observed that many of the implicit searches when compiling dotty were caused by overloading resolution (e.g., every call to Int#+ will check if the argument can be converted to Char,Short,Double, etc even if the argument is an Int) It's possible that I missed a case where this does change the semantics, if so could you give an example?

@odersky
Copy link
Contributor

odersky commented Jun 3, 2016

@smarter I was thinking something along these lines:

trait A; trait B
class C1 {
def f(x: A): Unit
}
class C2 extends C1 {
def f(x: B): Unit
}
object Test extends C2 {
implicit def a2b(x: A): B = ???
f(new A)
}

Under the old rules this is ambiguous. Under your new rules, C1#f would win. Which is reasonable, but not the way I remember the spec. On the other hand, scalac also picks C1#f, so maybe that's what we should do anyway. Do you have an idea of the savings in compile time this change gives us?

@odersky
Copy link
Contributor

odersky commented Jun 3, 2016

Everything else LGTM

@smarter
Copy link
Member Author

smarter commented Jun 3, 2016

Do you have an idea of the savings in compile time this change gives us?

Not really, it seemed to shave at least a second on dotty but the measurements are very noisy, I'm fine with either keeping or dropping this change, in either case we should have a look at what the spec says

@odersky
Copy link
Contributor

odersky commented Jun 3, 2016

The spec can be changed quite easily. And it's true that there are cases
where this could help a lot. So I think we should adopt the change.

On Fri, Jun 3, 2016 at 6:52 PM, Guillaume Martres notifications@github.com
wrote:

Do you have an idea of the savings in compile time this change gives us?

Not really, it seemed to shave at least a second on dotty but the
measurements are very noisy, I'm fine with either keeping or dropping this
change, in either case we should have a look at what the spec says


You are receiving this because you were assigned.
Reply to this email directly, view it on GitHub
#1288 (comment), or mute
the thread
https://github.com/notifications/unsubscribe/AAwlVpjKfGtC8YHq2QgV91oj0MugoPbjks5qIFu7gaJpZM4IqmNI
.

Prof. Martin Odersky
LAMP/IC, EPFL

@smarter
Copy link
Member Author

smarter commented Jun 3, 2016

OK, I'll add your example as a pos test to the commit that does the change and merge. Looking at the spec it seems we would just need to define what "directly applicable" means and use that in the overloading resolution secton

If directly applicable alternatives exists, do not try other
alternatives. The original motivation for this change was to reduce the
number of searches for implicit views we do since some overloaded
methods like `Int#+` are used a lot, but it turns out that this also
makes more code compile (see `overload_directly_applicable.scala` for an
example), this change does not seem to match what the specification
says (it does not define a notion of "directly applicable") but it does
match the behavior of scalac, and it seems useful in general.
@smarter smarter force-pushed the fix/implicit-caching-2 branch from 7a060ba to 295c981 Compare June 3, 2016 19:33
@smarter smarter merged commit 04b0e85 into scala:master Jun 3, 2016
@allanrenucci allanrenucci deleted the fix/implicit-caching-2 branch December 14, 2017 19:22
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.

2 participants