Skip to content

Nightly Dotty workflow of 2021-11-04 failed #13878

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

Closed
github-actions bot opened this issue Nov 4, 2021 · 14 comments · Fixed by #13911
Closed

Nightly Dotty workflow of 2021-11-04 failed #13878

github-actions bot opened this issue Nov 4, 2021 · 14 comments · Fixed by #13911

Comments

@github-actions
Copy link
Contributor

github-actions bot commented Nov 4, 2021

See https://github.com/lampepfl/dotty/actions/runs/1419651199

@nicolasstucki
Copy link
Contributor

We are getting a new waring from #13792 wich changes the failure in tests/neg-custom-args/deprecation/t3235-minimal.scala.

@dwijnand could you check if this is the intended behavior?

@SethTisue
Copy link
Member

Dale and I are in the Twilight Zone on this. We are seeing some crazy, inexplicable shit that's making us doubt our own sanity. Stay tuned.

@SethTisue
Copy link
Member

SethTisue commented Nov 4, 2021

class C { def x: Long = 123456789L.round }

we've got the compiler giving different results on compiling this code depending on the filename you put it in. we've got the above code in two identical files:

% sum tests/neg-custom-args/deprecation/t3235-{minimal,widen}.scala
8684 1 tests/neg-custom-args/deprecation/t3235-minimal.scala
8684 1 tests/neg-custom-args/deprecation/t3235-widen.scala

but then compiling one of them gives the expected "Widening conversion from Long to Float" warning and the other doesn't.

% ./dist/target/pack/bin/scalac -deprecation tests/neg-custom-args/deprecation/t3235-minimal.scala       
-- Deprecation Warning: tests/neg-custom-args/deprecation/t3235-minimal.scala:1:35 
1 |class C { def x: Long = 123456789L.round }
  |                        ^^^^^^^^^^^^^^^^
  |method round in class RichLong is deprecated since 2.11.0: this is an integer type; there is no reason to round it.  Perhaps you meant to call this on a floating-point value?
1 warning found
% ./dist/target/pack/bin/scalac -deprecation tests/neg-custom-args/deprecation/t3235-widen.scala
-- [E167] Lossy Conversion Warning: tests/neg-custom-args/deprecation/t3235-widen.scala:1:24 
1 |class C { def x: Long = 123456789L.round }
  |                        ^^^^^^^^^^
  |                   Widening conversion from Long to Float loses precision.
  |                   Write `.toFloat` instead.
1 warning found

and this is reproducible on both Dale's machine and my machine

and it's deterministic. some filenames reproducibly give one result, other filenames reproducibly give the other.

@SethTisue
Copy link
Member

SethTisue commented Nov 4, 2021

some yak hair may need to hit the barbershop floor before we can even effectively troubleshoot this

@soronpo
Copy link
Contributor

soronpo commented Nov 5, 2021

I just hit a related problem in my own library. I had to change to explicit math.min and math.max, because the wrong function was invoked, causing an inlined recursion.

@SethTisue
Copy link
Member

@soronpo I guess I'm not in a position to judge yet whether that might be the same, but I hope you'll circle back and test it again after we merge a fix to this

@dwijnand
Copy link
Member

dwijnand commented Nov 5, 2021

So I have a small diff of changes that allow me to build bootstrapped jars and cause the reproduction, while being able to actually see all the log messages (including when typerState.fresh changes the reporter to be a store reporter!!), and the behaviour change seems to come from a different order of implicits leading to a different "best implicit" being selected:

 [log typer]         ==> try insert impl on qualifier 123456789L.round Long?
 [log typer]           ==> inferView(123456789L, ?{ round: ? })?
 [log typer]             ==> typedImplicit(Candidate(implicitRef=ImplicitRef/
-  (floatWrapper : (x: Float): scala.runtime.RichFloat)
+  (doubleWrapper : (x: Double): scala.runtime.RichDouble)

@Adam-Vandervorst
Copy link

Maybe a good time to suggest: (an option to enable) a warning when it's up to luck which implicit is selected.

@dwijnand
Copy link
Member

dwijnand commented Nov 6, 2021

OK, good news: this is only a warning and not actually impacting which implicit is selected. Of course, if you make all warnings fatal, then it still has a real impact (outside of the checkfile mismatch in our test suite). The problem is that the floatWrapper implicit, that is ultimately not selected, is still emitting the lossy warning. That's the actual fix needed here (and that I still need to look at to PR the fix).

In terms of "why does the file name change things?" well that's because file names are inserted in the names table:

    def getFile(name: String): AbstractFile = getFile(name.toTermName)

Different names will have different name table hash values, which will impact the hash values and therefore the index of later names, particularly the members of LowPriorityImplicits. This matters because SimpleName's hashCode is based on its index.

Hashcodes matters because of the use of Set, which brings me to this documentation:

    /** The set of names of members of this type that pass the given name filter
     *  when seen as members of `pre`. More precisely, these are all
     *  of members `name` such that `keepOnly(pre, name)` is `true`.
     *  @note: OK to use a Set[Name] here because Name hashcodes are replayable,
     *         hence the Set will always give the same names in the same order.
     */
    final def memberNames(keepOnly: NameFilter, pre: Type = this)(using Context): Set[Name] = this match {

I'm not sure what "replayable" means, so I can't tell whether the status quo is still following or not that requirement.

There's a few ways I've been able to avoid the difference in order with these two files. One is by changing the set used:

    def computeMemberNames(keepOnly: NameFilter)(implicit onBehalf: MemberNames, ctx: Context): Set[Name] = {
    //var names = scala.collection.immutable.ListSet[Name]()
      var names = Set[Name]()

Another is removing this code, which is forcing names to be inserted (and which is also dead code):

  val predefClassNames: Set[Name] =
    Set("Predef$", "DeprecatedPredef", "LowPriorityImplicits").map(_.toTypeName.unmangleClassName)

@dwijnand
Copy link
Member

dwijnand commented Nov 6, 2021

We can also add name ordering to the implicit sorting:

@@ -1319,12 +1321,15 @@ trait Implicits:
             0
         len(sym1) - len(sym2)

+      val candidateNameOrdering: Ordering[Candidate] = Ordering.by(c => c.implicitRef.implicitName: Name)
+
       /** A relation that influences the order in which eligible implicits are tried.
        *
        *  We prefer (in order of importance)
        *   1. more deeply nested definitions
        *   2. definitions with fewer implicit parameters
        *   3. definitions whose owner has more parents (see `compareBaseClassesLength`)
+       *   4. implicit name ordering
        *  The reason for (2) is that we want to fail fast if the search type
        *  is underconstrained. So we look for "small" goals first, because that
        *  will give an ambiguity quickly.
@@ -1340,7 +1345,8 @@ trait Implicits:
         val cmpArity = arity1 - arity2
         if cmpArity != 0 then return cmpArity // 2.
         val cmpBcs = compareBaseClassesLength(sym1.owner, sym2.owner)
-        -cmpBcs // 3.
+        if cmpBcs != 0 then return -cmpBcs // 3.
+        candidateNameOrdering.compare(e1, e2) // 4.

       /** Check if `ord` respects the contract of `Ordering`.
        *

That also nicely shows that even with the wrong order the problem is present: floatWrapper is tried earlier than longWrapper, emitting its lossy warning even though it's not used.

@dwijnand
Copy link
Member

dwijnand commented Nov 6, 2021

Still unanswered (and I don't intend to spend time on it): why does this only occur (in 3 nightlies now) on jdk 8 and not jdk 16?

@soronpo
Copy link
Contributor

soronpo commented Nov 6, 2021

OK, good news: this is only a warning and not actually impacting which implicit is selected.

I'm not completely sure this is true. In my case (and I believe this is related to my case) it affected which extension method was selected. This was a change in behavior. I can try and minimize to give a better example.

@dwijnand
Copy link
Member

dwijnand commented Nov 6, 2021

OK, I understand now why attempted implicits, such as floatWrapper, are leaking warnings despite the implicit being discarded in favour of longWrapper: because of suppressed warnings (aka configurable warnings). In general infos/diagnostics are stored in the reporter, which is on the typerState, where it can then be never unbuffered or force removeBufferedMessages. Configurable warnings stick the warnings on the Run, and eventually get reported even though that implicit wasn't picked... 😞

@lrytz free on Monday for some pairing? 😄

@soronpo
Copy link
Contributor

soronpo commented Nov 7, 2021

@dwijnand here is a minimized code:
https://scastie.scala-lang.org/5GNoOjh1SwSUuVMBTzRqFA

import compiletime.ops.int.Max
import scala.annotation.targetName
opaque type Inlined[T] = T
object Inlined:
  extension [T](inlined: Inlined[T]) def value: T = inlined
  inline given fromValue[T <: Singleton]: Conversion[T, Inlined[T]] =
    value => value
  @targetName("fromValueWide")
  given fromValue[Wide]: Conversion[Wide, Inlined[Wide]] = value => value

  def forced[T](value: Any): Inlined[T] = value.asInstanceOf[T]
  extension [T <: Int](lhs: Inlined[T])
    def max[R <: Int](rhs: Inlined[R]) =
      forced[Max[T, R]](lhs.value max rhs.value)
[error] 14 |      forced[Max[T, R]](lhs.value max rhs.value)
[error]    |                        ^^^^^^^^^^^^^
[error]    |value max is not a member of Inlined[
[error]    |  Inlined[
[error]    |    Inlined[
[error]    |      Inlined[
[error]    |        Inlined[
[error]    |          Inlined[
[error]    |            Inlined[
[error]    |              Inlined[
[error]    |                Inlined[
[error]    |                  Inlined[
[error]    |                    Inlined[
[error]    |                      Inlined[
[error]    |                        Inlined[
[error]    |                          Inlined[
[error]    |                            Inlined[
[error]    |                              Inlined[
[error]    |                                Inlined[
[error]    |                                  Inlined[
[error]    |                                    Inlined[Inlined[Inlined[Inlined[...[...]]]]]
[error]    |                                  ]
[error]    |                                ]
[error]    |                              ]
[error]    |                            ]
[error]    |                          ]
[error]    |                        ]
[error]    |                      ]
[error]    |                    ]
[error]    |                  ]
[error]    |                ]
[error]    |              ]
[error]    |            ]
[error]    |          ]
[error]    |        ]
[error]    |      ]
[error]    |    ]
[error]    |  ]
[error]    |].
[error]    |Extension methods were tried, but the search failed with:
[error]    |
[error]    |    Recursion limit exceeded.
[error]    |Maybe there is an illegal cyclic reference?
[error]    |If that's not the case, you could also try to increase the stacksize using the -Xss JVM option.
[error]    |A recurring operation is (inner to outer):
[error]    |
[error]    |  subtype Inlined[
[error]    |  Inlined[
[error]    |    Inlined[
[error]    |      Inlined[
[error]    |        Inlined[
[error]    |          Inlined[
[error]    |            Inlined[
[error]    |              Inlined[
[error]    |                Inlined[
[error]    |                  Inlined[
[error]    |                    Inlined[
[error]    |                      Inlined[
[error]    |                        Inlined[
[error]    |                          Inlined[
[error]    |                            Inlined[
[error]    |                              Inlined[
[error]    |                                Inlined[
[error]    |                                  Inlined[
[error]    |                                    Inlined[
[error]    |                                      Inlined[
[error]    |                                        Inlined[
[error]    |                                          Inlined[
[error]    |                                            Inlined[
[error]    |                                              Inlined[
[error]    |                                                Inlined[
[error]    |                                                  Inlined[
[error]    |                                                    Inlined[
[error]    |                                                      Inlined[
[error]    |                                                        Inlined[
[error]    |                                                          Inlined[
[error]    |                                                            Inlined[
[error]    |                                                              Inlined[
[error]    |                                                                Inlined[
[error]    |                                                                  Inlined[
[error]    |                                                                    Inlined[
[error]    |                                                                      Inlined[
[error]    |                                                                        Inlined[
[error]    |                                                                          Inlined
[error]    |                                                                            [
[error]    |                                                                          Inlined
[error]    |                                                                            [
[error]    |                                                                          Inlined
[error]    |                                                                            [
[error]    |                                                                          Inlined
[error]    |                                                                            [
[error]    |                                                                          Inlined
[error]    |                                                                            [
[error]    |                                                                          Inlined
[error]    |                                                                            [
[error]    |                                                                          Inlined
[error]    |                                                                            [
[error]    |                                                                          Inlined
[error]    |                                                                            [
[error]    |                                                                          Inlined
[error]    |                                                                            [
[error]    |                                                                          Inlined
[error]    |                                                                            [
[error]    |                                                                          Inlined
[error]    |                                                                            [
[error]    |                                                                          ...
[error]    |                                                                            Inlined
[error]    |                                                                          [
[error]    |                                                                            ...[
[error]    |                                                                              ...
[error]    |                                                                            ]
[error]    |                                                                          ]
[error]    |                                                                          ]
[error]    |                                                                          ]
[error]    |                                                                          ]
[error]    |                                                                          ]
[error]    |                                                                          ]
[error]    |                                                                          ]
[error]    |                                                                          ]
[error]    |                                                                          ]
[error]    |                                                                          ]
[error]    |                                                                          ]
[error]    |                                                                          ]
[error]    |                                                                        ]
[error]    |                                                                      ]
[error]    |                                                                    ]
[error]    |                                                                  ]
[error]    |                                                                ]
[error]    |                                                              ]
[error]    |                                                            ]
[error]    |                                                          ]
[error]    |                                                        ]
[error]    |                                                      ]
[error]    |                                                    ]
[error]    |                                                  ]
[error]    |                                                ]
[error]    |                                              ]
[error]    |                                            ]
[error]    |                                          ]
[error]    |                                        ]
[error]    |                                      ]
[error]    |                                    ]
[error]    |                                  ]
[error]    |                                ]
[error]    |                              ]
[error]    |                            ]
[error]    |                          ]
[error]    |                        ]
[error]    |                      ]
[error]    |                    ]
[error]    |                  ]
[error]    |                ]
[error]    |              ]
[error]    |            ]
[error]    |          ]
[error]    |        ]
[error]    |      ]
[error]    |    ]
[error]    |  ]
[error]    |] <:< Boolean
[error] one error found

The code works in 3.1.1-RC1, but fails on master.
The workaround was to change the last line to forced[Max[T, R]](math.max(lhs.value, rhs.value))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
5 participants