it.unich.scalafix.ComboAssignment.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of scalafix_3 Show documentation
Show all versions of scalafix_3 Show documentation
A Scala library for solving fixpoint equations
/**
* Copyright 2015, 2016, 2021 Gianluca Amato
*
* This file is part of ScalaFix. ScalaFix is free software: you can
* redistribute it and/or modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* ScalaFix is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of a MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* ScalaFix. If not, see .
*/
package it.unich.scalafix
import it.unich.scalafix.finite.UnknownOrdering
import it.unich.scalafix.utils.Domain
/**
* A ComboAssignment maps a subset of unknowns to a Combo. When `isDefinedAt(u)`
* is false for a given unknown `u`, the corresponding `apply(u)` should be a
* right combo.
*
* As it was the case for Combo, a ComboAssignent is also a blueprint for
* buildind equivalent ComboAssignments. Each ComboAssignmant has a copy method
* which should produce a functionally equivalent copy of `this`. The copy
* method should try to minimize object duplication.
*/
abstract class ComboAssignment[-U, V] extends PartialFunction[U, Combo[V]]:
/**
* Returns true if the assignment is empty, i.e., it is undefined for all
* program points.
*/
def isEmpty: Boolean
/** Returns true if all returned combos are idempotent. */
def combosAreIdempotent: Boolean
/** Returns true if all combos are right combos. */
def combosAreRight: Boolean
/** Returns true if all combos are immutable */
def combosAreImmutable: Boolean
/**
* Returns a copy of this combo assignment. An immutable combo assignment may
* just returns itself, but a mutable one should produce a copy of itself.
*/
def copy: ComboAssignment[U, V]
/**
* Restrict the domain of this combo assignment. The new domain is the
* intersection of the old domain and the set whose characteristic function is
* `domain`.
*/
def restrict[U1 <: U](domain: U1 => Boolean): ComboAssignment[U1, V] =
if isEmpty then this
else ComboAssignment.RestrictAssignment(this, domain)
/**
* Restrict the domain of this combo assignment. The new domain is the
* intersection of the old domain and the set of head nodes according to the
* provided graph ordering.
*/
def restrict[U1 <: U](ordering: UnknownOrdering[U1]): ComboAssignment[U1, V] =
restrict(ordering.isHead)
/**
* The `ComboAssignment` object defines factories for building combo
* assignments.
*/
object ComboAssignment:
private object EmptyAssigment extends ComboAssignment[Any, Any]:
def apply(u: Any): Combo.ImmutableCombo[Any] = Combo.right[Any]
def isDefinedAt(u: Any) = false
def isEmpty = true
def combosAreIdempotent = true
def combosAreRight = true
def combosAreImmutable = true
def copy: this.type = this
/**
* A constant combo assignment maps the same combo to all program points. Be
* careful because if combo has internal state, this is shared among all
* program points. For example, this is not suited for delayed widenings or
* narrowings.
*
* @tparam V
* the type of the values
* @param combo
* the combo to return for each program point
*/
private final class ConstantAssignment[V](combo: Combo[V]) extends ComboAssignment[Any, V]:
def isDefinedAt(u: Any) = true
def apply(u: Any): Combo[V] = combo
def isEmpty = false
def combosAreIdempotent: Boolean = combo.isIdempotent
def combosAreRight: Boolean = combo.isRight
def combosAreImmutable: Boolean = combo.isImmutable
def copy: ConstantAssignment[V] =
if combosAreImmutable then this else ConstantAssignment(combo.copy)
/**
* A combo assignment which returns a copy of the same combo for each program
* point.
*
* @tparam V
* the type of values
* @param combo
* the template for the combo we need to associate to program points
*/
private final class TemplateAssignment[V](combo: Combo[V]) extends ComboAssignment[Any, V]:
private val hash = scala.collection.mutable.Map.empty[Any, Combo[V]]
def isDefinedAt(u: Any) = true
def apply(u: Any): Combo[V] = hash.getOrElseUpdate(u, combo.copy)
def isEmpty = false
def combosAreIdempotent: Boolean = combo.isIdempotent
def combosAreImmutable: Boolean = combo.isImmutable
def combosAreRight: Boolean = combo.isRight
def copy: TemplateAssignment[V] = if combosAreImmutable then this else TemplateAssignment(combo)
/**
* A combo assignment which restrict the assignment combos to the set of
* program points which satisfy domain.
*
* @tparam U
* the type for program points of the combo assignment
* @tparam V
* the type of values
* @tparam U1
* the type of program points (subtype of U) to which we want to restrict
* the assignment
* @param combos
* the original combo assignment
* @param domain
* the set of points on which we want to use a combo
*/
private final class RestrictAssignment[U, V, U1 <: U](
combos: ComboAssignment[U, V],
domain: U1 => Boolean
) extends ComboAssignment[U1, V]:
def apply(u: U1): Combo[V] = if domain(u) then combos(u) else Combo.right[V]
def isDefinedAt(u: U1): Boolean = domain(u) && combos.isDefinedAt(u)
def isEmpty: Boolean = combos.isEmpty
def combosAreIdempotent: Boolean = combos.combosAreIdempotent
def combosAreImmutable: Boolean = combos.combosAreImmutable
def combosAreRight: Boolean = combos.combosAreRight
def copy: RestrictAssignment[U, V, U1] =
if combosAreImmutable then this else RestrictAssignment(combos.copy, domain)
private final class WarrowingAssignment[U, V: Domain](
widenings: ComboAssignment[U, V],
narrowings: ComboAssignment[U, V]
) extends ComboAssignment[U, V]:
def apply(u: U): Combo[V] = Combo.warrowing(widenings(u), narrowings(u))
def isDefinedAt(x: U): Boolean = widenings.isDefinedAt(x) || narrowings.isDefinedAt(x)
def isEmpty: Boolean = widenings.isEmpty && narrowings.isEmpty
def combosAreIdempotent = false
def combosAreImmutable: Boolean = widenings.combosAreImmutable && narrowings.combosAreImmutable
def combosAreRight: Boolean = widenings.combosAreRight && narrowings.combosAreRight
def copy: WarrowingAssignment[U, V] =
if combosAreImmutable then this else WarrowingAssignment(widenings.copy, narrowings.copy)
/**
* A combo assignment which returns the same combo for each program point. If
* combo is mutable, different copies are used for the different program
* points.
*
* @tparam V
* the type of values
* @param combo
* the template for combo to be returned at each program point
*/
def apply[V](combo: Combo[V]): ComboAssignment[Any, V] =
if combo.isImmutable then ConstantAssignment(combo)
else TemplateAssignment(combo)
/**
* A combo assignment which returns the immutable and idempotent combo
* corresponding to the map `f: (V,V) => V`, for each program point.
*/
def apply[V](f: (V, V) => V, isIdempotent: Boolean = true): ComboAssignment[Any, V] =
ConstantAssignment[V](Combo(f, isIdempotent))
/** A combo assignment which is undefined for each program point. */
def empty[V]: ComboAssignment[Any, V] = EmptyAssigment.asInstanceOf[ComboAssignment[Any, V]]
/**
* A warrowing assignment obtained by combining the given widenings and
* narrowings.
*
* Warrowing is defined in the paper:
*
* - Amato, G., Scozzari, F., Seidl, H., Apinis, K., Vojdani, V. Efficiently
* intertwining widening and narrowing Science of Computer Programming,
* 120, pp. 1-24. 2016
*
* While the [[Combo.warrowing]] method builds a single warrowing from a
* widening and a narrowing, this method allows to simultaneous build
* different warrowings for different program points.
*
* @tparam U
* the type of program points of the assignment
* @tparam V
* the type of values, should be endowed with a partial ordering
* @param widenings
* widening assignment over U and V
* @param narrowings
* narrowing assignment over U and V
*/
def warrowing[U, V: Domain](
widenings: ComboAssignment[U, V],
narrowings: ComboAssignment[U, V]
): ComboAssignment[U, V] =
if widenings.combosAreRight && narrowings.combosAreRight then ComboAssignment(Combo.right[V])
else WarrowingAssignment(widenings, narrowings)
© 2015 - 2025 Weber Informatics LLC | Privacy Policy