Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion compiler/src/dotty/tools/dotc/reporting/messages.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import Contexts.*
import Decorators.*, Symbols.*, Names.*, NameOps.*, Types.*, Flags.*, Phases.*
import Denotations.SingleDenotation
import SymDenotations.SymDenotation
import NameKinds.{WildcardParamName, ContextFunctionParamName}
import NameKinds.{WildcardParamName, ContextFunctionParamName, SimpleNameKind}
import parsing.Scanners.Token
import parsing.Tokens, Tokens.showToken
import printing.Highlighting.*
Expand Down Expand Up @@ -3235,6 +3235,23 @@ class MissingImplicitArgument(
i"The following implicits in scope can be implicitly converted to ${pt.show}:" +
ignoredConvertibleImplicits.map { imp => s"\n- ${imp.symbol.showDcl}"}.mkString
)
def noteTrailingContextOfExtension: Option[String] =
paramSymWithMethodCallTree.flatMap: (sym, applTree) =>
def hasLeadingImplicit(tpe: Type): Boolean =
val resTypes = Iterator.iterate(tpe.resultType)(_.resultType)
val (prefix, suffix) = resTypes.span(_.isContextualMethod)
val tps = prefix ++ suffix.drop(1).takeWhile(_.isContextualMethod)
tps.exists:
case mt: MethodType => mt.paramNames.contains(sym.name)
case pt: PolyType => false
if applTree.symbol.is(Extension)
&& sym.info.typeSymbol != defn.SameTypeClass
&& sym.info.typeSymbol != defn.SubTypeClass
&& !hasLeadingImplicit(applTree.symbol.info) then
val name = if sym.name.is(SimpleNameKind) then i"`${sym.name}`" else "the missing arg"
Some(i"\n\nNote: ${name} is not a leading implicit of `${applTree.symbol.name}`; "
+ "it is not used to construct the extension.")
else None
def importSuggestionAddendum: String =
arg.tpe match
// If the failure was caused by an underlying NoMatchingImplicits, compute the addendum for its expected type
Expand All @@ -3243,6 +3260,7 @@ class MissingImplicitArgument(
case _ =>
ctx.typer.importSuggestionAddendum(pt)
super.msgPostscript
++ noteTrailingContextOfExtension.getOrElse("")
++ ignoredInstanceNormalImport.map(hiddenImplicitNote)
.orElse(noChainConversionsNote(ignoredConvertibleImplicits))
.getOrElse(importSuggestionAddendum)
Expand Down
12 changes: 12 additions & 0 deletions tests/neg/i23272.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
-- [E050] Type Error: tests/neg/i23272.scala:9:55 ----------------------------------------------------------------------
9 | def toArray: Array[Double] = v.components.map(c => c(lhs)) // error // error
| ^
| parameter c does not take parameters
|
| longer explanation available when compiling with `-explain`
-- [E172] Type Error: tests/neg/i23272.scala:9:62 ----------------------------------------------------------------------
9 | def toArray: Array[Double] = v.components.map(c => c(lhs)) // error // error
| ^
|No given instance of type Vectoric[Array[V => Double]] was found for parameter v of method map in trait VectoricOps
|
|Note: `v` is not a leading implicit of `map`; it is not used to construct the extension.
19 changes: 19 additions & 0 deletions tests/neg/i23272.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
trait Vectoric[V] {
def components: Array[V => Double]
def map(a: V)(f: Double => Double): V
}

trait VectoricOps {
extension [V: Vectoric as v](lhs: V) {
def map(f: Double => Double): V = v.map(lhs)(f)
def toArray: Array[Double] = v.components.map(c => c(lhs)) // error // error
}
}

trait WorkingVectoricOps {
// leading implicit is not found, so undesired extension map is not constructed
extension [V](lhs: V)(using v: Vectoric[V]) {
def map(f: Double => Double): V = v.map(lhs)(f)
def toArray: Array[Double] = v.components.map(c => c(lhs))
}
}
2 changes: 2 additions & 0 deletions tests/neg/missing-implicit1.check
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
| ^
|No given instance of type testObjectInstance.Zip[Option] was found for a context parameter of method traverse in trait Traverse
|
|Note: the missing arg is not a leading implicit of `traverse`; it is not used to construct the extension.
|
|The following import might fix the problem:
|
| import testObjectInstance.instances.zipOption
Expand Down
5 changes: 5 additions & 0 deletions tests/neg/missing-implicit1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,9 @@ object testObjectInstance:
import instances.traverseList
List(1, 2, 3).traverse(x => Option(x)) // error
}

locally {
import instances.given
List(1, 2, 3).traverse(x => Option(x)) // whew
}
end testObjectInstance
2 changes: 2 additions & 0 deletions tests/neg/missing-implicit4.check
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
| ^
| No given instance of type Zip[Option] was found for a context parameter of method traverse in trait Traverse
|
| Note: the missing arg is not a leading implicit of `traverse`; it is not used to construct the extension.
|
| The following import might fix the problem:
|
| import instances.zipOption
Expand Down
Loading