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

Avoid cycle with top-level export and trait #13719

Merged
merged 1 commit into from Oct 8, 2021

Conversation

smarter
Copy link
Member

@smarter smarter commented Oct 8, 2021

Previously, the following lead to a cycle (typing the extension method
requires typing its Int parameter, which forces completion of the
package object containing the top-level definition, which forces
completion of the extension method via the export clause):

trait MyExtensions:
  extension (lhs: Int) def bash: Unit = {}
object MyExtensions extends MyExtensions

export MyExtensions.*
val fails = 1.bash

But curiously enough, simply defining object MyExtensions before
trait MyExtensions was enough to work around the issue. This happened
because typing the module val of the object forces the package object,
this in turns forces the extension method but because of the way
class completers work, this doesn't lead to a cycle.

Based on this experiment, this commit simply always forces the package
object before typing any definition in the package, so we don't run into
a cycle no matter the order in which definitions appear.

Previously, the following lead to a cycle (typing the extension method
requires typing its `Int` parameter, which forces completion of the
package object containing the top-level definition, which forces
completion of the extension method via the export clause):

    trait MyExtensions:
      extension (lhs: Int) def bash: Unit = {}
    object MyExtensions extends MyExtensions

    export MyExtensions.*
    val fails = 1.bash

But curiously enough, simply defining `object MyExtensions` before
`trait MyExtensions` was enough to work around the issue. This happened
because typing the module val of the object forces the package object,
this in turns forces the extension method but because of the way
class completers work, this doesn't lead to a cycle.

Based on this experiment, this commit simply always forces the package
object before typing any definition in the package, so we don't run into
a cycle no matter the order in which definitions appear.
Copy link
Contributor

@odersky odersky left a comment

Choose a reason for hiding this comment

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

Nice!

@odersky odersky merged commit 97c772b into scala:master Oct 8, 2021
@odersky odersky deleted the toplevel-export-cycle branch October 8, 2021 15:33
@soronpo
Copy link
Contributor

soronpo commented Oct 8, 2021

This apparently also fixes #13120

@smarter
Copy link
Member Author

smarter commented Oct 8, 2021

Cool, would you mind submitting a PR adding it as a test case?

@soronpo
Copy link
Contributor

soronpo commented Oct 8, 2021

Already on it 😉

@Kordyjan Kordyjan added this to the 3.1.1 milestone Aug 2, 2023
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.

Cyclic reference of extension method when exported and used at toplevel
4 participants