Work in Prograss. Added step2

This commit is contained in:
Andreas Stadelmeier 2024-03-24 00:04:37 +01:00
parent ae933b05c1
commit 9bea1b1eeb
6 changed files with 204 additions and 28 deletions

View File

@ -1,17 +1,29 @@
package unify.algorithm
import unify.model.{ExtendsRelations, LessDot}
import unify.model.{ConstraintSet, ExtendsRelations, LessDot}
import unify.model.*
import java.lang.reflect.WildcardType
class Rules(cs: ConstraintSet, deltaIn: Set[Wildcard], wildcardEnvironment: WildcardEnvironment, fc: ExtendsRelations):
class Rules(cs: ConstraintSet, fc: ExtendsRelations, tvFactory: TypeVariableFactory):
private def eraseCircleRule() = {
val alessb = cs.getALessDotBCons
val circle = alessb.map(cons => findCircle(cons.left.asInstanceOf[TypeVariable], alessb)).find(!_.isEmpty)
if (circle.isDefined) {
cs.removeAll(circle.get)
cs.addAll(circle.get.map(c => EqualsDot(c.left, c.right)))
}
}
private def crunch(refType: RefType): RefType = {
val newWcs = WildcardEnvironment(refType.wildcards.getWCBounds.filter(wcb => wcb.upper == wcb.lower))
val map: Map[Type, Type] = refType.wildcards.getWCBounds.filter(wcb => wcb.upper == wcb.lower).map(wcb => (Wildcard(wcb.name) -> wcb.upper)).toMap
RefType(newWcs, refType.name, refType.params.map(_.substitute(map)))
}
def applyRules(tvFactory: TypeVariableFactory, fc: ExtendsRelations): Unit = {
def applyRules() = {
while
eraseCircleRule()
cs.hasChanged()
do (cs.hasChanged())
cs.getEqualsDotCons.foreach(cons => { //Hint: cannot be executed in parallel!
cons match {
case EqualsDot(a, b) if a == b => cs.remove(cons) //Erase
@ -33,9 +45,9 @@ class Rules(cs: ConstraintSet, deltaIn: Set[Wildcard], wildcardEnvironment: Wild
case EqualsDot(WTypeVariable(a), right) => //Subst-WC
cs.remove(cons)
cs.substitute(cons.right, cons.left)
case EqualsDot(Wildcard(w), right: RefType) => tameRule(cons, cs)
case EqualsDot(Wildcard(w), right: Wildcard) => tameRule(cons, cs)
case EqualsDot(Wildcard(w), right: TypeVariable) => tameRule(cons, cs)
case EqualsDot(Wildcard(w), right: RefType) => tameRule(cons)
case EqualsDot(Wildcard(w), right: Wildcard) => tameRule(cons)
case EqualsDot(Wildcard(w), right: TypeVariable) => tameRule(cons)
case EqualsDot(left: RefType, right: RefType) => // Equals rule
if (left.params.size == right.params.size && left.name == right.name) {
cs.remove(cons)
@ -56,30 +68,33 @@ class Rules(cs: ConstraintSet, deltaIn: Set[Wildcard], wildcardEnvironment: Wild
case LessDot(a, b, _) if a == b => cs.remove(cons) //Erase
case LessDot(left: Wildcard, right: (RefType | TypeVariable | Wildcard), cc) => // Upper
cs.remove(cons)
cs.add(LessDot(wildcardEnvironment.getUpperBound(left), right, cc))
cs.add(LessDot(cs.wildcardEnv.getUpperBound(left), right, cc))
case LessDot(left: (RefType | Wildcard), right: Wildcard, cc) => // Lower
cs.remove(cons)
cs.add(LessDot(left, wildcardEnvironment.getLowerBound(right)))
case LessDot(left: TypeVariable, right: Wildcard, cc) if !deltaIn.contains(right) => // Lower
cs.add(LessDot(left, cs.wildcardEnv.getLowerBound(right)))
case LessDot(left: TypeVariable, right: Wildcard, cc) // if !deltaIn.contains(right)
=> // Lower
cs.remove(cons)
cs.add(LessDot(left, wildcardEnvironment.getLowerBound(right)))
cs.add(LessDot(left, cs.wildcardEnv.getLowerBound(right)))
case LessDot(left: BotType, right: Type, _) => cs.remove(cons) //Bot
case LessDot(left: (RefType | Wildcard), right: BotType, _) => // TODO: insolvable constraint set!
case LessDot(left: TypePlaceholder, right: BotType, _) =>
cs.remove(cons)
cs.add(EqualsDot(left, right))
/*
case LessDot(left: TypePlaceholder, right: TypePlaceholder, _) =>
val circle = findCircle(cons.left.asInstanceOf[TypeVariable], cs.getALessDotBCons)
if (!circle.isEmpty) {
cs.removeAll(circle)
cs.addAll(circle.map(c => EqualsDot(c.left, c.right)))
}
*/
case LessDot(left: TypePlaceholder, right: RefType, cc) =>
val alessdotc = cs.getALessDotCCons
//match rule:
alessdotc.find(ic => (ic != cons && cons.left.equals(cons.left))).map(ic => {
if (fc.isPossibleSupertype(cons.right.asInstanceOf[RefType].name, ic.right.asInstanceOf[RefType].name)) {
matchRule(cons, ic, cs, tvFactory)
matchRule(cons, ic)
} else {
//TODO: insolvable constraint set!
}
@ -87,6 +102,8 @@ class Rules(cs: ConstraintSet, deltaIn: Set[Wildcard], wildcardEnvironment: Wild
//adopt rule:
cs.getALessDotBCons.find(_.right == left).map(blessa => {
cs.getALessDotCCons.find(_.left == blessa.left).map(blessN => {
//TODO: Check if adopt rule got already applied
// different approach: Do the adopt and circle rule at the beginning of the algorithm. Then never again
cs.add(LessDot(blessN.left, cons.right))
})
})
@ -94,7 +111,7 @@ class Rules(cs: ConstraintSet, deltaIn: Set[Wildcard], wildcardEnvironment: Wild
cs.remove (cons)
cs.add (LessDot (left, crunch (right), cc) )
}
case LessDot(RefType(wc, n, params), right: RefType, cc) if right.fvs().diff(deltaIn).isEmpty | cc > 0 => // Capture und Prepare
case LessDot(RefType(wc, n, params), right: RefType, cc) if right.fvs().isEmpty | cc > 0 => // Capture und Prepare
cs.remove(cons)
cs.add(LessDot(RefType(emptyWCs(), n, params), right))
case LessDot(RefType(wc1, n1, p1), RefType(wc2, n2, p2), cc) =>
@ -126,7 +143,7 @@ class Rules(cs: ConstraintSet, deltaIn: Set[Wildcard], wildcardEnvironment: Wild
* @param c2 a <. D
* It's important that C < D
*/
private def matchRule(c1: LessDot, c2: LessDot, cs: ConstraintSet, tvFactory: TypeVariableFactory) = {
private def matchRule(c1: LessDot, c2: LessDot) = {
cs.remove(c1)
cs.remove(c2)
@ -173,18 +190,14 @@ class Rules(cs: ConstraintSet, deltaIn: Set[Wildcard], wildcardEnvironment: Wild
cs.add(EqualsDot(cons.right, cons.left))
}
def tameRule(cons: EqualsDot, cs: ConstraintSet) = {
def tameRule(cons: EqualsDot) = {
cs.remove(cons)
val left = cons.left.asInstanceOf[Wildcard]
val right = cons.right
cs.add(EqualsDot(wildcardEnvironment.getUpperBound(left), right))
cs.add(EqualsDot(wildcardEnvironment.getLowerBound(left), right))
cs.add(EqualsDot(cs.wildcardEnv.getUpperBound(left), right))
cs.add(EqualsDot(cs.wildcardEnv.getLowerBound(left), right))
}
def adaptRule(cons: LessDot, cs: ConstraintSet, fc: ExtendsRelations) = {
}
def substRule(c: EqualsDot, cs: ConstraintSet): Unit = {
def substRule(c: EqualsDot): Unit = {
cs.remove(c)
cs.substitute(c.right, c.left)
}

View File

@ -0,0 +1,127 @@
package unify.algorithm
import unify.model.{ConstraintSet, EqualsDot, ExtendsRelations, LessDot, RefType, TypeVariable, UnifySolution, Wildcard, WildcardBound, WildcardEnvironment, WildcardFactory, emptyWCs}
import java.util.concurrent.{CompletableFuture, ExecutorService, Future}
import scala.collection.mutable
class Unify {
/**
* The steps transforming the constraint set (including substitution)
* but without branching into multiple constraint sets
* @param cs
* @param fc
*/
def step1(cs: ConstraintSet, fc: ExtendsRelations, tvFactory: TypeVariableFactory) = {
val rules = new Rules(cs, fc, tvFactory)
while
rules.applyRules()
cs.hasChanged()
do ()
}
def step3(cs: ConstraintSet, fc: ExtendsRelations, tvFactory: TypeVariableFactory) = {
val ret: mutable.Set[ConstraintSet] = mutable.Set()
cs.getLessDotCons.find(cons => cons match {
case LessDot(RefType(w, n, p), TypeVariable(a), _) => true
case _ => false
}).map(cons => cons match {
case LessDot(RefType(w, n, p), TypeVariable(a), _) => {
//Same rule
//TODO
//General rule
val cs3: ConstraintSet = cs.copy()
val wcFactory = new WildcardFactory()
val freshWCs = p.map(_ => WildcardBound(wcFactory.freshName(), tvFactory.freshTV(), tvFactory.freshTV()))
val freshC = RefType(new WildcardEnvironment(freshWCs.toSet), n, freshWCs.map(wcb => Wildcard(wcb.name)))
cs3.add(EqualsDot(cons.right, freshC))
//cs3.addAll(freshWCs.map(w => LessDot(cs3.getLowerBound(w), cs3.getUpperBound(w))))
//Set upper bound to Object: //TODO: take the real upper bound (therefore ExtendsRelations has to be changed)
cs3.addAll(freshWCs.map(w => LessDot(w.upper, RefType(emptyWCs(), "Object", List.empty))))
ret.add(cs3)
//Super rule
//Object is the exception, which does not have a supertype
if(!cons.left.asInstanceOf[RefType].name.equals("Object")){
val cs4: ConstraintSet = cs.copy()
cs4.remove(cons)
val cType = cons.left.asInstanceOf[RefType]
val paramMap = fc.supertype(cType.name)._1.params.zip(cType.params).toMap
val superType = fc.supertype(cType.name)._2
val newSuperType = RefType(cType.wildcards, superType.name, superType.params.map(p => p.substitute(paramMap)))
cs4.add(LessDot(newSuperType, cons.right))
ret.add(cs4)
}
}
case _ => {}
})
cs.getALessDotCCons.map(cons => cons match {
case LessDot(TypeVariable(a), RefType(wc, n, ps), _) => {
cs.getALessDotBCons.find(c => c.left.equals(TypeVariable(a))).map(_.right).map(b => {
//Lower rule:
val csLower: ConstraintSet = cs.copy()
csLower.remove(LessDot(TypeVariable(a), RefType(wc, n, ps)))
csLower.add(LessDot(b, RefType(wc, n, ps)))
ret.add(csLower)
//Raise rule:
val csRaise: ConstraintSet = cs.copy()
csRaise.remove(LessDot(TypeVariable(a), b))
csRaise.add(LessDot(RefType(wc, n, ps), b))
ret.add(csRaise)
})
}
case _ => {}
})
/*
cs.getALessDotCCons().filter(cons => !cs.fv(cons.right).isEmpty).map(cons => {
//Force
val csForce: ConstraintSet = cs.copy()
val fvs = cs.fv(cons.right)
if(fvs.find(t => !t.isInstanceOf[Wildcard]).isEmpty){
val freeWildcards = fvs.map(_.asInstanceOf[Wildcard])
val oldRight = cons.right.asInstanceOf[RefType]
val newCons = freeWildcards.map(wc => LessDot(cs.getUpperBound(wc), cs.getLowerBound(wc))) ++ freeWildcards.map(wc => LessDot(cs.getLowerBound(wc), cs.getUpperBound(wc)))
csForce.remove(cons)
csForce.add(LessDot(cons.left, RefType(oldRight.wildcards ++ freeWildcards, oldRight.name, oldRight.params)))
csForce.addAll(newCons)
ret.add(csForce)
}
})
*/
ret.toSet
}
/**
* Returns a constraintset in solved form on success
* @param cs
* @return
*/
def step4(cs: ConstraintSet): Option[UnifySolution] = {
//Clean up step
//Ground rule
val alessT = cs.getALessDotCCons.filter(c => cs.isOnlyLowerBound(c.left.asInstanceOf[TypeVariable]))
if(alessT.size > 0) {
alessT.map(cons => {
cs.groundRule(cons)
})
}
//SubElim rule
cs.getALessDotBCons.map(cons => {
cs.remove(cons)
cs.substitute(cons.left, cons.right)
cs.addUnifier(EqualsDot(cons.right, cons.left))
})
if(cs.isSolvedForm){
cs.solvedForm()
}else{
None
}
}
}

View File

@ -3,14 +3,25 @@ package unify.model
class ConstraintSet( private var unifier: Set[EqualsDot] = Set(),
private var lessdot: Set[LessDot] = Set(),
private var equalsdot: Set[EqualsDot] = Set(),
private var bounds: WildcardEnvironment,
private var bounds: WildcardEnvironment = emptyWCs(),
private var processed: Set[(TypePlaceholder, TypePlaceholder)] = Set(),
private var changed: Boolean = false) {
def notProcessed(a: TypePlaceholder, b: TypePlaceholder): Boolean = !processed.contains((a,b))
def setProcessedByAdopt(a: TypePlaceholder, b: TypePlaceholder): Unit = {
processed = processed + ((a, b))
}
def wildcardEnv = bounds
/*
The Subtype-Constraints flagged as capture constraints are saved in lessdotCC.
lessdotCC is a list. there can be multiple T <c S constraints. Removing one leaves the other one in the set.
This is intentional
*/
def hasChanged(): Boolean = {
val ret = changed
changed = false
ret
}
def getEqualsDotCons = equalsdot
@ -69,5 +80,16 @@ class ConstraintSet( private var unifier: Set[EqualsDot] = Set(),
EqualsDot(substitute(c.left), substitute(c.right))
})
this.bounds = WildcardEnvironment(this.bounds.map(substituteWCB))
changed = true
}
def copy(): ConstraintSet = {
val ret = ConstraintSet()
ret.processed = processed
ret.lessdot = lessdot
ret.equalsdot = equalsdot
ret.unifier = unifier
ret.bounds = new WildcardEnvironment(bounds.getWCBounds)
ret
}
}

View File

@ -6,8 +6,9 @@ class ExtendsRelations(val extendsRelations : Set[(RefType, RefType)]):
def isPossibleSupertype(of: String, superType: String): Boolean = {
if (of.equals(superType)) return true
extendsRelations.map(p => {
//TODO
})
false
if(extendsRelations.contains(of)){
isPossibleSupertype(superType(of), superType)
}else{
false
}
}

View File

@ -0,0 +1,10 @@
package unify.model
class UnifySolution(delta: WildcardEnvironment, sigma: Map[TypeVariable, Type]) {
def getDelta() = delta
override def toString: String =
"Δ = " + delta.map(wc => wc._1.name + ":["+wc._2._1.toString + ".."+wc._2._2.toString + "]").mkString("{",", ", "}") +
", σ = " + sigma.toString()
def getSigma = sigma
}

View File

@ -1,10 +1,13 @@
package unify.model
import unify.algorithm.TypeVariableFactory
case class WildcardBound(name: String, upper: Type, lower: Type){}
class WildcardEnvironment(wcBounds: Set[WildcardBound]) {
def getWCBounds = bounds.map(b => WildcardBound(b._1, b._2._1, b._2._2)).toSet
val bounds: Map[String, (Type, Type)] = wcBounds.map(b => (b.name -> (b.upper, b.lower))).toMap
def getWCBounds = bounds.map(b => WildcardBound(b._1, b._2._1, b._2._2)).toSet
def isEmpty = wcBounds.isEmpty
def getUpperBound(wc: Wildcard): Type = bounds(wc.name)._1