@@ -14,7 +14,7 @@ import Flags._
14
14
import TypeErasure .{erasure , hasStableErasure }
15
15
import Mode .ImplicitsEnabled
16
16
import NameOps ._
17
- import NameKinds .LazyImplicitName
17
+ import NameKinds .{ LazyImplicitName , EvidenceParamName }
18
18
import Symbols ._
19
19
import Denotations ._
20
20
import Types ._
@@ -67,6 +67,14 @@ object Implicits {
67
67
final val Extension = 4
68
68
}
69
69
70
+ /** If `expected` is a selection prototype, does `tp` have an extension
71
+ * method with the selecting name? False otherwise.
72
+ */
73
+ def hasExtMethod (tp : Type , expected : Type )(given Context ) = expected match
74
+ case SelectionProto (name, _, _, _) =>
75
+ tp.memberBasedOnFlags(name, required = ExtensionMethod ).exists
76
+ case _ => false
77
+
70
78
/** A common base class of contextual implicits and of-type implicits which
71
79
* represents a set of references to implicit definitions.
72
80
*/
@@ -147,11 +155,7 @@ object Implicits {
147
155
val isImplicitConversion = tpw.derivesFrom(defn.ConversionClass )
148
156
// An implementation of <:< counts as a view
149
157
val isConforms = tpw.derivesFrom(defn.SubTypeClass )
150
- val hasExtensions = resType match {
151
- case SelectionProto (name, _, _, _) =>
152
- tpw.memberBasedOnFlags(name, required = ExtensionMethod ).exists
153
- case _ => false
154
- }
158
+ val hasExtensions = hasExtMethod(tpw, resType)
155
159
val conversionKind =
156
160
if (isFunctionInS2 || isImplicitConversion || isConforms) Candidate .Conversion
157
161
else Candidate .None
@@ -1215,32 +1219,37 @@ trait Implicits { self: Typer =>
1215
1219
pt.typeSymbol.typeParams.map(_.name.unexpandedName.toString),
1216
1220
pt.widenExpr.argInfos))
1217
1221
1218
- def hiddenImplicitsAddendum : String = arg.tpe match {
1219
- case fail : SearchFailureType =>
1220
-
1221
- def hiddenImplicitNote (s : SearchSuccess ) =
1222
- em " \n\n Note: given instance ${s.ref.symbol.showLocated} was not considered because it was not imported with `import given`. "
1222
+ def hiddenImplicitsAddendum : String =
1223
+
1224
+ def hiddenImplicitNote (s : SearchSuccess ) =
1225
+ em " \n\n Note: given instance ${s.ref.symbol.showLocated} was not considered because it was not imported with `import given`. "
1226
+
1227
+ def FindHiddenImplicitsCtx (ctx : Context ): Context =
1228
+ if (ctx == NoContext ) ctx
1229
+ else ctx.freshOver(FindHiddenImplicitsCtx (ctx.outer)).addMode(Mode .FindHiddenImplicits )
1230
+
1231
+ val normalImports = arg.tpe match
1232
+ case fail : SearchFailureType =>
1233
+ if (fail.expectedType eq pt) || isFullyDefined(fail.expectedType, ForceDegree .none) then
1234
+ inferImplicit(fail.expectedType, fail.argument, arg.span)(
1235
+ FindHiddenImplicitsCtx (ctx)) match {
1236
+ case s : SearchSuccess => hiddenImplicitNote(s)
1237
+ case f : SearchFailure =>
1238
+ f.reason match {
1239
+ case ambi : AmbiguousImplicits => hiddenImplicitNote(ambi.alt1)
1240
+ case r => " "
1241
+ }
1242
+ }
1243
+ else
1244
+ // It's unsafe to search for parts of the expected type if they are not fully defined,
1245
+ // since these come with nested contexts that are lost at this point. See #7249 for an
1246
+ // example where searching for a nested type causes an infinite loop.
1247
+ " "
1223
1248
1224
- def FindHiddenImplicitsCtx ( ctx : Context ) : Context =
1225
- if (ctx == NoContext ) ctx
1226
- else ctx.freshOver( FindHiddenImplicitsCtx (ctx.outer)).addMode( Mode . FindHiddenImplicits )
1249
+ def suggestedImports = importSuggestionAddendum(pt)
1250
+ if normalImports.isEmpty then suggestedImports else normalImports
1251
+ end hiddenImplicitsAddendum
1227
1252
1228
- if (fail.expectedType eq pt) || isFullyDefined(fail.expectedType, ForceDegree .none) then
1229
- inferImplicit(fail.expectedType, fail.argument, arg.span)(
1230
- FindHiddenImplicitsCtx (ctx)) match {
1231
- case s : SearchSuccess => hiddenImplicitNote(s)
1232
- case f : SearchFailure =>
1233
- f.reason match {
1234
- case ambi : AmbiguousImplicits => hiddenImplicitNote(ambi.alt1)
1235
- case r => " "
1236
- }
1237
- }
1238
- else
1239
- // It's unsafe to search for parts of the expected type if they are not fully defined,
1240
- // since these come with nested contexts that are lost at this point. See #7249 for an
1241
- // example where searching for a nested type causes an infinite loop.
1242
- " "
1243
- }
1244
1253
msg(userDefined.getOrElse(
1245
1254
em " no implicit argument of type $pt was found ${location(" for" )}" ))() ++
1246
1255
hiddenImplicitsAddendum
@@ -1256,7 +1265,8 @@ trait Implicits { self: Typer =>
1256
1265
def addendum = if (qt1 eq qt) " " else (i " \n which is an alias of: $qt1" )
1257
1266
em " parameter of ${qual.tpe.widen}$addendum"
1258
1267
case _ =>
1259
- em " parameter ${paramName} of $methodStr"
1268
+ em " ${ if paramName.is(EvidenceParamName ) then " an implicit parameter"
1269
+ else s " parameter $paramName" } of $methodStr"
1260
1270
}
1261
1271
1262
1272
private def strictEquality (implicit ctx : Context ): Boolean =
@@ -1352,32 +1362,10 @@ trait Implicits { self: Typer =>
1352
1362
ctx.searchHistory.emitDictionary(span, result)
1353
1363
}
1354
1364
1355
- /** An implicit search; parameters as in `inferImplicit` */
1356
- class ImplicitSearch (protected val pt : Type , protected val argument : Tree , span : Span )(implicit ctx : Context ) {
1357
- assert(argument.isEmpty || argument.tpe.isValueType || argument.tpe.isInstanceOf [ExprType ],
1358
- em " found: $argument: ${argument.tpe}, expected: $pt" )
1359
-
1360
- private def nestedContext () =
1361
- ctx.fresh.setMode(ctx.mode &~ Mode .ImplicitsEnabled )
1362
-
1363
- private def implicitProto (resultType : Type , f : Type => Type ) =
1364
- if (argument.isEmpty) f(resultType) else ViewProto (f(argument.tpe.widen), f(resultType))
1365
- // Not clear whether we need to drop the `.widen` here. All tests pass with it in place, though.
1366
-
1367
- private def isCoherent = pt.isRef(defn.EqlClass )
1368
-
1369
- /** The expected type for the searched implicit */
1370
- @ threadUnsafe lazy val fullProto : Type = implicitProto(pt, identity)
1371
-
1372
- /** The expected type where parameters and uninstantiated typevars are replaced by wildcard types */
1373
- val wildProto : Type = implicitProto(pt, wildApprox(_))
1374
-
1375
- val isNot : Boolean = wildProto.classSymbol == defn.NotClass
1376
-
1377
- // println(i"search implicits $pt / ${eligible.map(_.ref)}")
1378
-
1379
- /** Try to typecheck an implicit reference */
1380
- def typedImplicit (cand : Candidate , contextual : Boolean )(implicit ctx : Context ): SearchResult = trace(i " typed implicit ${cand.ref}, pt = $pt, implicitsEnabled == ${ctx.mode is ImplicitsEnabled }" , implicits, show = true ) {
1365
+ /** Try to typecheck an implicit reference */
1366
+ def typedImplicit (cand : Candidate , pt : Type , argument : Tree , span : Span )(implicit ctx : Context ): SearchResult = trace(i " typed implicit ${cand.ref}, pt = $pt, implicitsEnabled == ${ctx.mode is ImplicitsEnabled }" , implicits, show = true ) {
1367
+ if ctx.run.isCancelled then NoMatchingImplicitsFailure
1368
+ else
1381
1369
record(" typedImplicit" )
1382
1370
val ref = cand.ref
1383
1371
val generated : Tree = tpd.ref(ref).withSpan(span.startPos)
@@ -1431,6 +1419,30 @@ trait Implicits { self: Typer =>
1431
1419
}
1432
1420
}
1433
1421
1422
+ /** An implicit search; parameters as in `inferImplicit` */
1423
+ class ImplicitSearch (protected val pt : Type , protected val argument : Tree , span : Span )(implicit ctx : Context ) {
1424
+ assert(argument.isEmpty || argument.tpe.isValueType || argument.tpe.isInstanceOf [ExprType ],
1425
+ em " found: $argument: ${argument.tpe}, expected: $pt" )
1426
+
1427
+ private def nestedContext () =
1428
+ ctx.fresh.setMode(ctx.mode &~ Mode .ImplicitsEnabled )
1429
+
1430
+ private def implicitProto (resultType : Type , f : Type => Type ) =
1431
+ if (argument.isEmpty) f(resultType) else ViewProto (f(argument.tpe.widen), f(resultType))
1432
+ // Not clear whether we need to drop the `.widen` here. All tests pass with it in place, though.
1433
+
1434
+ private def isCoherent = pt.isRef(defn.EqlClass )
1435
+
1436
+ /** The expected type for the searched implicit */
1437
+ @ threadUnsafe lazy val fullProto : Type = implicitProto(pt, identity)
1438
+
1439
+ /** The expected type where parameters and uninstantiated typevars are replaced by wildcard types */
1440
+ val wildProto : Type = implicitProto(pt, wildApprox(_))
1441
+
1442
+ val isNot : Boolean = wildProto.classSymbol == defn.NotClass
1443
+
1444
+ // println(i"search implicits $pt / ${eligible.map(_.ref)}")
1445
+
1434
1446
/** Try to type-check implicit reference, after checking that this is not
1435
1447
* a diverging search
1436
1448
*/
@@ -1440,7 +1452,7 @@ trait Implicits { self: Typer =>
1440
1452
else {
1441
1453
val history = ctx.searchHistory.nest(cand, pt)
1442
1454
val result =
1443
- typedImplicit(cand, contextual )(nestedContext().setNewTyperState().setFreshGADTBounds.setSearchHistory(history))
1455
+ typedImplicit(cand, pt, argument, span )(nestedContext().setNewTyperState().setFreshGADTBounds.setSearchHistory(history))
1444
1456
result match {
1445
1457
case res : SearchSuccess =>
1446
1458
ctx.searchHistory.defineBynameImplicit(pt.widenExpr, res)
0 commit comments