Skip to content

Commit 0b4c2af

Browse files
committed
Allow type parameters in by-name implicit to be instantiated to Nothing
Nothing has legitimate use as a type parameter, so special-casing inference to reject it can cause issues. Also by removing this special-case we can remove the error reporting logic dedicated to dealing with non-fully-defined types, instead the user will see that a type parameter was instantiated to `Nothing` in the error which should be clear enough.
1 parent 9270839 commit 0b4c2af

File tree

3 files changed

+8
-33
lines changed

3 files changed

+8
-33
lines changed

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

Lines changed: 5 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -486,10 +486,9 @@ object Implicits:
486486

487487
class DivergingImplicit(ref: TermRef,
488488
val expectedType: Type,
489-
val argument: Tree,
490-
addendum: => String = "") extends SearchFailureType {
489+
val argument: Tree) extends SearchFailureType {
491490
def explanation(using Context): String =
492-
em"${err.refStr(ref)} produces a diverging implicit search when trying to $qualify$addendum"
491+
em"${err.refStr(ref)} produces a diverging implicit search when trying to $qualify"
493492
}
494493

495494
class FailedExtension(extApp: Tree, val expectedType: Type) extends SearchFailureType:
@@ -1100,13 +1099,7 @@ trait Implicits:
11001099
*/
11011100
def tryImplicit(cand: Candidate, contextual: Boolean): SearchResult =
11021101
if checkDivergence(cand) then
1103-
val addendum = ctx.searchHistory.disqualifiedType match
1104-
case NoType => ""
1105-
case disTp =>
1106-
em""".
1107-
|Note that open search type $disTp cannot be re-used as a by-name implicit parameter
1108-
|since it is not fully defined"""
1109-
SearchFailure(new DivergingImplicit(cand.ref, wideProto, argument, addendum))
1102+
SearchFailure(new DivergingImplicit(cand.ref, wideProto, argument))
11101103
else {
11111104
val history = ctx.searchHistory.nest(cand, pt)
11121105
val result =
@@ -1376,12 +1369,9 @@ trait Implicits:
13761369
history match
13771370
case prev @ OpenSearch(cand1, tp, outer) =>
13781371
if cand1.ref eq cand.ref then
1379-
def checkFullyDefined =
1380-
val result = isFullyDefined(tp, ForceDegree.failBottom)
1381-
if !result then prev.disqualified = true
1382-
result
13831372
lazy val wildTp = wildApprox(tp.widenExpr)
1384-
if belowByname && (wildTp <:< wildPt) && checkFullyDefined then
1373+
if belowByname && (wildTp <:< wildPt) then
1374+
fullyDefinedType(tp, "by-name implicit parameter", span)
13851375
false
13861376
else if prev.typeSize > ptSize || prev.coveringSet != ptCoveringSet then
13871377
loop(outer, tp.isByName || belowByname)
@@ -1473,15 +1463,6 @@ abstract class SearchHistory:
14731463
def defineBynameImplicit(tpe: Type, result: SearchSuccess)(using Context): SearchResult =
14741464
root.defineBynameImplicit(tpe, result)
14751465

1476-
/** There is a qualifying call-by-name parameter in the history
1477-
* that cannot be used since is it not fully defined. Used for error reporting.
1478-
*/
1479-
def disqualifiedType: Type =
1480-
def loop(h: SearchHistory): Type = h match
1481-
case h: OpenSearch => if h.disqualified then h.pt else loop(h.outer)
1482-
case _ => NoType
1483-
loop(this)
1484-
14851466
// This is NOOP unless at the root of this search history.
14861467
def emitDictionary(span: Span, result: SearchResult)(using Context): SearchResult = result
14871468

@@ -1501,10 +1482,6 @@ case class OpenSearch(cand: Candidate, pt: Type, outer: SearchHistory)(using Con
15011482
// An example is in neg/9504.scala
15021483
lazy val typeSize = pt.typeSize
15031484
lazy val coveringSet = pt.coveringSet
1504-
1505-
// Set if there would be a qualifying call-by-name parameter
1506-
// that cannot be used since is it not fully defined
1507-
var disqualified: Boolean = false
15081485
end OpenSearch
15091486

15101487
/**

tests/neg/i3452.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ object Test {
66
implicit def case1[F[_]](implicit t: => TC[F[Any]]): TC[Tuple2K[[_] =>> Any, F, Any]] = ???
77
implicit def case2[A, F[_]](implicit r: TC[F[Any]]): TC[A] = ???
88

9-
implicitly[TC[Int]] // error
9+
implicitly[TC[Int]] // typechecks because we infer F := Nothing (should we avoid inferring Nothing for higher-kinded types?)
1010
}
1111

1212
object Test1 {

tests/neg/i9568.check

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
|no implicit argument of type => Monad[([_$3] =>> Any)] was found for parameter ev of method blaMonad in object Test.
55
|I found:
66
|
7-
| Test.blaMonad[F, S](/* missing */summon[Monad[F]])
7+
| Test.blaMonad[Nothing, S](Test.blaMonad[F, S])
88
|
9-
|But method blaMonad in object Test produces a diverging implicit search when trying to match type Monad[F].
10-
|Note that open search type => Monad[([X] =>> Bla[F, X])] cannot be re-used as a by-name implicit parameter
11-
|since it is not fully defined.
9+
|But method blaMonad in object Test does not match type => Monad[Nothing].

0 commit comments

Comments
 (0)