Skip to content

Commit 6b8169c

Browse files
committed
Handle FunProto with committed TyperState
The TyperState of `FunProto#protoCtx` might already be committed by the time we call `FunProto#typedArgs` (this can happen for example with the nested TyperState in a `tryEither`), in that case we can trigger assertion errors if we touch that TyperState again. Fixed by using the nearest uncommited ancestor of the capture TyperState instead.
1 parent 076ab0a commit 6b8169c

File tree

4 files changed

+15
-3
lines changed

4 files changed

+15
-3
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,10 @@ object Contexts {
526526
final def withOwner(owner: Symbol): Context =
527527
if (owner ne this.owner) fresh.setOwner(owner) else this
528528

529+
final def withUncommittedTyperState: Context =
530+
val ts = typerState.uncommittedAncestor
531+
if ts ne typerState then fresh.setTyperState(ts) else this
532+
529533
final def withProperty[T](key: Key[T], value: Option[T]): Context =
530534
if (property(key) == value) this
531535
else value match {

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,11 @@ class TyperState() {
138138
*/
139139
def commit()(using Context): Unit = {
140140
Stats.record("typerState.commit")
141-
assert(isCommittable)
141+
assert(isCommittable, s"$this is not committable")
142+
assert(!isCommitted, s"$this is already committed")
142143
setCommittable(false)
143144
val targetState = ctx.typerState
145+
assert(!targetState.isCommitted, s"Attempt to commit $this into already committed $targetState")
144146
if constraint ne targetState.constraint then
145147
Stats.record("typerState.commit.new constraint")
146148
constr.println(i"committing $this to $targetState, fromConstr = $constraint, toConstr = ${targetState.constraint}")

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -388,8 +388,8 @@ object ProtoTypes {
388388
if state.typedArgs.size == args.length then state.typedArgs
389389
else
390390
val passedTyperState = ctx.typerState
391-
inContext(protoCtx) {
392-
val protoTyperState = protoCtx.typerState
391+
inContext(protoCtx.withUncommittedTyperState) {
392+
val protoTyperState = ctx.typerState
393393
val oldConstraint = protoTyperState.constraint
394394
val args1 = args.mapWithIndexConserve((arg, idx) =>
395395
cacheTypedArg(arg, arg => typer.typed(norm(arg, idx)), force = false))

tests/neg/i12736a.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
object Test {
2+
def apply[S](r: Any): Any = r
3+
4+
def test =
5+
(x: Int) => Test(doesntexist, x) // error
6+
}

0 commit comments

Comments
 (0)