Skip to content

[WIP] Fix #4986 Support implicitNotFound in Method Def. #6703

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
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
21 changes: 17 additions & 4 deletions compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,23 @@ package typer

import ast._
import core._
import Types._, ProtoTypes._, Contexts._, Decorators._, Denotations._, Symbols._
import Implicits._, Flags._
import Types._
import ProtoTypes._
import Contexts._
import Decorators._
import Denotations._
import Symbols._
import Implicits._
import Flags._
import util.Spans._
import util.SourcePosition
import java.util.regex.Matcher.quoteReplacement

import reporting.diagnostic.Message
import reporting.diagnostic.messages._

import scala.util.matching.Regex

object ErrorReporting {

import tpd._
Expand Down Expand Up @@ -152,10 +161,14 @@ object ErrorReporting {
*/
def userDefinedErrorString(raw: String, paramNames: List[String], args: List[Type]): String = {
def translate(name: String): Option[String] = {
println("<" + name + ">")
val idx = paramNames.indexOf(name)
if (idx >= 0) Some(quoteReplacement(ex"${args(idx)}")) else None
if (idx >= 0) Some(ex"${args(idx)}") else None
}
"""\$\{\w*\}""".r.replaceSomeIn(raw, m => translate(m.matched.drop(2).init))
println(raw)
"""\$\{\s*([^}\s]+)\s*\}""".r.replaceAllIn(raw, (_: Regex.Match) match {
case Regex.Groups(v) => quoteReplacement(translate(v).getOrElse(""))
})
}

def rewriteNotice: String =
Expand Down
19 changes: 13 additions & 6 deletions compiler/src/dotty/tools/dotc/typer/Implicits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ package dotc
package typer

import core._
import ast.{Trees, TreeTypeMap, untpd, tpd}
import ast.{TreeTypeMap, Trees, tpd, untpd}
import util.Spans._
import util.Stats.{track, record, monitored}
import printing.{Showable, Printer}
import util.Stats.{monitored, record, track}
import printing.{Printer, Showable}
import printing.Texts._
import Contexts._
import Types._
Expand All @@ -28,13 +28,15 @@ import reporting.diagnostic.Message
import Inferencing.fullyDefinedType
import Trees._
import Hashable._
import util.{Property, SourceFile, NoSource}
import util.{NoSource, Property, SourceFile}
import config.Config
import config.Printers.{implicits, implicitsDetailed}
import dotty.tools.dotc.core.Annotations.Annotation

import collection.mutable
import reporting.trace
import annotation.tailrec

import annotation.tailrec
import scala.annotation.internal.sharable

/** Implicit resolution */
Expand Down Expand Up @@ -859,11 +861,16 @@ trait Implicits { self: Typer =>

def location(preposition: String) = if (where.isEmpty) "" else s" $preposition $where"

@tailrec def annotationOnType(cls: Symbol, tp: Type): Option[Annotation] = tp.widen match {
case AnnotatedType(tpe, ann) => if (ann matches cls) Some(ann) else annotationOnType(cls, tpe)
case _ => None
}

/** Extract a user defined error message from a symbol `sym`
* with an annotation matching the given class symbol `cls`.
*/
def userDefinedMsg(sym: Symbol, cls: Symbol) = for {
ann <- sym.getAnnotation(cls)
ann <- annotationOnType(cls, pt).orElse(sym.getAnnotation(cls))
Trees.Literal(Constant(msg: String)) <- ann.argument(0)
} yield msg

Expand Down
25 changes: 25 additions & 0 deletions tests/neg-custom-args/fatal-warnings/t2462b.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package test

import scala.annotation.implicitNotFound

@implicitNotFound(msg = "Cannot construct a collection of type ${Too} with elements of type ${Elem} based on a collection of type ${From}.")
trait Meh[-From, +To]

@implicitNotFound(msg = "Cannot construct a collection of type ${To} ${Elem}.")
trait Meh2[-From, +To]

class C[T]
trait T {
def m[Aaa](implicit theC: C[Aaa] @implicitNotFound("I see no C[${Uuh}]")) = ???
def n[Aaa](implicit theC: C[Aaa] @implicitNotFound("I see no C[${Aaa}]")) = ???
}

trait U[X, Y[_], Z[_, ZZ]] {
class I[R] {
def m[S](implicit i: Int @implicitNotFound("${X} ${Y} ${ Z } ${R} ${S} -- ${XX} ${ZZ} ${ Nix }")) = ???
}
}

// error
// error
// error
9 changes: 9 additions & 0 deletions tests/neg/t2462a.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-- Error: tests/neg/t2462a.scala:2:44 ----------------------------------------------------------------------------------
2 | List(1,2,3).map[Int, List[String]](x => 1) // error
| ^
|Cannot construct a collection of type List[String] with elements of type Int based on a collection of type List[Int]..
|I found:
|
| scala.collection.immutable.List.canBuildFrom[Nothing]
|
|But method canBuildFrom in object List does not match type scala.collection.generic.CanBuildFrom[List[Int], Int, List[String]].
3 changes: 3 additions & 0 deletions tests/neg/t2462a.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
object Test {
List(1,2,3).map[Int, List[String]](x => 1) // error
}
20 changes: 20 additions & 0 deletions tests/neg/t2462c.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
-- Error: tests/neg/t2462c.scala:24:8 ----------------------------------------------------------------------------------
24 | f[X$Y] // error
| ^
| No C of X$Y
-- Error: tests/neg/t2462c.scala:30:13 ---------------------------------------------------------------------------------
30 | f[Foo[Int]] // error
| ^
| No C of Foo[Int]
-- Error: tests/neg/t2462c.scala:33:13 ---------------------------------------------------------------------------------
33 | g[Foo[Int]] // error
| ^
| No C of Foo[Int]
-- Error: tests/neg/t2462c.scala:36:13 ---------------------------------------------------------------------------------
36 | h[Foo[Int]] // error
| ^
| No C of Foo[Int]
-- Error: tests/neg/t2462c.scala:40:19 ---------------------------------------------------------------------------------
40 | i.m[Option[Long]] // error
| ^
| no implicit argument of type Int was found for parameter i of method m in class I
41 changes: 41 additions & 0 deletions tests/neg/t2462c.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@

import annotation._

@implicitNotFound("No C of ${ A }")
class C[A]

trait X$Y
/* using the $$ separator for expanded names is unwise
trait X$$Y
trait X$$$Y
trait X$$$$Y
*/

trait Foo[A]

trait U[X, Y[_], Z[_, ZZ]] {
class I[R] {
def m[S](implicit i: Int @implicitNotFound("${X} ${Y} ${ Z } ${R} ${S} -- ${XX}.")) = ???
}
}

class Test {
def f[A: C] = ???
f[X$Y] // error
/* using the $$ separator for expanded names is unwise
f[X$$Y]
f[X$$$Y]
f[X$$$$Y]
*/
f[Foo[Int]] // error

def g[Aaa](implicit theC: C[Aaa]) = ???
g[Foo[Int]] // error

def h[Aaa](implicit theC: C[Aaa] @implicitNotFound("I see no C[${Aaa}]")) = ???
h[Foo[Int]] // error

val u = new U[String, List, ({type T[A, _] = List[C[_]]})#T] { }
val i = new u.I[Int]
i.m[Option[Long]] // error
}
4 changes: 0 additions & 4 deletions tests/untried/neg/t2462a.check

This file was deleted.

3 changes: 0 additions & 3 deletions tests/untried/neg/t2462a.scala

This file was deleted.

1 change: 0 additions & 1 deletion tests/untried/neg/t2462b.flags

This file was deleted.

9 changes: 0 additions & 9 deletions tests/untried/neg/t2462b.scala

This file was deleted.

7 changes: 0 additions & 7 deletions tests/untried/neg/t2462c.check

This file was deleted.

1 change: 0 additions & 1 deletion tests/untried/neg/t2462c.flags

This file was deleted.

25 changes: 0 additions & 25 deletions tests/untried/neg/t2462c.scala

This file was deleted.