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

mysterious companion scope allows erroneous code to compile #6668

Closed
scabug opened this issue Nov 14, 2012 · 8 comments
Closed

mysterious companion scope allows erroneous code to compile #6668

scabug opened this issue Nov 14, 2012 · 8 comments
Labels

Comments

@scabug
Copy link

scabug commented Nov 14, 2012

Related to #6667, but not the same bug as far as I can see it. This is finding its idea of a non-ambiguous implicit A in the companion of A. The only problem with that is that A has no companion. Defining trait A outside of Test, or if Test is not an object, and it fails as expected.

package p1 {
  object Test {
    trait A

    def f(implicit x: A) = println(x)
    implicit val a: A = new A { }
    def g {
      implicit val b: A = new A { }
      f // COMPILES!
    }
  }
}

package p2 {
  trait A
  object Test {

    def f(implicit x: A) = println(x)
    implicit val a: A = new A { }
    def g {
      implicit val b: A = new A { }
      f // c.scala:22: error: ambiguous implicit values:
    }
  }
}

package p3 {
  class Test {
    trait A

    def f(implicit x: A) = println(x)
    implicit val a: A = new A { }
    def g {
      implicit val b: A = new A { }
      f // c.scala:35: error: ambiguous implicit values:
    }
  }
}

package p4 {
  trait A
  class Test {

    def f(implicit x: A) = println(x)
    implicit val a: A = new A { }
    def g {
      implicit val b: A = new A { }
      f // c.scala:48: error: ambiguous implicit values:
    }
  }
}
@scabug
Copy link
Author

scabug commented Nov 14, 2012

Imported From: https://issues.scala-lang.org/browse/SI-6668?orig=1
Reporter: @paulp

@scabug
Copy link
Author

scabug commented Nov 14, 2012

@retronym said (edited on Nov 14, 2012 9:31:16 PM UTC):
Members object p1.Test are, admittedly suprisingly, part of the implicit scope of A, as would be members of the package object p1. See #4427

@scabug
Copy link
Author

scabug commented Nov 14, 2012

@retronym said:
not-a-bugging for now.

@scabug scabug closed this as completed Nov 14, 2012
@scabug
Copy link
Author

scabug commented Nov 15, 2012

@paulp said:
The other half of this is: can you tell me, is everyone on board with this situation where the ambiguous implicits in scope cancel one another out and it succeeds when it finds the companion scope implicit? That just violates every intuition I have about "good idea." It's like setting two wrongs equal to one right.

@scabug
Copy link
Author

scabug commented Nov 15, 2012

@harrah said:
My understanding is that this is a bug according to the specification independently of whether Test is part of the implicit scope of A (although I agree with Jason that it is) :

Implicit resolution first considers identifiers accessible without a prefix. It only moves on to the implicit scope (the companion object) if there are no eligible identifiers. If there are several eligible, overloading resolution applies. It does not appear to suggest that if that resolution is ambiguous, it continues to the implicit scope.

Caveat: I didn't bother to grab the latest specification, so mine might be out of date. I'll update it tomorrow.

@scabug
Copy link
Author

scabug commented Nov 15, 2012

@retronym said:

The actual arguments that are eligible to be passed to an implicit parameter of type T fall into two categories. First, eligible are all identifiers x that can be accessed at the point of the method call without a prefix and that denote an implicit definition (§7.1) or an implicit parameter. An eligible identifier may thus be a local name, or a member of an enclosing template, or it may be have been made accessible without a prefix through an import clause (§4.7). If there are no eligible identifiers under this rule, then, second, eligible are also all implicit members of some object that belongs to the implicit scope of the implicit parameter’s type, T .

The spec seems very wrong: it tells me that the presence of any implicit in scope, e.g. any of those I get from import Predef._, should inhibit the companion scope search.

The implementation looks like:

def inferImplicit(tree: Tree, pt: Type, reportAmbiguous: Boolean, isView: Boolean, context: Context, saveAmbiguousDivergent: Boolean, pos: Position): SearchResult = {
...
var result = searchImplicit(context.implicitss, true)

if (result == SearchFailure) {
  val previousErrs = context.flushAndReturnBuffer()

  result = materializeImplicit(pt)

  // `materializeImplicit` does some preprocessing for `pt`
  // is it only meant for manifests/tags or we need to do the same for `implicitsOfExpectedType`?
  if (result == SearchFailure) result = searchImplicit(implicitsOfExpectedType, false)

  if (result == SearchFailure) {
    context.updateBuffer(previousErrs)
  }
}
}

I'm going to seek a clerical interpretation on this one from Martin. At a minimum, the definition of "eligible" must be updated to "and conforms to the T". Then, we have to clarify what should happen when there is ambiguity. I'll track this under #6667.

@scabug
Copy link
Author

scabug commented Nov 15, 2012

@harrah said:
I agree "eligible" implies "conforms to T" and the spec should say that explicitly.

As a side note, the spec I have is actually the latest from the website, but the date on it is May 2011, so I thought there would be a more recent one.

@scabug
Copy link
Author

scabug commented Nov 15, 2012

@paulp said:
"I thought there would be a more recent one."

https://groups.google.com/d/msg/scala-language/E60_yrs_6lY/gE-jBH8tK0oJ

@scabug scabug added the implicit label Apr 7, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant