Skip to content

Commit c49dfba

Browse files
committed
Fix scala#4709: report if local implicits need type annotation
This improves the error message, and also puts more effort into diagnosing the cycle. Now we use the same logic as for recursive values to check we're indeed dealing with a (potentially) recursive implicit. Remaining `CyclicReferenceInvolvingImplicit` are unexpected and might involve bugs, so make the error message and explanation more tentative, following `CyclicReferenceInvolving`.
1 parent 38d07d9 commit c49dfba

File tree

4 files changed

+41
-10
lines changed

4 files changed

+41
-10
lines changed

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

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -102,24 +102,31 @@ class CyclicReference private (val denot: SymDenotation) extends TypeError {
102102

103103
override def toMessage(implicit ctx: Context) = {
104104

105-
def errorMsg(cx: Context): Message =
105+
def errorMsg(cycleSym: Symbol, isCycleSymImplicit: Boolean, cx: Context): Message = {
106106
if (cx.mode is Mode.InferringReturnType) {
107107
cx.tree match {
108108
case tree: untpd.DefDef if !tree.tpt.typeOpt.exists =>
109109
OverloadedOrRecursiveMethodNeedsResultType(tree.name)
110110
case tree: untpd.ValDef if !tree.tpt.typeOpt.exists =>
111-
RecursiveValueNeedsResultType(tree.name)
111+
if (isCycleSymImplicit) {
112+
assert(cycleSym.name == tree.name)
113+
ImplicitValNeedsResultType(cycleSym)
114+
} else {
115+
RecursiveValueNeedsResultType(tree.name)
116+
}
112117
case _ =>
113-
errorMsg(cx.outer)
118+
errorMsg(cycleSym, isCycleSymImplicit, cx.outer)
114119
}
115120
}
116-
else CyclicReferenceInvolving(denot)
121+
else if (isCycleSymImplicit)
122+
CyclicReferenceInvolvingImplicit(cycleSym)
123+
else
124+
CyclicReferenceInvolving(denot)
125+
}
117126

118127
val cycleSym = denot.symbol
119-
if (cycleSym.is(Implicit, butNot = Method) && cycleSym.owner.isTerm)
120-
CyclicReferenceInvolvingImplicit(cycleSym)
121-
else
122-
errorMsg(ctx)
128+
val isCycleSymImplicit = cycleSym.is(Implicit, butNot = Method) && cycleSym.owner.isTerm
129+
errorMsg(denot.symbol, isCycleSymImplicit, ctx)
123130
}
124131
}
125132

compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ public enum ErrorMessageID {
131131
MatchCaseOnlyNullWarningID,
132132
ImportRenamedTwiceID,
133133
TypeTestAlwaysSucceedsID,
134+
ImplicitValNeedsResultTypeID
134135
;
135136

136137
public int errorNumber() {

compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1298,8 +1298,10 @@ object messages {
12981298
val kind = "Syntax"
12991299
val msg = hl"""cyclic reference involving implicit $cycleSym"""
13001300
val explanation =
1301-
hl"""|This happens when the right hand-side of $cycleSym's definition involves an implicit search.
1302-
|To avoid this error, give `${cycleSym.name}` an explicit type.
1301+
hl"""|$cycleSym is declared as part of a cycle which makes it impossible for the
1302+
|compiler to decide upon ${cycleSym.name}'s type.
1303+
|This might happen when the right hand-side of $cycleSym's definition involves an implicit search.
1304+
|To avoid this error, try giving `${cycleSym.name}` an explicit type.
13031305
|""".stripMargin
13041306
}
13051307

@@ -2105,4 +2107,15 @@ object messages {
21052107
}
21062108
val explanation = ""
21072109
}
2110+
2111+
// Relative of CyclicReferenceInvolvingImplicit and RecursiveValueNeedsResultType
2112+
case class ImplicitValNeedsResultType(cycleSym: Symbol)(implicit ctx: Context)
2113+
extends Message(ImplicitValNeedsResultTypeID) {
2114+
val kind = "Syntax"
2115+
val msg = hl"""implicit $cycleSym needs result type because its right-hand side attempts implicit search"""
2116+
val explanation =
2117+
hl"""|The right hand-side of $cycleSym's definition requires an implicit search at the highlighted position.
2118+
|To avoid this error, give `${cycleSym.name}` an explicit type.
2119+
|""".stripMargin
2120+
}
21082121
}

tests/neg/i4709.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
class Context
2+
class ContextBase { def settings = 1 }
3+
4+
class Test {
5+
implicit def toBase(ctx: Context): ContextBase = ???
6+
7+
def test(ctx0: Context) = {
8+
implicit val ctx = { ctx0.settings; ??? } // error
9+
}
10+
}

0 commit comments

Comments
 (0)