Skip to content

Commit

Permalink
Record failures to adapt application arguments (#18269)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
dwijnand authored Aug 9, 2023
2 parents 512fbd5 + b35f85f commit d521be5
Show file tree
Hide file tree
Showing 17 changed files with 105 additions and 24 deletions.
4 changes: 3 additions & 1 deletion compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,8 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
if newSet.isEmpty then deps.remove(referenced)
else deps.updated(referenced, newSet)

def traverse(t: Type) = t match
def traverse(t: Type) = try
t match
case param: TypeParamRef =>
if hasBounds(param) then
if variance >= 0 then coDeps = update(coDeps, param)
Expand All @@ -356,6 +357,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
seen += tp
traverse(tp.ref)
case _ => traverseChildren(t)
catch case ex: Throwable => handleRecursive("adjust", t.show, ex)
end Adjuster

/** Adjust dependencies to account for the delta of previous entry `prevEntry`
Expand Down
7 changes: 7 additions & 0 deletions compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,13 @@ class PlainPrinter(_ctx: Context) extends Printer {
else if (pos.source.exists) s"${pos.source.file.name}:${pos.line + 1}"
else s"(no source file, offset = ${pos.span.point})"

def toText(cand: Candidate): Text =
"Cand("
~ toTextRef(cand.ref)
~ (if cand.isConversion then " conv" else "")
~ (if cand.isExtension then " ext" else "")
~ Str(" L" + cand.level) ~ ")"

def toText(result: SearchResult): Text = result match {
case result: SearchSuccess =>
"SearchSuccess: " ~ toText(result.ref) ~ " via " ~ toText(result.tree)
Expand Down
5 changes: 4 additions & 1 deletion compiler/src/dotty/tools/dotc/printing/Printer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import Texts._, ast.Trees._
import Types.{Type, SingletonType, LambdaParam, NamedType},
Symbols.Symbol, Scopes.Scope, Constants.Constant,
Names.Name, Denotations._, Annotations.Annotation, Contexts.Context
import typer.Implicits.SearchResult
import typer.Implicits.*
import util.SourcePosition
import typer.ImportInfo

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

/** Textual representation of implicit candidates. */
def toText(cand: Candidate): Text

/** Textual representation of implicit search result */
def toText(result: SearchResult): Text

Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/Applications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -844,7 +844,7 @@ trait Applications extends Compatibility {
var typedArgs = typedArgBuf.toList
def app0 = cpy.Apply(app)(normalizedFun, typedArgs) // needs to be a `def` because typedArgs can change later
val app1 =
if (!success) app0.withType(UnspecifiedErrorType)
if (!success || typedArgs.exists(_.tpe.isError)) app0.withType(UnspecifiedErrorType)
else {
if !sameSeq(args, orderedArgs)
&& !isJavaAnnotConstr(methRef.symbol)
Expand Down
6 changes: 4 additions & 2 deletions compiler/src/dotty/tools/dotc/typer/Implicits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,19 @@ object Implicits:
}

/** Both search candidates and successes are references with a specific nesting level. */
sealed trait RefAndLevel {
sealed trait RefAndLevel extends Showable {
def ref: TermRef
def level: Int
}

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

def isExtension = (kind & Candidate.Extension) != 0
def isConversion = (kind & Candidate.Conversion) != 0

def toText(printer: Printer): Text = printer.toText(this)
}
object Candidate {
type Kind = Int
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,15 +134,15 @@ class HoverTypeSuite extends BaseHoverSuite:
|class C
|object Foo:
| extension [T](using A)(s: T)(using B)
| def double[G](using C)(times: G) = (s.toString + s.toString) * times
| def double[G <: Int](using C)(times: G) = (s.toString + s.toString) * times
| end extension
| given A with {}
| given B with {}
| given C with {}
| "".<<doub@@le(1)>>
|end Foo
|""".stripMargin,
"extension [T](using A)(s: T) def double(using B)[G](using C)(times: G): String".hover
"extension [T](using A)(s: T) def double(using B)[G <: Int](using C)(times: G): String".hover
)

@Test def `extension-methods-complex-binary` =
Expand Down
14 changes: 13 additions & 1 deletion tests/neg-macros/i16522.check
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
-- [E007] Type Mismatch Error: tests/neg-macros/i16522.scala:10:45 -----------------------------------------------------
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
| ^^^^^^^
| Found: tl
| Required: HList
|
| longer explanation available when compiling with `-explain`
-- [E006] Not Found Error: tests/neg-macros/i16522.scala:10:62 ---------------------------------------------------------
10 | case '{HCons($h1: hd1, HCons($h2: hd2, $_ : tl))} => '{$h1.toString ++ $h2.toString} // error // error // error
| ^^
| Not found: h1
|
| longer explanation available when compiling with `-explain`
-- [E006] Not Found Error: tests/neg-macros/i16522.scala:10:78 ---------------------------------------------------------
10 | case '{HCons($h1: hd1, HCons($h2: hd2, $_ : tl))} => '{$h1.toString ++ $h2.toString} // error // error // error
| ^^
| Not found: h2
|
| longer explanation available when compiling with `-explain`
2 changes: 1 addition & 1 deletion tests/neg-macros/i16522.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
def showFirstTwoImpl(e: Expr[HList])(using Quotes): Expr[String] = {
e match {
case '{HCons($h1, HCons($h2, $_))} => '{$h1.toString ++ $h2.toString}
case '{HCons($h1: hd1, HCons($h2: hd2, $_ : tl))} => '{$h1.toString ++ $h2.toString} // error
case '{HCons($h1: hd1, HCons($h2: hd2, $_ : tl))} => '{$h1.toString ++ $h2.toString} // error // error // error
case '{HCons[hd, HCons[sd, tl]]($h1, HCons($h2, $_))} => '{$h1.toString ++ $h2.toString}
case _ => '{""}
}
Expand Down
2 changes: 1 addition & 1 deletion tests/neg-macros/i6762.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ import scala.quoted.*

type G[X]
case class Foo[T](x: T)
def f(word: String)(using Quotes): Expr[Foo[G[String]]] = '{Foo(${Expr(word)})} // error // error
def f(word: String)(using Quotes): Expr[Foo[G[String]]] = '{Foo(${Expr(word)})} // error
8 changes: 4 additions & 4 deletions tests/neg/enum-values.check
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
|
| failed with:
|
| Found: Array[example.Tag[?]]
| Required: Array[example.ListLike[?]]
| Found: example.ListLike.type
| Required: Nothing
-- [E008] Not Found Error: tests/neg/enum-values.scala:34:52 -----------------------------------------------------------
34 | val typeCtorsK: Array[TypeCtorsK[?]] = TypeCtorsK.values // error
| ^^^^^^^^^^^^^^^^^
Expand All @@ -38,8 +38,8 @@
|
| failed with:
|
| Found: Array[example.Tag[?]]
| Required: Array[example.TypeCtorsK[?[_$1]]]
| Found: example.TypeCtorsK.type
| Required: Nothing
-- [E008] Not Found Error: tests/neg/enum-values.scala:36:6 ------------------------------------------------------------
36 | Tag.valueOf("Int") // error
| ^^^^^^^^^^^
Expand Down
2 changes: 1 addition & 1 deletion tests/neg/enumsAccess.scala
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ object test5 {
enum E5[T](x: T) {
case C3() extends E5[INT](defaultX)// error: illegal reference // error: illegal reference
case C4 extends E5[INT](defaultX) // error: illegal reference // error: illegal reference
case C5 extends E5[E5[_]](E5.this) // error: type mismatch
case C5 extends E5[E5[_]](E5.this) // error: cannot be instantiated // error: conflicting base types // error: type mismatch
}

object E5 {
Expand Down
2 changes: 1 addition & 1 deletion tests/neg/i6779.check
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
| value f is not a member of T.
| An extension method was tried, but could not be fully constructed:
|
| Test.f[G[T]](x)(given_Stuff)
| Test.f[G[T]](x)
|
| failed with:
|
Expand Down
2 changes: 1 addition & 1 deletion tests/neg/recursive-lower-constraint.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ class Bar extends Foo[Bar]

class A {
def foo[T <: Foo[T], U >: Foo[T] <: T](x: T): T = x
foo(new Bar) // error
foo(new Bar) // error // error
}
6 changes: 0 additions & 6 deletions tests/neg/syntax-error-recovery.check
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,6 @@
| Not found: bam
|
| longer explanation available when compiling with `-explain`
-- [E006] Not Found Error: tests/neg/syntax-error-recovery.scala:61:10 -------------------------------------------------
61 | println(bam) // error
| ^^^
| Not found: bam
|
| longer explanation available when compiling with `-explain`
-- [E129] Potential Issue Warning: tests/neg/syntax-error-recovery.scala:7:2 -------------------------------------------
6 | 2
7 | }
Expand Down
2 changes: 1 addition & 1 deletion tests/neg/syntax-error-recovery.scala
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,5 @@ object Test2:
def foo5(x: Int) =
foo2(foo2(,) // error // error

println(bam) // error
println(bam)
// error
40 changes: 40 additions & 0 deletions tests/pos/i18163.orig.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import scala.language.implicitConversions

// We do have 2 `contramap` functions, one provided via `LoggerSyntax` other via `Contravariant.Ops`
// `ContravariantMonoidal` given instances are not used, and they do not match our type. Code fails when we have at least 2 instances of them
// Removal of `import catsSyntax._` allow to compile code
// Removal of `import odinSyntax.LoggerSyntax` and remaining `catsSyntax` would fail to compile the `def fails`

trait Foo[A]
trait Bar[A]

trait WriterT[F[_]: Contravariant, L, V]:
def contramap[Z](fn: Z => V): WriterT[F, L, Z] = ???
trait Logger[F[_]]
class WriterTLogger[F[_]] extends Logger[[G] =>> WriterT[F, List[String], G]]

trait ContravariantMonoidal[F[_]] extends Invariant[F] with Contravariant[F]
trait Invariant[F[_]]
object Invariant:
given ContravariantMonoidal[Foo] = ???
given ContravariantMonoidal[Bar] = ???

trait Contravariant[F[_]] extends Invariant[F]
object Contravariant:
trait Ops[F[_], A]:
def contramap[B](f: B => A): F[B] = ???

object catsSyntax:
implicit def toContravariantOps[F[_]: Contravariant, A](target: F[A]): Contravariant.Ops[F, A] = ???

object odinSyntax:
implicit class LoggerSyntax[F[_]](logger: Logger[F]):
def contramap(f: String => String): Logger[F] = ???

import catsSyntax._
import odinSyntax.LoggerSyntax

class Test:
def fails = new WriterTLogger[Option].contramap(identity)
def works = LoggerSyntax(new WriterTLogger[Option]).contramap(identity)

21 changes: 21 additions & 0 deletions tests/pos/i18163.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import scala.language.implicitConversions

trait Foo[A]
trait Bar[B]
trait Qux[C]
class Log[K[_]]

trait Inv[F[_]]
object Inv:
given monFoo: Inv[Foo] = ???
given monBar: Inv[Bar] = ???

trait InvOps[H[_], D] { def desc(s: String): H[D] = ??? }
trait LogOps[L[_]] { def desc(s: String): Log[L] = ??? }

class Test:
implicit def LogOps[Q[_]](l: Log[Q]): LogOps[Q] = ???
implicit def InvOps[J[_], E](j11: J[E])(implicit z: Inv[J]): InvOps[J, E] = ???

def fails = new Log[Qux].desc("fails")
def works = LogOps[Qux](new Log[Qux]).desc("works")

0 comments on commit d521be5

Please sign in to comment.