Skip to content

Commit 87791a6

Browse files
committed
Further refine condition when not to typecheck again
This should fix the failures in spire and specs2.
1 parent 1608e47 commit 87791a6

File tree

2 files changed

+41
-2
lines changed

2 files changed

+41
-2
lines changed

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

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,24 @@ object ProtoTypes {
350350
*/
351351
def hasErrorArg = !state.errorArgs.isEmpty
352352

353+
/** Does tree have embedded error trees that are not at the outside.
354+
* A nested tree t1 is "at the outside" relative to a tree t2 if
355+
* - t1 and t2 have the same span, or
356+
* - t2 is a ascription (t22: T) and t1 is at the outside of t22
357+
* - t2 is a closure (...) => t22 and t1 is at the outside of t22
358+
*/
359+
def hasInnerErrors(t: Tree): Boolean = t match
360+
case Typed(expr, tpe) => hasInnerErrors(expr)
361+
case closureDef(mdef) => hasInnerErrors(mdef.rhs)
362+
case _ =>
363+
t.existsSubTree { t1 =>
364+
if t1.tpe.isError && t1.span.toSynthetic != t.span.toSynthetic then
365+
typr.println(i"error subtree $t1 of $t with ${t1.tpe}, spans = ${t1.span}, ${t.span}")
366+
true
367+
else
368+
false
369+
}
370+
353371
private def cacheTypedArg(arg: untpd.Tree, typerFn: untpd.Tree => Tree, force: Boolean)(using Context): Tree = {
354372
var targ = state.typedArg(arg)
355373
if (targ == null)
@@ -366,8 +384,9 @@ object ProtoTypes {
366384
targ = arg.withType(WildcardType)
367385
case _ =>
368386
targ = typerFn(arg)
369-
if ctx.reporter.hasUnreportedErrors && targ.existsSubTree(_.tpe.isError) then
370-
state.errorArgs += arg
387+
if ctx.reporter.hasUnreportedErrors then
388+
if hasInnerErrors(targ) then
389+
state.errorArgs += arg
371390
else
372391
state.typedArg = state.typedArg.updated(arg, targ)
373392
state.errorArgs -= arg

tests/pos/specs2-failure.scala

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import util.matching.Regex
2+
import util.matching.Regex.Match
3+
4+
// Demonstrate what used to be a failure in specs2, before we refined
5+
// the scheme when not to typecheck a function argument again.
6+
object Test:
7+
8+
extension (s: String)
9+
10+
def replaceAll(pairs: (String, String)*): String =
11+
pairs.foldLeft(s) { (res, cur) =>
12+
res.replaceAll(cur._1, cur._2)
13+
}
14+
15+
def replaceAll(exp: String, f: String => String): String =
16+
new Regex(exp).replaceAllIn(s, (m: Match) => f(m.group(0).replace("\\", "\\\\")))
17+
18+
def replaceInsideTag(tag: String, p: (String, String)*): String =
19+
s.replaceAll(tag, (s: String) => java.util.regex.Matcher.quoteReplacement(s.replaceAll(p*)))
20+

0 commit comments

Comments
 (0)