Skip to content

Commit d521be5

Browse files
authored
Record failures to adapt application arguments (#18269)
In tests/pos/i18163.scala, we don't want the ambiguous implicit of `Inv[J]` to cause the selection of `LogOps` to fail. The logic is there because it think the user's implicits "seem to be used to implement a local failure in order to negate an implicit search". But that's not the case here. The regular arguments aren't correct to start with (type kindness error), so we shouldn't even get to the implicit search and ambiguity.
2 parents 512fbd5 + b35f85f commit d521be5

17 files changed

+105
-24
lines changed

compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala

+3-1
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,8 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
344344
if newSet.isEmpty then deps.remove(referenced)
345345
else deps.updated(referenced, newSet)
346346

347-
def traverse(t: Type) = t match
347+
def traverse(t: Type) = try
348+
t match
348349
case param: TypeParamRef =>
349350
if hasBounds(param) then
350351
if variance >= 0 then coDeps = update(coDeps, param)
@@ -356,6 +357,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
356357
seen += tp
357358
traverse(tp.ref)
358359
case _ => traverseChildren(t)
360+
catch case ex: Throwable => handleRecursive("adjust", t.show, ex)
359361
end Adjuster
360362

361363
/** Adjust dependencies to account for the delta of previous entry `prevEntry`

compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala

+7
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,13 @@ class PlainPrinter(_ctx: Context) extends Printer {
641641
else if (pos.source.exists) s"${pos.source.file.name}:${pos.line + 1}"
642642
else s"(no source file, offset = ${pos.span.point})"
643643

644+
def toText(cand: Candidate): Text =
645+
"Cand("
646+
~ toTextRef(cand.ref)
647+
~ (if cand.isConversion then " conv" else "")
648+
~ (if cand.isExtension then " ext" else "")
649+
~ Str(" L" + cand.level) ~ ")"
650+
644651
def toText(result: SearchResult): Text = result match {
645652
case result: SearchSuccess =>
646653
"SearchSuccess: " ~ toText(result.ref) ~ " via " ~ toText(result.tree)

compiler/src/dotty/tools/dotc/printing/Printer.scala

+4-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import Texts._, ast.Trees._
77
import Types.{Type, SingletonType, LambdaParam, NamedType},
88
Symbols.Symbol, Scopes.Scope, Constants.Constant,
99
Names.Name, Denotations._, Annotations.Annotation, Contexts.Context
10-
import typer.Implicits.SearchResult
10+
import typer.Implicits.*
1111
import util.SourcePosition
1212
import typer.ImportInfo
1313

@@ -153,6 +153,9 @@ abstract class Printer {
153153
/** Textual representation of source position */
154154
def toText(pos: SourcePosition): Text
155155

156+
/** Textual representation of implicit candidates. */
157+
def toText(cand: Candidate): Text
158+
156159
/** Textual representation of implicit search result */
157160
def toText(result: SearchResult): Text
158161

compiler/src/dotty/tools/dotc/typer/Applications.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -844,7 +844,7 @@ trait Applications extends Compatibility {
844844
var typedArgs = typedArgBuf.toList
845845
def app0 = cpy.Apply(app)(normalizedFun, typedArgs) // needs to be a `def` because typedArgs can change later
846846
val app1 =
847-
if (!success) app0.withType(UnspecifiedErrorType)
847+
if (!success || typedArgs.exists(_.tpe.isError)) app0.withType(UnspecifiedErrorType)
848848
else {
849849
if !sameSeq(args, orderedArgs)
850850
&& !isJavaAnnotConstr(methRef.symbol)

compiler/src/dotty/tools/dotc/typer/Implicits.scala

+4-2
Original file line numberDiff line numberDiff line change
@@ -49,17 +49,19 @@ object Implicits:
4949
}
5050

5151
/** Both search candidates and successes are references with a specific nesting level. */
52-
sealed trait RefAndLevel {
52+
sealed trait RefAndLevel extends Showable {
5353
def ref: TermRef
5454
def level: Int
5555
}
5656

5757
/** An eligible implicit candidate, consisting of an implicit reference and a nesting level */
58-
case class Candidate(implicitRef: ImplicitRef, kind: Candidate.Kind, level: Int) extends RefAndLevel {
58+
case class Candidate(implicitRef: ImplicitRef, kind: Candidate.Kind, level: Int) extends RefAndLevel with Showable {
5959
def ref: TermRef = implicitRef.underlyingRef
6060

6161
def isExtension = (kind & Candidate.Extension) != 0
6262
def isConversion = (kind & Candidate.Conversion) != 0
63+
64+
def toText(printer: Printer): Text = printer.toText(this)
6365
}
6466
object Candidate {
6567
type Kind = Int

presentation-compiler/test/dotty/tools/pc/tests/hover/HoverTypeSuite.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -134,15 +134,15 @@ class HoverTypeSuite extends BaseHoverSuite:
134134
|class C
135135
|object Foo:
136136
| extension [T](using A)(s: T)(using B)
137-
| def double[G](using C)(times: G) = (s.toString + s.toString) * times
137+
| def double[G <: Int](using C)(times: G) = (s.toString + s.toString) * times
138138
| end extension
139139
| given A with {}
140140
| given B with {}
141141
| given C with {}
142142
| "".<<doub@@le(1)>>
143143
|end Foo
144144
|""".stripMargin,
145-
"extension [T](using A)(s: T) def double(using B)[G](using C)(times: G): String".hover
145+
"extension [T](using A)(s: T) def double(using B)[G <: Int](using C)(times: G): String".hover
146146
)
147147

148148
@Test def `extension-methods-complex-binary` =

tests/neg-macros/i16522.check

+13-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,19 @@
11
-- [E007] Type Mismatch Error: tests/neg-macros/i16522.scala:10:45 -----------------------------------------------------
2-
10 | case '{HCons($h1: hd1, HCons($h2: hd2, $_ : tl))} => '{$h1.toString ++ $h2.toString} // error
2+
10 | case '{HCons($h1: hd1, HCons($h2: hd2, $_ : tl))} => '{$h1.toString ++ $h2.toString} // error // error // error
33
| ^^^^^^^
44
| Found: tl
55
| Required: HList
66
|
77
| longer explanation available when compiling with `-explain`
8+
-- [E006] Not Found Error: tests/neg-macros/i16522.scala:10:62 ---------------------------------------------------------
9+
10 | case '{HCons($h1: hd1, HCons($h2: hd2, $_ : tl))} => '{$h1.toString ++ $h2.toString} // error // error // error
10+
| ^^
11+
| Not found: h1
12+
|
13+
| longer explanation available when compiling with `-explain`
14+
-- [E006] Not Found Error: tests/neg-macros/i16522.scala:10:78 ---------------------------------------------------------
15+
10 | case '{HCons($h1: hd1, HCons($h2: hd2, $_ : tl))} => '{$h1.toString ++ $h2.toString} // error // error // error
16+
| ^^
17+
| Not found: h2
18+
|
19+
| longer explanation available when compiling with `-explain`

tests/neg-macros/i16522.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
def showFirstTwoImpl(e: Expr[HList])(using Quotes): Expr[String] = {
88
e match {
99
case '{HCons($h1, HCons($h2, $_))} => '{$h1.toString ++ $h2.toString}
10-
case '{HCons($h1: hd1, HCons($h2: hd2, $_ : tl))} => '{$h1.toString ++ $h2.toString} // error
10+
case '{HCons($h1: hd1, HCons($h2: hd2, $_ : tl))} => '{$h1.toString ++ $h2.toString} // error // error // error
1111
case '{HCons[hd, HCons[sd, tl]]($h1, HCons($h2, $_))} => '{$h1.toString ++ $h2.toString}
1212
case _ => '{""}
1313
}

tests/neg-macros/i6762.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ import scala.quoted.*
22

33
type G[X]
44
case class Foo[T](x: T)
5-
def f(word: String)(using Quotes): Expr[Foo[G[String]]] = '{Foo(${Expr(word)})} // error // error
5+
def f(word: String)(using Quotes): Expr[Foo[G[String]]] = '{Foo(${Expr(word)})} // error

tests/neg/enum-values.check

+4-4
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
|
2525
| failed with:
2626
|
27-
| Found: Array[example.Tag[?]]
28-
| Required: Array[example.ListLike[?]]
27+
| Found: example.ListLike.type
28+
| Required: Nothing
2929
-- [E008] Not Found Error: tests/neg/enum-values.scala:34:52 -----------------------------------------------------------
3030
34 | val typeCtorsK: Array[TypeCtorsK[?]] = TypeCtorsK.values // error
3131
| ^^^^^^^^^^^^^^^^^
@@ -38,8 +38,8 @@
3838
|
3939
| failed with:
4040
|
41-
| Found: Array[example.Tag[?]]
42-
| Required: Array[example.TypeCtorsK[?[_$1]]]
41+
| Found: example.TypeCtorsK.type
42+
| Required: Nothing
4343
-- [E008] Not Found Error: tests/neg/enum-values.scala:36:6 ------------------------------------------------------------
4444
36 | Tag.valueOf("Int") // error
4545
| ^^^^^^^^^^^

tests/neg/enumsAccess.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ object test5 {
6363
enum E5[T](x: T) {
6464
case C3() extends E5[INT](defaultX)// error: illegal reference // error: illegal reference
6565
case C4 extends E5[INT](defaultX) // error: illegal reference // error: illegal reference
66-
case C5 extends E5[E5[_]](E5.this) // error: type mismatch
66+
case C5 extends E5[E5[_]](E5.this) // error: cannot be instantiated // error: conflicting base types // error: type mismatch
6767
}
6868

6969
object E5 {

tests/neg/i6779.check

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
| value f is not a member of T.
1212
| An extension method was tried, but could not be fully constructed:
1313
|
14-
| Test.f[G[T]](x)(given_Stuff)
14+
| Test.f[G[T]](x)
1515
|
1616
| failed with:
1717
|

tests/neg/recursive-lower-constraint.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@ class Bar extends Foo[Bar]
33

44
class A {
55
def foo[T <: Foo[T], U >: Foo[T] <: T](x: T): T = x
6-
foo(new Bar) // error
6+
foo(new Bar) // error // error
77
}

tests/neg/syntax-error-recovery.check

-6
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,6 @@
9494
| Not found: bam
9595
|
9696
| longer explanation available when compiling with `-explain`
97-
-- [E006] Not Found Error: tests/neg/syntax-error-recovery.scala:61:10 -------------------------------------------------
98-
61 | println(bam) // error
99-
| ^^^
100-
| Not found: bam
101-
|
102-
| longer explanation available when compiling with `-explain`
10397
-- [E129] Potential Issue Warning: tests/neg/syntax-error-recovery.scala:7:2 -------------------------------------------
10498
6 | 2
10599
7 | }

tests/neg/syntax-error-recovery.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,5 +58,5 @@ object Test2:
5858
def foo5(x: Int) =
5959
foo2(foo2(,) // error // error
6060

61-
println(bam) // error
61+
println(bam)
6262
// error

tests/pos/i18163.orig.scala

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import scala.language.implicitConversions
2+
3+
// We do have 2 `contramap` functions, one provided via `LoggerSyntax` other via `Contravariant.Ops`
4+
// `ContravariantMonoidal` given instances are not used, and they do not match our type. Code fails when we have at least 2 instances of them
5+
// Removal of `import catsSyntax._` allow to compile code
6+
// Removal of `import odinSyntax.LoggerSyntax` and remaining `catsSyntax` would fail to compile the `def fails`
7+
8+
trait Foo[A]
9+
trait Bar[A]
10+
11+
trait WriterT[F[_]: Contravariant, L, V]:
12+
def contramap[Z](fn: Z => V): WriterT[F, L, Z] = ???
13+
trait Logger[F[_]]
14+
class WriterTLogger[F[_]] extends Logger[[G] =>> WriterT[F, List[String], G]]
15+
16+
trait ContravariantMonoidal[F[_]] extends Invariant[F] with Contravariant[F]
17+
trait Invariant[F[_]]
18+
object Invariant:
19+
given ContravariantMonoidal[Foo] = ???
20+
given ContravariantMonoidal[Bar] = ???
21+
22+
trait Contravariant[F[_]] extends Invariant[F]
23+
object Contravariant:
24+
trait Ops[F[_], A]:
25+
def contramap[B](f: B => A): F[B] = ???
26+
27+
object catsSyntax:
28+
implicit def toContravariantOps[F[_]: Contravariant, A](target: F[A]): Contravariant.Ops[F, A] = ???
29+
30+
object odinSyntax:
31+
implicit class LoggerSyntax[F[_]](logger: Logger[F]):
32+
def contramap(f: String => String): Logger[F] = ???
33+
34+
import catsSyntax._
35+
import odinSyntax.LoggerSyntax
36+
37+
class Test:
38+
def fails = new WriterTLogger[Option].contramap(identity)
39+
def works = LoggerSyntax(new WriterTLogger[Option]).contramap(identity)
40+

tests/pos/i18163.scala

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import scala.language.implicitConversions
2+
3+
trait Foo[A]
4+
trait Bar[B]
5+
trait Qux[C]
6+
class Log[K[_]]
7+
8+
trait Inv[F[_]]
9+
object Inv:
10+
given monFoo: Inv[Foo] = ???
11+
given monBar: Inv[Bar] = ???
12+
13+
trait InvOps[H[_], D] { def desc(s: String): H[D] = ??? }
14+
trait LogOps[L[_]] { def desc(s: String): Log[L] = ??? }
15+
16+
class Test:
17+
implicit def LogOps[Q[_]](l: Log[Q]): LogOps[Q] = ???
18+
implicit def InvOps[J[_], E](j11: J[E])(implicit z: Inv[J]): InvOps[J, E] = ???
19+
20+
def fails = new Log[Qux].desc("fails")
21+
def works = LogOps[Qux](new Log[Qux]).desc("works")

0 commit comments

Comments
 (0)