From 9aa6ded8e01179e7d55144de273b39f3a0b2d3ec Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Thu, 22 Nov 2012 14:20:18 +0100 Subject: SI-6667 Abort after any ambiguous in-scope implicit Rather than continuing on to a search of implicits of the expected type. Previously, the companion implicits were searched if the the caller was running the implicit search in silent mode, for example if searching for an implicit parameter in an application which has an expected type. After this commit, the behaviour is consistent, regardless on silent/non-silent typing. --- .../scala/tools/nsc/typechecker/Implicits.scala | 3 ++- test/files/neg/t6667.check | 13 +++++++++++ test/files/neg/t6667.scala | 10 +++++++++ test/files/neg/t6667b.check | 13 +++++++++++ test/files/neg/t6667b.scala | 25 ++++++++++++++++++++++ 5 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 test/files/neg/t6667.check create mode 100644 test/files/neg/t6667.scala create mode 100644 test/files/neg/t6667b.check create mode 100644 test/files/neg/t6667b.scala diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index 8f32f0e653..a74470a9cd 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -1399,11 +1399,12 @@ trait Implicits { val failstart = if (Statistics.canEnable) Statistics.startTimer(oftypeFailNanos) else null val succstart = if (Statistics.canEnable) Statistics.startTimer(oftypeSucceedNanos) else null + val wasAmbigious = result.isAmbiguousFailure // SI-6667, never search companions after an ambiguous error in in-scope implicits 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.isFailure) result = searchImplicit(implicitsOfExpectedType, false) + if (result.isFailure && !wasAmbigious) result = searchImplicit(implicitsOfExpectedType, false) if (result.isFailure) { context.updateBuffer(previousErrs) diff --git a/test/files/neg/t6667.check b/test/files/neg/t6667.check new file mode 100644 index 0000000000..43313fa4fe --- /dev/null +++ b/test/files/neg/t6667.check @@ -0,0 +1,13 @@ +t6667.scala:8: error: ambiguous implicit values: + both value inScope1 in object Test of type => C + and value inScope2 in object Test of type => C + match expected type C + implicitly[C]: Unit // C.companion was used; whereas the ambiguity should abort the implicit search. + ^ +t6667.scala:9: error: ambiguous implicit values: + both value inScope1 in object Test of type => C + and value inScope2 in object Test of type => C + match expected type C + implicitly[C] // ambiguity reported, rather than falling back to C.companion + ^ +two errors found diff --git a/test/files/neg/t6667.scala b/test/files/neg/t6667.scala new file mode 100644 index 0000000000..fb857ebd33 --- /dev/null +++ b/test/files/neg/t6667.scala @@ -0,0 +1,10 @@ +class C +object C { + implicit def companion = new C +} + +object Test { + implicit val inScope1, inScope2 = new C + implicitly[C]: Unit // C.companion was used; whereas the ambiguity should abort the implicit search. + implicitly[C] // ambiguity reported, rather than falling back to C.companion +} diff --git a/test/files/neg/t6667b.check b/test/files/neg/t6667b.check new file mode 100644 index 0000000000..99cea9a47c --- /dev/null +++ b/test/files/neg/t6667b.check @@ -0,0 +1,13 @@ +t6667b.scala:16: error: ambiguous implicit values: + both value a in object Test of type => Test.Box + and value b of type Test.Box + match expected type Test.Box + new Test() + ^ +t6667b.scala:19: error: ambiguous implicit values: + both value a in object Test of type => Test.Box + and value b of type Test.Box + match expected type Test.Box + new Test() + ^ +two errors found diff --git a/test/files/neg/t6667b.scala b/test/files/neg/t6667b.scala new file mode 100644 index 0000000000..4e64e1af17 --- /dev/null +++ b/test/files/neg/t6667b.scala @@ -0,0 +1,25 @@ +object Test { + abstract class Box { + val value: Int + } + + implicit val a: Box = new Box { + val value= 1 + } + + def main(args: Array[String]) { + implicit val b: Box= new Box { + val value= 2 + } + + new Object { + new Test() + } + // compare with: + new Test() + } +} + +class Test()(implicit x: Test.Box) { + println(x.value) +} -- cgit v1.2.3