Use rule match identity as feedback key for TypesIndex instead of rule unique tag

It seems to reflect the exact information needed: there's
one-to-one correspondence between feedback and its match.
While using rule unique tag as feedback key in TypesIndex
relied on several assumptions.
Also there's less use of MatchJournal information with this.
Previously parent principal match was passed to FeedbackConsumer.
This commit is contained in:
Grigorii Kirgizov 2020-07-20 19:00:48 +03:00
parent 53a5d2f489
commit f2d1f089ad
8 changed files with 23 additions and 22 deletions

View File

@ -33,12 +33,12 @@ class CompositeFeedback private constructor(private val elements: List<Feedback>
this.severity = maxSeverity(elements)
}
override fun handle(currentRuleMatch: RuleMatch, parentPrincipalMatch: RuleMatch, supervisor: Supervisor): Boolean {
override fun handle(currentRuleMatch: RuleMatch, feedbackKey: Any, supervisor: Supervisor): Boolean {
var unhandled = 0
for (feedback in elements) {
if (!feedback.alreadyHandled()) {
unhandled += 1
if (supervisor.handleFeedback(currentRuleMatch, parentPrincipalMatch, feedback)) {
if (supervisor.handleFeedback(currentRuleMatch, feedbackKey, feedback)) {
feedback.setHandled()
unhandled -= 1
}

View File

@ -40,8 +40,8 @@ abstract class Feedback : EvaluationFeedback() {
/**
* Returns true if the feedback has been handled.
*/
open fun handle(currentRuleMatch: RuleMatch, parentPrincipalMatch: RuleMatch, supervisor: Supervisor): Boolean {
if (!alreadyHandled() && supervisor.handleFeedback(currentRuleMatch, parentPrincipalMatch, this)) {
open fun handle(currentRuleMatch: RuleMatch, feedbackKey: Any, supervisor: Supervisor): Boolean {
if (!alreadyHandled() && supervisor.handleFeedback(currentRuleMatch, feedbackKey, this)) {
setHandled()
}
return alreadyHandled()
@ -54,3 +54,7 @@ abstract class Feedback : EvaluationFeedback() {
}
}
typealias FeedbackKeySet = Set<Any>
internal val RuleMatch.feedbackKey: Any get() = System.identityHashCode(this)

View File

@ -51,7 +51,7 @@ internal class ConstraintsProcessing(private var dispatchingFront: Dispatcher.Di
private val activationQueue: ContinuedActivationQueue = ContinuedActivationQueue(journalIndex, RuleOrdering(ruleIndex))
private val invalidatedRulesTags: MutableSet<Any> = mutableSetOf<Any>()
private val invalidFeedbackKeys: MutableSet<Any> = mutableSetOf<Any>()
private data class MatchCandidate(val rule: Rule, val occChunk: MatchJournal.OccChunk)
@ -116,7 +116,7 @@ internal class ConstraintsProcessing(private var dispatchingFront: Dispatcher.Di
val validOccs: Sequence<Occurrence>
if (chunk is MatchJournal.MatchChunk) {
trace.invalidate(chunk.match)
invalidatedRulesTags.add(chunk.ruleUniqueTag)
invalidFeedbackKeys.add(chunk.match.feedbackKey)
dispatchingFront = dispatchingFront.forget(chunk.match as RuleMatchEx)
// Valid head occurrences could match more rules
@ -195,7 +195,7 @@ internal class ConstraintsProcessing(private var dispatchingFront: Dispatcher.Di
* and returns [SessionToken] with session results.
*/
fun endSession(): SessionToken {
invalidatedRulesTags.clear()
invalidFeedbackKeys.clear()
val histView = view()
resetStore() // clear observers
val rules = ArrayList<Rule>().apply { ruleIndex.forEach { add(it) } }
@ -206,7 +206,7 @@ internal class ConstraintsProcessing(private var dispatchingFront: Dispatcher.Di
return SessionTokenImpl(histView, rules, principalState, logicalState.clear())
}
fun invalidatedRules(): Set<Any> = HashSet<Any>(invalidatedRulesTags)
fun invalidatedFeedback(): FeedbackKeySet = HashSet<Any>(invalidFeedbackKeys)
/**
* Called to update the state with the currently active constraint occurrence.

View File

@ -54,7 +54,7 @@ internal class ControllerImpl (
return storeView()
}
fun incrLaunch(constraint: Constraint, rulesDiff: RulesDiff): Pair<FeedbackStatus, Set<Any>> {
fun incrLaunch(constraint: Constraint, rulesDiff: RulesDiff): Pair<FeedbackStatus, FeedbackKeySet> {
if (rulesDiff.removed.isNotEmpty()) {
profiler.profile("invalidation") {
@ -73,7 +73,7 @@ internal class ControllerImpl (
processing.launchQueue(this)
}
return status to processing.invalidatedRules()
return status to processing.invalidatedFeedback()
}
fun activate(constraint: Constraint) : FeedbackStatus {
@ -180,7 +180,7 @@ internal class ControllerImpl (
if (itemOk) {
context.withStatus { status ->
if (status.feedback?.alreadyHandled() == false) {
status.feedback.handle(match, newParent.match, supervisor)
status.feedback.handle(match, newParent.match.feedbackKey, supervisor)
}
}
@ -201,7 +201,7 @@ internal class ControllerImpl (
// if failure can be handled here then recover
} else if (status.feedback?.alreadyHandled() == false
&& status.failure.handle(match, newParent.match, supervisor)) {
&& status.failure.handle(match, newParent.match.feedbackKey, supervisor)) {
status.recover()
@ -280,7 +280,6 @@ internal class ControllerImpl (
it.first.patternPredicates(it.second.arguments())
}.toList()
inner private class Context(inStatus: FeedbackStatus,
val checking: Boolean,
val logicalContext: LogicalContext,

View File

@ -46,7 +46,7 @@ internal class EvaluationSessionImpl private constructor (
val newToken: SessionToken
val status: FeedbackStatus
val invalidatedTags: Set<Any>
val invalidFeedbackKeys: Set<Any>
val ruleIndex = RuleIndex(program.rulesLists())
@ -63,7 +63,7 @@ internal class EvaluationSessionImpl private constructor (
status = controller.activate(main)
newToken = processing.endSession()
invalidatedTags = emptySet()
invalidFeedbackKeys = emptySet()
} else {
val tkn = token as SessionTokenImpl
@ -80,14 +80,14 @@ internal class EvaluationSessionImpl private constructor (
val status2tags = controller.incrLaunch(main, rulesDiff)
newToken = processing.endSession()
status = status2tags.first
invalidatedTags = status2tags.second
invalidFeedbackKeys = status2tags.second
}
return object : EvaluationResult {
override fun token(): SessionToken = newToken
override fun storeView(): StoreView = newToken.journalView.storeView
override fun feedback(): EvaluationFeedback? = if (status is FAILED) status.failure else null
override fun invalidatedTags(): Collection<Any> = invalidatedTags
override fun invalidFeedbackKeys(): Collection<Any> = invalidFeedbackKeys
}
}

View File

@ -29,6 +29,6 @@ public interface EvaluationResult {
public EvaluationFeedback feedback();
public Collection<Object> invalidatedTags();
public Collection<Object> invalidFeedbackKeys();
}

View File

@ -34,7 +34,7 @@ public interface Supervisor {
* Override this method in order to "handle" the feedback.
* Returns true if the method has handled (consumed) the feedback.
*/
default boolean handleFeedback(RuleMatch ruleMatch, RuleMatch parentPrincipalMatch, EvaluationFeedback feedback) {
default boolean handleFeedback(RuleMatch ruleMatch, Object feedbackKey, EvaluationFeedback feedback) {
return false;
}

View File

@ -1,12 +1,10 @@
import jetbrains.mps.logic.reactor.core.*
import jetbrains.mps.logic.reactor.core.internal.LogicalState
import jetbrains.mps.logic.reactor.core.internal.createController
import jetbrains.mps.logic.reactor.core.internal.logical
import jetbrains.mps.logic.reactor.evaluation.*
import jetbrains.mps.logic.reactor.logical.Logical
import jetbrains.mps.logic.reactor.program.ConstraintSymbol
import jetbrains.mps.logic.reactor.program.Program
import jetbrains.mps.logic.reactor.program.Rule
import jetbrains.mps.unification.Term
import jetbrains.mps.unification.test.MockTerm.*
import org.junit.After
@ -70,7 +68,7 @@ class TestController {
vararg occurrences: ConstraintOccurrence): Controller {
val program = MockProgram("test", rulesLists, registry = MockConstraintRegistry())
val supervisor = object : MockSupervisor() {
override fun handleFeedback(ruleMatch: RuleMatch, parentPrincipalMatch: RuleMatch, feedback: EvaluationFeedback): Boolean =
override fun handleFeedback(ruleMatch: RuleMatch, feedbackKey: Any, feedback: EvaluationFeedback): Boolean =
feedbackHandler(ruleMatch, feedback)
}
MockSession.init(program, supervisor)