Skip to content

Commit 569087b

Browse files
committed
Implement changed import implied rules
`import implied` now also imports old-style implicits. Missing implicits errors now report if an implied instance could have been imported if a regular import is changed to an import implied.
1 parent 8a98b18 commit 569087b

File tree

5 files changed

+100
-20
lines changed

5 files changed

+100
-20
lines changed

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -432,8 +432,11 @@ object Contexts {
432432
this
433433
}
434434

435-
/** A fresh clone of this context. */
436-
def fresh: FreshContext = clone.asInstanceOf[FreshContext].init(this)
435+
/** A fresh clone of this context embedded in this context. */
436+
def fresh: FreshContext = freshOver(this)
437+
438+
/** A fresh clone of this context embedded in the specified `outer` context. */
439+
def freshOver(outer: Context): FreshContext = clone.asInstanceOf[FreshContext].init(outer)
437440

438441
final def withOwner(owner: Symbol): Context =
439442
if (owner ne this.owner) fresh.setOwner(owner) else this

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,4 +104,7 @@ object Mode {
104104

105105
/** We are synthesizing the receiver of an extension method */
106106
val SynthesizeExtMethodReceiver: Mode = newMode(23, "SynthesizeExtMethodReceiver")
107+
108+
/** Are we trying to find a hidden implicit? */
109+
val FindHiddenImplicits: Mode = newMode(24, "FindHiddenImplicits")
107110
}

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

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ object Implicits {
364364

365365
abstract class SearchFailureType extends ErrorType {
366366
def expectedType: Type
367-
protected def argument: Tree
367+
def argument: Tree
368368

369369
/** A "massaging" function for displayed types to give better info in error diagnostics */
370370
def clarify(tp: Type)(implicit ctx: Context): Type = tp
@@ -822,6 +822,7 @@ trait Implicits { self: Typer =>
822822
}
823823

824824
def missingArgMsg(arg: Tree, pt: Type, where: String)(implicit ctx: Context): String = {
825+
825826
def msg(shortForm: String)(headline: String = shortForm) = arg match {
826827
case arg: Trees.SearchFailureIdent[_] =>
827828
shortForm
@@ -836,6 +837,7 @@ trait Implicits { self: Typer =>
836837
|But ${tpe.explanation}."""
837838
}
838839
}
840+
839841
def location(preposition: String) = if (where.isEmpty) "" else s" $preposition $where"
840842

841843
/** Extract a user defined error message from a symbol `sym`
@@ -898,7 +900,30 @@ trait Implicits { self: Typer =>
898900
raw,
899901
pt.typeSymbol.typeParams.map(_.name.unexpandedName.toString),
900902
pt.argInfos))
901-
msg(userDefined.getOrElse(em"no implicit argument of type $pt was found${location("for")}"))()
903+
904+
def hiddenImplicitsAddendum: String = arg.tpe match {
905+
case fail: SearchFailureType =>
906+
907+
def hiddenImplicitNote(s: SearchSuccess) =
908+
em"\n\nNote: implied instance ${s.ref.symbol.showLocated} was not considered because it was not imported with an `import implied`."
909+
910+
def FindHiddenImplicitsCtx(ctx: Context): Context =
911+
if (ctx == NoContext) ctx
912+
else ctx.freshOver(FindHiddenImplicitsCtx(ctx.outer)).addMode(Mode.FindHiddenImplicits)
913+
914+
inferImplicit(fail.expectedType, fail.argument, fail.argument.span)(
915+
FindHiddenImplicitsCtx(ctx)) match {
916+
case s: SearchSuccess => hiddenImplicitNote(s)
917+
case f: SearchFailure =>
918+
f.reason match {
919+
case ambi: AmbiguousImplicits => hiddenImplicitNote(ambi.alt1)
920+
case r => ""
921+
}
922+
}
923+
}
924+
msg(userDefined.getOrElse(
925+
em"no implicit argument of type $pt was found${location("for")}"))() ++
926+
hiddenImplicitsAddendum
902927
}
903928
}
904929

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,9 @@ class ImportInfo(symf: Context => Symbol, val selectors: List[untpd.Tree],
9595
recur(selectors)
9696
}
9797

98-
private def implicitFlag = if (importImplied) Implied else Implicit
98+
private def implicitFlag(implicit ctx: Context) =
99+
if (importImplied || ctx.mode.is(Mode.FindHiddenImplicits)) ImplicitOrImplied
100+
else Implicit
99101

100102
/** The implicit references imported by this import clause */
101103
def importedImplicits(implicit ctx: Context): List[ImplicitRef] = {

tests/pos/i5978.scala

Lines changed: 62 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,74 @@ opaque type Position[Buffer] = Int
44

55
trait TokenParser[Token, R]
66

7-
object TextParser {
8-
implied TP for TokenParser[Char, Position[CharSequence]] {}
7+
package p1 {
98

10-
implied FromCharToken
11-
given (T: TokenParser[Char, Position[CharSequence]]) for Conversion[Char, Position[CharSequence]] = ???
9+
object TextParser {
10+
implied TP for TokenParser[Char, Position[CharSequence]] {}
11+
12+
implied FromCharToken
13+
given (T: TokenParser[Char, Position[CharSequence]]) for Conversion[Char, Position[CharSequence]] = ???
14+
}
15+
16+
17+
object Testcase {
18+
def main(args: Array[String]): Unit = {
19+
import implied TextParser._
20+
import TextParser._
21+
22+
val tp_v: TokenParser[Char, Position[CharSequence]] = TextParser.TP
23+
val tp_i = the[TokenParser[Char, Position[CharSequence]]]
24+
val co_i = the[Conversion[Char, Position[CharSequence]]]
25+
val co_x : Position[CharSequence] = 'x'
26+
27+
{
28+
implied XXX for Conversion[Char, Position[CharSequence]] = co_i
29+
val co_y : Position[CharSequence] = 'x'
30+
}
31+
}
32+
}
33+
}
34+
package p2 {
35+
36+
object TextParser {
37+
implicit object TP extends TokenParser[Char, Position[CharSequence]] {}
38+
39+
implicit def FromCharToken(c: Char)(implicit T: TokenParser[Char, Position[CharSequence]]): Position[CharSequence] = ???
40+
}
41+
42+
object Testcase {
43+
def main(args: Array[String]): Unit = {
44+
import TextParser._
45+
import implied TextParser._
46+
47+
val tp_v: TokenParser[Char, Position[CharSequence]] = TextParser.TP
48+
val tp_i = the[TokenParser[Char, Position[CharSequence]]]
49+
val co_x : Position[CharSequence] = 'x'
50+
}
51+
}
1252
}
53+
package p3 {
1354

55+
object TextParser {
56+
implicit object TP extends TokenParser[Char, Position[CharSequence]] {}
57+
58+
implicit def FromCharToken(implicit T: TokenParser[Char, Position[CharSequence]]): Conversion[Char, Position[CharSequence]] = ???
59+
}
1460

15-
object Testcase {
16-
def main(args: Array[String]): Unit = {
17-
import TextParser._
18-
import implied TextParser._
61+
object Testcase {
62+
def main(args: Array[String]): Unit = {
63+
import implied TextParser._
64+
import TextParser._
1965

20-
val tp_v: TokenParser[Char, Position[CharSequence]] = TextParser.TP
21-
val tp_i = the[TokenParser[Char, Position[CharSequence]]]
22-
val co_i = the[Conversion[Char, Position[CharSequence]]]
23-
val co_x : Position[CharSequence] = 'x'
66+
val tp_v: TokenParser[Char, Position[CharSequence]] = TextParser.TP
67+
val tp_i = the[TokenParser[Char, Position[CharSequence]]]
68+
implicit val co_i: Conversion[Char, Position[CharSequence]] = the[Conversion[Char, Position[CharSequence]]]
69+
val co_x : Position[CharSequence] = 'x'
2470

25-
{
26-
implied XXX for Conversion[Char, Position[CharSequence]] = co_i
27-
val co_y : Position[CharSequence] = 'x'
71+
{
72+
implied XXX for Conversion[Char, Position[CharSequence]] = co_i
73+
val co_y : Position[CharSequence] = 'x'
74+
}
2875
}
2976
}
3077
}

0 commit comments

Comments
 (0)