diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index 6147cd78f3e6..d66c5d7ab4c2 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -218,6 +218,7 @@ private sealed trait XSettings: val Xtarget: Setting[String] = ChoiceSetting("-Xtarget", "target", "Emit bytecode for the specified version of the Java platform. This might produce bytecode that will break at runtime. When on JDK 9+, consider -release as a safer alternative.", ScalaSettings.supportedTargetVersions, "", aliases = List("--Xtarget")) val XcheckMacros: Setting[Boolean] = BooleanSetting("-Xcheck-macros", "Check some invariants of macro generated code while expanding macros", aliases = List("--Xcheck-macros")) val XmainClass: Setting[String] = StringSetting("-Xmain-class", "path", "Class for manifest's Main-Class entry (only useful with -d )", "") + val XimplicitSearchLimit: Setting[Int] = IntSetting("-Ximplicit-search-limit", "Maximal number of expressions to be generated in an implicit search", 50000) val XmixinForceForwarders = ChoiceSetting( name = "-Xmixin-force-forwarders", diff --git a/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala b/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala index 342e640ca819..f55196f82a8e 100644 --- a/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala +++ b/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala @@ -175,7 +175,8 @@ enum ErrorMessageID extends java.lang.Enum[ErrorMessageID]: OverrideErrorID, MatchableWarningID, CannotExtendFunctionID, - LossyWideningConstantConversionID + LossyWideningConstantConversionID, + ImplicitSearchTooLargeID def errorNumber = ordinal - 2 diff --git a/compiler/src/dotty/tools/dotc/reporting/Message.scala b/compiler/src/dotty/tools/dotc/reporting/Message.scala index 8ce94f4fa3a3..cd7456cafcc2 100644 --- a/compiler/src/dotty/tools/dotc/reporting/Message.scala +++ b/compiler/src/dotty/tools/dotc/reporting/Message.scala @@ -124,6 +124,13 @@ abstract class Message(val errorId: ErrorMessageID) { self => def explain = self.explain ++ suffix override def canExplain = true + /** Override with `true` for messages that should always be shown even if their + * position overlaps another messsage of a different class. On the other hand + * multiple messages of the same class with overlapping positions will lead + * to only a single message of that class to be issued. + */ + def showAlways = false + override def toString = msg } diff --git a/compiler/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala b/compiler/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala index fb4c92c12f83..e4312f46f779 100644 --- a/compiler/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala +++ b/compiler/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala @@ -10,19 +10,24 @@ import core.Contexts._ * are suppressed, unless they are of increasing severity. */ trait UniqueMessagePositions extends Reporter { - private val positions = new mutable.HashMap[(SourceFile, Int), Int] + private val positions = new mutable.HashMap[(SourceFile, Int), Diagnostic] /** Logs a position and returns true if it was already logged. * @note Two positions are considered identical for logging if they have the same point. */ override def isHidden(dia: Diagnostic)(using Context): Boolean = + extension (dia1: Diagnostic) def hides(dia2: Diagnostic): Boolean = + if dia2.msg.showAlways then dia1.msg.getClass == dia2.msg.getClass + else dia1.level >= dia2.level super.isHidden(dia) || { - dia.pos.exists && !ctx.settings.YshowSuppressedErrors.value && { + dia.pos.exists + && !ctx.settings.YshowSuppressedErrors.value + && { var shouldHide = false for (pos <- dia.pos.start to dia.pos.end) positions get (ctx.source, pos) match { - case Some(level) if level >= dia.level => shouldHide = true - case _ => positions((ctx.source, pos)) = dia.level + case Some(dia1) if dia1.hides(dia) => shouldHide = true + case _ => positions((ctx.source, pos)) = dia } shouldHide } diff --git a/compiler/src/dotty/tools/dotc/reporting/messages.scala b/compiler/src/dotty/tools/dotc/reporting/messages.scala index 62bf295fed8c..4a1efab782a1 100644 --- a/compiler/src/dotty/tools/dotc/reporting/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/messages.scala @@ -18,6 +18,7 @@ import ast.Trees import config.{Feature, ScalaVersion} import typer.ErrorReporting.{err, matchReductionAddendum} import typer.ProtoTypes.ViewProto +import typer.Implicits.Candidate import scala.util.control.NonFatal import StdNames.nme import printing.Formatting.hl @@ -2515,3 +2516,26 @@ import transform.SymUtils._ |Inlining such definition would multiply this footprint for each call site. |""".stripMargin } + + class ImplicitSearchTooLargeWarning(limit: Int, openSearchPairs: List[(Candidate, Type)])(using Context) + extends TypeMsg(ImplicitSearchTooLargeID): + override def showAlways = true + def showQuery(query: (Candidate, Type)): String = + i" ${query._1.ref.symbol.showLocated} for ${query._2}}" + def msg = + em"""Implicit search problem too large. + |an implicit search was terminated with failure after trying $limit expressions. + |The root candidate for the search was: + | + |${showQuery(openSearchPairs.last)} + | + |You can change the behavior by setting the `-Ximplicit-search-limit` value. + |Smaller values cause the search to fail faster. + |Larger values might make a very large search problem succeed. + |""" + def explain = + em"""The overflow happened with the following lists of tried expressions and target types, + |starting with the root query: + | + |${openSearchPairs.reverse.map(showQuery)}%\n% + """ diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 6c24dc6be119..a3b0dd02714d 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -489,6 +489,11 @@ object Implicits: @sharable val NoMatchingImplicitsFailure: SearchFailure = SearchFailure(NoMatchingImplicits, NoSpan)(using NoContext) + @sharable object ImplicitSearchTooLarge extends NoMatchingImplicits(NoType, EmptyTree, OrderingConstraint.empty) + + @sharable val ImplicitSearchTooLargeFailure: SearchFailure = + SearchFailure(ImplicitSearchTooLarge, NoSpan)(using NoContext) + /** An ambiguous implicits failure */ class AmbiguousImplicits(val alt1: SearchSuccess, val alt2: SearchSuccess, val expectedType: Type, val argument: Tree) extends SearchFailureType { def explanation(using Context): String = @@ -790,16 +795,8 @@ trait Implicits: */ def inferView(from: Tree, to: Type)(using Context): SearchResult = { record("inferView") - val wfromtp = from.tpe.widen - if to.isAny - || to.isAnyRef - || to.isRef(defn.UnitClass) - || wfromtp.isRef(defn.NothingClass) - || wfromtp.isRef(defn.NullClass) - || !ctx.mode.is(Mode.ImplicitsEnabled) - || from.isInstanceOf[Super] - || (wfromtp eq NoPrefix) - then NoMatchingImplicitsFailure + if !ctx.mode.is(Mode.ImplicitsEnabled) || from.isInstanceOf[Super] then + NoMatchingImplicitsFailure else { def adjust(to: Type) = to.stripTypeVar.widenExpr match { case SelectionProto(name, memberProto, compat, true) => @@ -1129,18 +1126,36 @@ trait Implicits: val isNotGiven: Boolean = wildProto.classSymbol == defn.NotGivenClass + private def searchTooLarge(): Boolean = ctx.searchHistory match + case root: SearchRoot => + root.nestedSearches = 1 + false + case h => + val limit = ctx.settings.XimplicitSearchLimit.value + val nestedSearches = h.root.nestedSearches + val result = nestedSearches > limit + if result then + var c = ctx + while c.outer.typer eq ctx.typer do c = c.outer + report.warning(ImplicitSearchTooLargeWarning(limit, h.openSearchPairs), ctx.source.atSpan(span))(using c) + else + h.root.nestedSearches = nestedSearches + 1 + result + /** Try to type-check implicit reference, after checking that this is not * a diverging search */ def tryImplicit(cand: Candidate, contextual: Boolean): SearchResult = if checkDivergence(cand) then SearchFailure(new DivergingImplicit(cand.ref, wideProto, argument), span) - else { + else if searchTooLarge() then + ImplicitSearchTooLargeFailure + else val history = ctx.searchHistory.nest(cand, pt) val typingCtx = nestedContext().setNewTyperState().setFreshGADTBounds.setSearchHistory(history) val result = typedImplicit(cand, pt, argument, span)(using typingCtx) - result match { + result match case res: SearchSuccess => ctx.searchHistory.defineBynameImplicit(wideProto, res) case _ => @@ -1152,8 +1167,6 @@ trait Implicits: // tests/neg/implicitSearch.check typingCtx.typerState.gc() result - } - } /** Search a list of eligible implicit references */ private def searchImplicit(eligible: List[Candidate], contextual: Boolean): SearchResult = @@ -1242,7 +1255,9 @@ trait Implicits: negateIfNot(tryImplicit(cand, contextual)) match { case fail: SearchFailure => - if (fail.isAmbiguous) + if fail eq ImplicitSearchTooLargeFailure then + fail + else if (fail.isAmbiguous) if migrateTo3 then val result = rank(remaining, found, NoMatchingImplicitsFailure :: rfailures) if (result.isSuccess) @@ -1411,27 +1426,43 @@ trait Implicits: rank(sort(eligible), NoMatchingImplicitsFailure, Nil) end searchImplicit + def isUnderSpecifiedArgument(tp: Type): Boolean = + tp.isRef(defn.NothingClass) || tp.isRef(defn.NullClass) || (tp eq NoPrefix) + + private def isUnderspecified(tp: Type): Boolean = tp.stripTypeVar match + case tp: WildcardType => + !tp.optBounds.exists || isUnderspecified(tp.optBounds.hiBound) + case tp: ViewProto => + isUnderspecified(tp.resType) + || tp.resType.isRef(defn.UnitClass) + || isUnderSpecifiedArgument(tp.argType.widen) + case _ => + tp.isAny || tp.isAnyRef + private def searchImplicit(contextual: Boolean): SearchResult = - val eligible = - if contextual then ctx.implicits.eligible(wildProto) - else implicitScope(wildProto).eligible - searchImplicit(eligible, contextual) match - case result: SearchSuccess => - result - case failure: SearchFailure => - failure.reason match - case _: AmbiguousImplicits => failure - case reason => - if contextual then - searchImplicit(contextual = false).recoverWith { - failure2 => failure2.reason match - case _: AmbiguousImplicits => failure2 - case _ => - reason match - case (_: DivergingImplicit) => failure - case _ => List(failure, failure2).maxBy(_.tree.treeSize) - } - else failure + if isUnderspecified(wildProto) then + NoMatchingImplicitsFailure + else + val eligible = + if contextual then ctx.implicits.eligible(wildProto) + else implicitScope(wildProto).eligible + searchImplicit(eligible, contextual) match + case result: SearchSuccess => + result + case failure: SearchFailure => + failure.reason match + case _: AmbiguousImplicits => failure + case reason => + if contextual then + searchImplicit(contextual = false).recoverWith { + failure2 => failure2.reason match + case _: AmbiguousImplicits => failure2 + case _ => + reason match + case (_: DivergingImplicit) => failure + case _ => List(failure, failure2).maxBy(_.tree.treeSize) + } + else failure end searchImplicit /** Find a unique best implicit reference */ @@ -1610,13 +1641,17 @@ case class OpenSearch(cand: Candidate, pt: Type, outer: SearchHistory)(using Con end OpenSearch /** - * The the state corresponding to the outermost context of an implicit searcch. + * The state corresponding to the outermost context of an implicit searcch. */ final class SearchRoot extends SearchHistory: val root = this val byname = false def openSearchPairs = Nil + /** How many expressions were constructed so far in the current toplevel implicit search? + */ + var nestedSearches: Int = 0 + /** The dictionary of recursive implicit types and corresponding terms for this search. */ var myImplicitDictionary: mutable.Map[Type, (TermRef, tpd.Tree)] = null private def implicitDictionary = diff --git a/compiler/test/dotty/tools/dotc/CompilationTests.scala b/compiler/test/dotty/tools/dotc/CompilationTests.scala index a9f376d3cda6..06526aa6a924 100644 --- a/compiler/test/dotty/tools/dotc/CompilationTests.scala +++ b/compiler/test/dotty/tools/dotc/CompilationTests.scala @@ -183,6 +183,7 @@ class CompilationTests { compileFile("tests/neg-custom-args/feature-shadowing.scala", defaultOptions.and("-Xfatal-warnings", "-feature")), compileDir("tests/neg-custom-args/hidden-type-errors", defaultOptions.and("-explain")), compileFile("tests/neg-custom-args/i13026.scala", defaultOptions.and("-print-lines")), + compileFile("tests/neg-custom-args/i13838.scala", defaultOptions.and("-Ximplicit-search-limit", "1000")), ).checkExpectedErrors() } diff --git a/tests/neg-custom-args/i13838.check b/tests/neg-custom-args/i13838.check new file mode 100644 index 000000000000..5730cb144e52 --- /dev/null +++ b/tests/neg-custom-args/i13838.check @@ -0,0 +1,26 @@ +-- Error: tests/neg-custom-args/i13838.scala:10:5 ---------------------------------------------------------------------- +10 | foo // error + | ^ + |no implicit argument of type Order[X] was found for parameter x$1 of method foo in object FooT + | + |where: X is a type variable + |. + |I found: + | + | FooT.OrderFFooA[F, A](FooT.OrderFFooA[F, A](/* missing */summon[Order[F[Foo[A]]]])) + | + |But given instance OrderFFooA in object FooT produces a diverging implicit search when trying to match type Order[F[Foo[A]]]. +-- [E168] Type Warning: tests/neg-custom-args/i13838.scala:10:5 -------------------------------------------------------- +10 | foo // error + | ^ + | Implicit search problem too large. + | an implicit search was terminated with failure after trying 1000 expressions. + | The root candidate for the search was: + | + | given instance OrderFFooA in object FooT for Order[Any]} + | + | You can change the behavior by setting the `-Ximplicit-search-limit` value. + | Smaller values cause the search to fail faster. + | Larger values might make a very large search problem succeed. + +longer explanation available when compiling with `-explain` diff --git a/tests/neg-custom-args/i13838.scala b/tests/neg-custom-args/i13838.scala new file mode 100644 index 000000000000..c99d3fa1f82d --- /dev/null +++ b/tests/neg-custom-args/i13838.scala @@ -0,0 +1,42 @@ +implicit def catsSyntaxEq[A: Eq](a: A): Foo[A] = ??? + +class Foo[A] +object Foo: + given [A: Eq]: Eq[Foo[A]] = ??? + +object FooT: + + def foo[X](using Order[X]): Unit = ??? + foo // error + + def map[F[_], A](ffa: F[Foo[A]])(f: A): Nothing = ??? + + given OrderFFooA[F[_], A](using Ord: Order[F[Foo[A]]]): Order[F[Foo[A]]] = ??? + +trait Eq[A] +trait Order[A] extends Eq[A] + +object Eq { + given catsKernelOrderForTuple1[A0](using A0: Order[A0]): Order[Tuple1[A0]] = ??? + given catsKernelOrderForTuple2[A0, A1](using A0: Order[A0], A1: Order[A1]): Order[(A0, A1)] = ??? + given catsKernelOrderForTuple3[A0, A1, A2](using A0: Order[A0], A1: Order[A1], A2: Order[A2]): Order[(A0, A1, A2)] = ??? + given catsKernelOrderForTuple4[A0, A1, A2, A3](using A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3]): Order[(A0, A1, A2, A3)] = ??? + given catsKernelOrderForTuple5[A0, A1, A2, A3, A4](using A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4]): Order[(A0, A1, A2, A3, A4)] = ??? + given catsKernelOrderForTuple6[A0, A1, A2, A3, A4, A5](using A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5]): Order[(A0, A1, A2, A3, A4, A5)] = ??? + given catsKernelOrderForTuple7[A0, A1, A2, A3, A4, A5, A6](using A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6]): Order[(A0, A1, A2, A3, A4, A5, A6)] = ??? + given catsKernelOrderForTuple8[A0, A1, A2, A3, A4, A5, A6, A7](using A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7]): Order[(A0, A1, A2, A3, A4, A5, A6, A7)] = ??? + given catsKernelOrderForTuple9[A0, A1, A2, A3, A4, A5, A6, A7, A8](using A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8)] = ??? + given catsKernelOrderForTuple10[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9](using A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9)] = ??? + given catsKernelOrderForTuple11[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10](using A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9], A10: Order[A10]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)] = ??? + given catsKernelOrderForTuple12[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11](using A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9], A10: Order[A10], A11: Order[A11]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11)] = ??? + given catsKernelOrderForTuple13[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12](using A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9], A10: Order[A10], A11: Order[A11], A12: Order[A12]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12)] = ??? + given catsKernelOrderForTuple14[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13](using A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9], A10: Order[A10], A11: Order[A11], A12: Order[A12], A13: Order[A13]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13)] = ??? + given catsKernelOrderForTuple15[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14](using A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9], A10: Order[A10], A11: Order[A11], A12: Order[A12], A13: Order[A13], A14: Order[A14]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14)] = ??? + given catsKernelOrderForTuple16[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15](using A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9], A10: Order[A10], A11: Order[A11], A12: Order[A12], A13: Order[A13], A14: Order[A14], A15: Order[A15]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15)] = ??? + given catsKernelOrderForTuple17[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16](using A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9], A10: Order[A10], A11: Order[A11], A12: Order[A12], A13: Order[A13], A14: Order[A14], A15: Order[A15], A16: Order[A16]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16)] = ??? + given catsKernelOrderForTuple18[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17](using A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9], A10: Order[A10], A11: Order[A11], A12: Order[A12], A13: Order[A13], A14: Order[A14], A15: Order[A15], A16: Order[A16], A17: Order[A17]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17)] = ??? + given catsKernelOrderForTuple19[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18](using A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9], A10: Order[A10], A11: Order[A11], A12: Order[A12], A13: Order[A13], A14: Order[A14], A15: Order[A15], A16: Order[A16], A17: Order[A17], A18: Order[A18]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18)] = ??? + given catsKernelOrderForTuple20[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19](using A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9], A10: Order[A10], A11: Order[A11], A12: Order[A12], A13: Order[A13], A14: Order[A14], A15: Order[A15], A16: Order[A16], A17: Order[A17], A18: Order[A18], A19: Order[A19]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19)] = ??? + given catsKernelOrderForTuple21[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20](using A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9], A10: Order[A10], A11: Order[A11], A12: Order[A12], A13: Order[A13], A14: Order[A14], A15: Order[A15], A16: Order[A16], A17: Order[A17], A18: Order[A18], A19: Order[A19], A20: Order[A20]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20)] = ??? + given catsKernelOrderForTuple22[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21](using A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9], A10: Order[A10], A11: Order[A11], A12: Order[A12], A13: Order[A13], A14: Order[A14], A15: Order[A15], A16: Order[A16], A17: Order[A17], A18: Order[A18], A19: Order[A19], A20: Order[A20], A21: Order[A21]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21)] = ??? +} diff --git a/tests/pos/i10082.scala b/tests/neg/i10082.scala similarity index 100% rename from tests/pos/i10082.scala rename to tests/neg/i10082.scala diff --git a/tests/neg/i13838a.scala b/tests/neg/i13838a.scala new file mode 100644 index 000000000000..9fcb7be7bdcf --- /dev/null +++ b/tests/neg/i13838a.scala @@ -0,0 +1,47 @@ +object TooSlow { + trait EqSyntax { + implicit def catsSyntaxEq[A: Eq](a: A): EqOps[A] = ??? + } + + final class EqOps[A] + + object eq extends EqSyntax + + import eq._ + + sealed abstract class Foo[A] + object Foo { + implicit def eqFoo[A: Eq]: Eq[Foo[A]] = ??? + } + + type FooT[F[_], A] = F[Foo[A]] + object FooT { + def liftF[F[_], A](fa: F[A]): F[Foo[A]] = + map(fa)(???) // error + + def map[F[_], A, B](ffa: F[Foo[A]])(f: A => B): F[Foo[B]] = + ??? + } + + trait Order[A] extends Eq[A] + + trait Eq[A] + + object Eq { + implicit def catsKernelOrderForTuple14[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13](implicit A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9], A10: Order[A10], A11: Order[A11], A12: Order[A12], A13: Order[A13]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13)] = ??? + implicit def catsKernelOrderForTuple13[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12](implicit A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9], A10: Order[A10], A11: Order[A11], A12: Order[A12]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12)] = ??? + implicit def catsKernelOrderForTuple12[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11](implicit A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9], A10: Order[A10], A11: Order[A11]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11)] = ??? + implicit def catsKernelOrderForTuple11[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10](implicit A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9], A10: Order[A10]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)] = ??? + implicit def catsKernelOrderForTuple10[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9](implicit A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9)] = ??? + implicit def catsKernelOrderForTuple9[A0, A1, A2, A3, A4, A5, A6, A7, A8](implicit A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8)] = ??? + implicit def catsKernelOrderForTuple8[A0, A1, A2, A3, A4, A5, A6, A7](implicit A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7]): Order[(A0, A1, A2, A3, A4, A5, A6, A7)] = ??? + implicit def catsKernelOrderForTuple7[A0, A1, A2, A3, A4, A5, A6](implicit A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6]): Order[(A0, A1, A2, A3, A4, A5, A6)] = ??? + implicit def catsKernelOrderForTuple6[A0, A1, A2, A3, A4, A5](implicit A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5]): Order[(A0, A1, A2, A3, A4, A5)] = ??? + implicit def catsKernelOrderForTuple5[A0, A1, A2, A3, A4](implicit A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4]): Order[(A0, A1, A2, A3, A4)] = ??? + implicit def catsKernelOrderForTuple4[A0, A1, A2, A3](implicit A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3]): Order[(A0, A1, A2, A3)] = ??? + implicit def catsKernelOrderForTuple3[A0, A1, A2](implicit A0: Order[A0], A1: Order[A1], A2: Order[A2]): Order[(A0, A1, A2)] = ??? + implicit def catsKernelOrderForTuple2[A0, A1](implicit A0: Order[A0], A1: Order[A1]): Order[(A0, A1)] = ??? + implicit def catsKernelOrderForTuple1[A0](implicit A0: Order[A0]): Order[Tuple1[A0]] = ??? + } + +} \ No newline at end of file diff --git a/tests/pos/i7745.scala b/tests/neg/i7745.scala similarity index 72% rename from tests/pos/i7745.scala rename to tests/neg/i7745.scala index de03d3995d33..7b54be159661 100644 --- a/tests/pos/i7745.scala +++ b/tests/neg/i7745.scala @@ -1,3 +1,3 @@ trait F[x] implicit def foo[f[_], y, x <: f[y]](implicit ev: F[y]): F[x] = ??? -val test = implicitly \ No newline at end of file +val test = implicitly // error \ No newline at end of file diff --git a/tests/neg/i9330.scala b/tests/neg/i9330.scala index 6ba57c033473..ca25582ef7e8 100644 --- a/tests/neg/i9330.scala +++ b/tests/neg/i9330.scala @@ -1,4 +1,4 @@ val x = { - () == "" + () == "" // error implicit def foo[A: A] // error // error // error }