Skip to content

Commit

Permalink
Handle FunProto with committed TyperState
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
smarter committed Jun 15, 2021
1 parent 076ab0a commit 6b8169c
Show file tree
Hide file tree
Showing 4 changed files with 15 additions and 3 deletions.
4 changes: 4 additions & 0 deletions compiler/src/dotty/tools/dotc/core/Contexts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,10 @@ object Contexts {
final def withOwner(owner: Symbol): Context =
if (owner ne this.owner) fresh.setOwner(owner) else this

final def withUncommittedTyperState: Context =
val ts = typerState.uncommittedAncestor
if ts ne typerState then fresh.setTyperState(ts) else this

final def withProperty[T](key: Key[T], value: Option[T]): Context =
if (property(key) == value) this
else value match {
Expand Down
4 changes: 3 additions & 1 deletion compiler/src/dotty/tools/dotc/core/TyperState.scala
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,11 @@ class TyperState() {
*/
def commit()(using Context): Unit = {
Stats.record("typerState.commit")
assert(isCommittable)
assert(isCommittable, s"$this is not committable")
assert(!isCommitted, s"$this is already committed")
setCommittable(false)
val targetState = ctx.typerState
assert(!targetState.isCommitted, s"Attempt to commit $this into already committed $targetState")
if constraint ne targetState.constraint then
Stats.record("typerState.commit.new constraint")
constr.println(i"committing $this to $targetState, fromConstr = $constraint, toConstr = ${targetState.constraint}")
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -388,8 +388,8 @@ object ProtoTypes {
if state.typedArgs.size == args.length then state.typedArgs
else
val passedTyperState = ctx.typerState
inContext(protoCtx) {
val protoTyperState = protoCtx.typerState
inContext(protoCtx.withUncommittedTyperState) {
val protoTyperState = ctx.typerState
val oldConstraint = protoTyperState.constraint
val args1 = args.mapWithIndexConserve((arg, idx) =>
cacheTypedArg(arg, arg => typer.typed(norm(arg, idx)), force = false))
Expand Down
6 changes: 6 additions & 0 deletions tests/neg/i12736a.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
object Test {
def apply[S](r: Any): Any = r

def test =
(x: Int) => Test(doesntexist, x) // error
}

0 comments on commit 6b8169c

Please sign in to comment.