Proposal: Changes to implicit resolution rules

I agree. If the existing mechanism continues to work (and take precedence over the parameter-count mechanism) then there’s no need to address it at the language level. It isn’t uncommon, but is rare enough (and should be encouraged to stay that way)

A note on compatibility, I have been testing the Dotty only factor10/intent library with the Scala 2 tasty reader, and the various given instance definitions they provide for Eq and Formatter type classes become ambiguous when reading from Scala 2, as can be demonstrated in a basic test suite:

import intent._

class ATest extends TestSuite with Stateless { self =>
  import self.{stringExt => test}, test._
  implicit val pos: intent.macros.Position        = ??? // comment line for illegal macro
  implicit val Eq: intent.core.Eq[Int]            = ??? // comment line for ambiguous implicit
  implicit val format: intent.core.Formatter[Int] = ??? // comment line for ambiguous implicit
  test("3 + 3") {                                       // illegal union type intent.core.MapLike
    in("should be 6") {
      toEqual(expect(3 + 3))(6)

The definitions can be found here for Eq

The ambiguity mentions tryEq, so I guess this comes under rule 7

Yes, the existing subclass-based mechanism takes precedence over the added disambiguations.

Quill’s materializeSchemaMeta is a case-in-point. This functionality (currently) uses macros activated by low-priority implicits which synthesize a entity derivation (which is eventually supposed to materialize into SQL). I have gladly ripped out the implicit-ordering code and replaced it with:

summonExpr(given '[SchemaMeta[T]]) match {
  case Some(meta) =>
    '{ $meta.unquote }

  case None => 
    '{ new EntityQuery[T]() }

This is a very intuitive and beautiful pattern compared to the implicit def trait-extension/override hackery of High/Low ordered implicits that was needed before.

1 Like

The problem I have with low priority implicits is that I want to put a default instance in the type class companion object that covers type T, which can be overridden in the companion object of type T. Using a low priority base trait with the type class companion object doesn’t help here, because it will still have the same priority as an instance declared in the type T companion final object.

The only trick left then as far as I can understand it is to take a Not[T] implicit evidence for the default instance.