Skip to content

Commit b40b9de

Browse files
authored
Merge pull request #15320 from dotty-staging/fix-15301
Prevent crash when reporting an error
2 parents 77bcd0d + 6b68924 commit b40b9de

File tree

3 files changed

+67
-2
lines changed

3 files changed

+67
-2
lines changed

compiler/src/dotty/tools/dotc/ast/Trees.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1646,7 +1646,9 @@ object Trees {
16461646
}
16471647

16481648
def foldMoreCases(x: X, tree: Tree)(using Context): X = {
1649-
assert(ctx.reporter.errorsReported || ctx.mode.is(Mode.Interactive), tree)
1649+
assert(ctx.reporter.hasUnreportedErrors
1650+
|| ctx.reporter.errorsReported
1651+
|| ctx.mode.is(Mode.Interactive), tree)
16501652
// In interactive mode, errors might come from previous runs.
16511653
// In case of errors it may be that typed trees point to untyped ones.
16521654
// The IDE can still traverse inside such trees, either in the run where errors

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ object ProtoTypes {
362362
* - t2 is a ascription (t22: T) and t1 is at the outside of t22
363363
* - t2 is a closure (...) => t22 and t1 is at the outside of t22
364364
*/
365-
def hasInnerErrors(t: Tree): Boolean = t match
365+
def hasInnerErrors(t: Tree)(using Context): Boolean = t match
366366
case Typed(expr, tpe) => hasInnerErrors(expr)
367367
case closureDef(mdef) => hasInnerErrors(mdef.rhs)
368368
case _ =>

tests/neg/i15301.scala

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package theproblem
2+
3+
import scala.concurrent.{ ExecutionContext, Future }
4+
import scala.concurrent.ExecutionContext.Implicits.global
5+
6+
object Items:
7+
opaque type TheId = Int
8+
extension (TheId: TheId) def raw: Int = TheId
9+
10+
object TheId:
11+
def apply(id: Int): TheId = id
12+
13+
14+
import Items.TheId
15+
16+
case class AnError(id: TheId)
17+
18+
type ErrAcc[A] = Either[Seq[AnError], A]
19+
20+
case class Res[A](future: Future[ErrAcc[A]]):
21+
22+
def map[B](f: A => B)(using ExecutionContext): Res[B] =
23+
Res(this.future.map(_.map(f)))
24+
25+
def flatMap[B](f: A => Res[B])(using ExecutionContext): Res[B] =
26+
Res(this.future.flatMap {
27+
case Right(x) => f(x).future
28+
case Left(es) => Future.successful(Left[Seq[AnError], B](es))
29+
})
30+
31+
def zip[B](that: Res[B])(using ExecutionContext): Res[(A, B)] =
32+
def zipacc(a: ErrAcc[A], b: ErrAcc[B]): ErrAcc[(A, B)] = (a, b) match
33+
case (Right(x), Right(y)) => Right((x, y))
34+
case (Right(_), Left(e) ) => Left(e)
35+
case (Left(e), Right(_)) => Left(e)
36+
case (Left(ex), Left(ey)) => Left(ex ++ ey)
37+
38+
Res(this.future.flatMap { a => that.future.map { b => zipacc(a, b) } })
39+
40+
object Res:
41+
def successful[A](x: A): Res[A] = Res(Future.successful(Right[Seq[AnError], A](x)))
42+
43+
def traverse[A, B](as: Seq[A])(f: A => Res[B])(using ExecutionContext): Res[Seq[B]] =
44+
as.foldLeft[Res[Seq[B]]](successful(Seq.empty)) { (acc, x) => acc.zip(f(x)).map(_ :+ _) }
45+
46+
trait M:
47+
def getID(name: String)(using ExecutionContext): Res[TheId]
48+
def bfs(sid: TheId, tid: TheId): Res[Boolean]
49+
50+
class theproblem(m: M):
51+
52+
def thebug(names: List[String]): Res[Seq[(String, String, Boolean)]] =
53+
Res.traverse(names)(m.getID).flatMap { ids =>
54+
val id_names = ids.zip(names)
55+
val ps = for {
56+
(sid, sname) <- id_names
57+
(tid, tname) <- id_names
58+
if sid != tid
59+
} yield (sid -> sname, tid -> tname)
60+
Res.traverse(ps){ (s, t) =>
61+
m.bfs(s(0), t(0)).map((s(1), t(2), _)) // error t(2) should be t(1)
62+
}
63+
}

0 commit comments

Comments
 (0)