Skip to content

Commit 1380104

Browse files
committed
Avoid crash by relaxing TyperState assertion
Flushing a reporter might force error messages (in particular when a StoreReporter is flushed into a non-StoreReporter), and the TyperState of the context captured in an error message might already be committed at this point. In ea6449f I tried to deal with this by flushing before committing but that's not sufficient since the reporter we're flushing might contain error messages from a more deeply nested TyperState. So this commit just relaxes the assertion (ideally we would also check that only TyperStates created in a committed TyperState can be committed in one, but keeping track of that would require an extra field in TyperState).
1 parent 6655587 commit 1380104

File tree

2 files changed

+33
-1
lines changed

2 files changed

+33
-1
lines changed

compiler/src/dotty/tools/dotc/core/TyperState.scala

+9-1
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,15 @@ class TyperState() {
143143
reporter.flush()
144144
setCommittable(false)
145145
val targetState = ctx.typerState
146-
assert(!targetState.isCommitted, s"Attempt to commit $this into already committed $targetState")
146+
147+
// Committing into an already committed TyperState usually doesn't make
148+
// sense since it means the constraints we're committing won't be propagated
149+
// further, but it can happen if the targetState gets captured in a reported
150+
// Message, because forcing that Message might involve creating and
151+
// committing new TyperStates into the captured one after its been committed.
152+
assert(!targetState.isCommitted || targetState.reporter.hasErrors || targetState.reporter.hasWarnings,
153+
s"Attempt to commit $this into already committed $targetState")
154+
147155
if constraint ne targetState.constraint then
148156
Stats.record("typerState.commit.new constraint")
149157
constr.println(i"committing $this to $targetState, fromConstr = $constraint, toConstr = ${targetState.constraint}")

tests/neg/i13101.scala

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
trait Vehicle
2+
trait Car extends Vehicle
3+
4+
trait Encoder[A]
5+
object Encoder {
6+
implicit val encodeVehicle: Encoder[Vehicle] = ???
7+
implicit val encodeCar: Encoder[Car] = ???
8+
}
9+
10+
trait Route
11+
trait Printer
12+
trait Marshaller[-A] // must be contravariant
13+
14+
object Test {
15+
implicit def marshaller[A: Encoder](implicit p: Printer = ???): Marshaller[A] = ???
16+
// the `Printer` implicit arg seems to be necessary, either with default value, or no implicit in scope
17+
18+
def foo[A](v: A)(implicit m: Marshaller[A]): Route = ???
19+
20+
val route: Route = identity {
21+
val f: (Car => Route) => Route = ??? // ok if s/Car/Vehicle/
22+
f(vehicle => foo(vehicle)) // error: ambiguous implicit
23+
}
24+
}

0 commit comments

Comments
 (0)