From d1931aae1b87fbe87e429e6a08b0cb2a07ccb8f6 Mon Sep 17 00:00:00 2001 From: Eugene Flesselle Date: Thu, 18 Apr 2024 02:03:54 +0200 Subject: [PATCH 1/5] Cache `myReduced = NoType` if match type reduction overflowed --- compiler/src/dotty/tools/dotc/core/Types.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index e5cdd3b0613d..5a4618edb3a3 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -5173,17 +5173,17 @@ object Types extends TypeUtils { trace(i"reduce match type $this $hashCode", matchTypes, show = true): withMode(Mode.Type): setReductionContext() - def matchCases(cmp: MatchReducer): Type = + TypeComparer.reduceMatchWith: cmp => val saved = ctx.typerState.snapshot() try - cmp.matchCases(scrutinee.normalized, cases.map(MatchTypeCaseSpec.analyze(_))) + cmp.matchCases(scrutinee.normalized, cases.map(MatchTypeCaseSpec.analyze)) catch case ex: Throwable => + myReduced = NoType handleRecursive("reduce type ", i"$scrutinee match ...", ex) finally ctx.typerState.resetTo(saved) // this drops caseLambdas in constraint and undoes any typevar // instantiations during matchtype reduction - TypeComparer.reduceMatchWith(matchCases) //else println(i"no change for $this $hashCode / $myReduced") myReduced.nn From d7b69a36793d86eb831e36b5dfd87ff1eff4e543 Mon Sep 17 00:00:00 2001 From: Eugene Flesselle Date: Thu, 18 Apr 2024 02:06:26 +0200 Subject: [PATCH 2/5] Only set match type reduction context if not up to date --- compiler/src/dotty/tools/dotc/core/Types.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 5a4618edb3a3..416dcef733ee 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -5124,6 +5124,7 @@ object Types extends TypeUtils { } def isUpToDate: Boolean = + (reductionContext ne null) && reductionContext.keysIterator.forall: tp => reductionContext(tp) `eq` contextInfo(tp) @@ -5169,10 +5170,10 @@ object Types extends TypeUtils { then record("MatchType.reduce computed") if (myReduced != null) record("MatchType.reduce cache miss") + if !isUpToDate then setReductionContext() myReduced = trace(i"reduce match type $this $hashCode", matchTypes, show = true): withMode(Mode.Type): - setReductionContext() TypeComparer.reduceMatchWith: cmp => val saved = ctx.typerState.snapshot() try From 4a4ad17804865831855c988c86e4705f9daaee52 Mon Sep 17 00:00:00 2001 From: Eugene Flesselle Date: Thu, 18 Apr 2024 02:15:13 +0200 Subject: [PATCH 3/5] Restructure `MatchType#reduced` try catch --- .../src/dotty/tools/dotc/core/Types.scala | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 416dcef733ee..2646b8eb76c3 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -5171,20 +5171,19 @@ object Types extends TypeUtils { record("MatchType.reduce computed") if (myReduced != null) record("MatchType.reduce cache miss") if !isUpToDate then setReductionContext() - myReduced = - trace(i"reduce match type $this $hashCode", matchTypes, show = true): + val saved = ctx.typerState.snapshot() + try + myReduced = trace(i"reduce match type $this $hashCode", matchTypes, show = true): withMode(Mode.Type): TypeComparer.reduceMatchWith: cmp => - val saved = ctx.typerState.snapshot() - try - cmp.matchCases(scrutinee.normalized, cases.map(MatchTypeCaseSpec.analyze)) - catch case ex: Throwable => - myReduced = NoType - handleRecursive("reduce type ", i"$scrutinee match ...", ex) - finally - ctx.typerState.resetTo(saved) - // this drops caseLambdas in constraint and undoes any typevar - // instantiations during matchtype reduction + cmp.matchCases(scrutinee.normalized, cases.map(MatchTypeCaseSpec.analyze)) + catch case ex: Throwable => + myReduced = NoType + handleRecursive("reduce type ", i"$scrutinee match ...", ex) + finally + ctx.typerState.resetTo(saved) + // this drops caseLambdas in constraint and undoes any typevar + // instantiations during matchtype reduction //else println(i"no change for $this $hashCode / $myReduced") myReduced.nn From a5195f83571aba62be6eae82ce284fa92028ffd3 Mon Sep 17 00:00:00 2001 From: Eugene Flesselle Date: Thu, 18 Apr 2024 12:01:52 +0200 Subject: [PATCH 4/5] Avoid recomputing `isUpToDate` --- compiler/src/dotty/tools/dotc/core/Types.scala | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 2646b8eb76c3..a198a1c3a2c5 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -5123,11 +5123,6 @@ object Types extends TypeUtils { tp.underlying } - def isUpToDate: Boolean = - (reductionContext ne null) && - reductionContext.keysIterator.forall: tp => - reductionContext(tp) `eq` contextInfo(tp) - def setReductionContext(): Unit = new TypeTraverser: var footprint: Set[Type] = Set() @@ -5162,15 +5157,22 @@ object Types extends TypeUtils { matchTypes.println(i"footprint for $thisMatchType $hashCode: ${footprint.toList.map(x => (x, contextInfo(x)))}%, %") end setReductionContext + def changedReductionContext(): Boolean = + val isUpToDate = + (reductionContext ne null) && + reductionContext.keysIterator.forall: tp => + reductionContext(tp) `eq` contextInfo(tp) + if !isUpToDate then setReductionContext() + !isUpToDate + record("MatchType.reduce called") if !Config.cacheMatchReduced || myReduced == null - || !isUpToDate + || changedReductionContext() || MatchTypeTrace.isRecording then record("MatchType.reduce computed") if (myReduced != null) record("MatchType.reduce cache miss") - if !isUpToDate then setReductionContext() val saved = ctx.typerState.snapshot() try myReduced = trace(i"reduce match type $this $hashCode", matchTypes, show = true): From 66f7f9599ff8ce592e9a6e9e60432ae410e95d54 Mon Sep 17 00:00:00 2001 From: Eugene Flesselle Date: Thu, 18 Apr 2024 13:39:30 +0200 Subject: [PATCH 5/5] Use explicit nulls for reductionContext --- compiler/src/dotty/tools/dotc/core/Types.scala | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index a198a1c3a2c5..9080d5933693 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -5098,7 +5098,7 @@ object Types extends TypeUtils { def underlying(using Context): Type = bound private var myReduced: Type | Null = null - private var reductionContext: util.MutableMap[Type, Type] = uninitialized + private var reductionContext: util.MutableMap[Type, Type] | Null = null override def tryNormalize(using Context): Type = try @@ -5153,15 +5153,12 @@ object Types extends TypeUtils { cases.foreach(traverse) reductionContext = util.HashMap() for tp <- footprint do - reductionContext(tp) = contextInfo(tp) + reductionContext.nn(tp) = contextInfo(tp) matchTypes.println(i"footprint for $thisMatchType $hashCode: ${footprint.toList.map(x => (x, contextInfo(x)))}%, %") end setReductionContext def changedReductionContext(): Boolean = - val isUpToDate = - (reductionContext ne null) && - reductionContext.keysIterator.forall: tp => - reductionContext(tp) `eq` contextInfo(tp) + val isUpToDate = reductionContext != null && reductionContext.nn.iterator.forall(contextInfo(_) `eq` _) if !isUpToDate then setReductionContext() !isUpToDate @@ -5193,10 +5190,9 @@ object Types extends TypeUtils { /** True if the reduction uses GADT constraints. */ def reducesUsingGadt(using Context): Boolean = - (reductionContext ne null) && reductionContext.keysIterator.exists { - case tp: TypeRef => reductionContext(tp).exists - case _ => false - } + reductionContext != null && reductionContext.nn.iterator.exists: + case (tp: TypeRef, tpCtx) => tpCtx.exists + case _ => false override def computeHash(bs: Binders): Int = doHash(bs, scrutinee, bound :: cases)