Shared: Refactor type inference and expose SatisfiesConstraint module

This commit is contained in:
Simon Friis Vindum
2025-06-20 13:44:34 +02:00
parent 93c891a987
commit a367388326

View File

@@ -866,6 +866,101 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
private import BaseTypes
signature module SatisfiesConstraintSig<HasTypeTreeSig TypeTree> {
/** Holds if it is relevant to know if `term` satisfies `constraint`. */
predicate relevantConstraint(TypeTree term, Type constraint);
}
module SatisfiesConstraint<HasTypeTreeSig TypeTree, SatisfiesConstraintSig<TypeTree> Input> {
import Input
private module IsInstantiationOfInput implements IsInstantiationOfInputSig<TypeTree> {
predicate potentialInstantiationOf(TypeTree tt, TypeAbstraction abs, TypeMention cond) {
exists(Type constraint, Type type |
type = tt.getTypeAt(TypePath::nil()) and
relevantConstraint(tt, constraint) and
rootTypesSatisfaction(type, constraint, abs, cond, _) and
// We only need to check instantiations where there are multiple candidates.
countConstraintImplementations(type, constraint) > 1
)
}
predicate relevantTypeMention(TypeMention constraint) {
rootTypesSatisfaction(_, _, _, constraint, _)
}
}
/** Holds if the type tree has the type `type` and should satisfy `constraint`. */
private predicate hasTypeConstraint(TypeTree term, Type type, Type constraint) {
type = term.getTypeAt(TypePath::nil()) and
relevantConstraint(term, constraint)
}
/**
* Holds if `tt` satisfies `constraint` through `abs`, `sub`, and `constraintMention`.
*/
pragma[nomagic]
private predicate hasConstraintMention(
TypeTree tt, TypeAbstraction abs, TypeMention sub, Type constraint,
TypeMention constraintMention
) {
exists(Type type | hasTypeConstraint(tt, type, constraint) |
not exists(countConstraintImplementations(type, constraint)) and
conditionSatisfiesConstraintTypeAt(abs, sub, constraintMention, _, _) and
resolveTypeMentionRoot(sub) = abs.getATypeParameter() and
constraint = resolveTypeMentionRoot(constraintMention)
or
countConstraintImplementations(type, constraint) > 0 and
rootTypesSatisfaction(type, constraint, abs, sub, constraintMention) and
// When there are multiple ways the type could implement the
// constraint we need to find the right implementation, which is the
// one where the type instantiates the precondition.
if countConstraintImplementations(type, constraint) > 1
then IsInstantiationOf<TypeTree, IsInstantiationOfInput>::isInstantiationOf(tt, abs, sub)
else any()
)
}
pragma[nomagic]
private predicate satisfiesConstraintTypeMention0(
TypeTree tt, Type constraint, TypeAbstraction abs, TypeMention sub, TypePath path, Type t
) {
exists(TypeMention constraintMention |
hasConstraintMention(tt, abs, sub, constraint, constraintMention) and
conditionSatisfiesConstraintTypeAt(abs, sub, constraintMention, path, t)
)
}
pragma[nomagic]
private predicate satisfiesConstraintTypeMention1(
TypeTree tt, Type constraint, TypePath path, TypePath pathToTypeParamInSub
) {
exists(TypeAbstraction abs, TypeMention sub, TypeParameter tp |
satisfiesConstraintTypeMention0(tt, constraint, abs, sub, path, tp) and
tp = abs.getATypeParameter() and
sub.resolveTypeAt(pathToTypeParamInSub) = tp
)
}
/**
* Holds if the type tree at `tt` satisfies the constraint `constraint`
* with the type `t` at `path`.
*/
pragma[nomagic]
predicate satisfiesConstraintTypeMention(TypeTree tt, Type constraint, TypePath path, Type t) {
exists(TypeAbstraction abs |
satisfiesConstraintTypeMention0(tt, constraint, abs, _, path, t) and
not t = abs.getATypeParameter()
)
or
exists(TypePath prefix0, TypePath pathToTypeParamInSub, TypePath suffix |
satisfiesConstraintTypeMention1(tt, constraint, prefix0, pathToTypeParamInSub) and
tt.getTypeAt(pathToTypeParamInSub.appendInverse(suffix)) = t and
path = prefix0.append(suffix)
)
}
}
/** Provides the input to `Matching`. */
signature module MatchingInputSig {
/**
@@ -1129,11 +1224,8 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
adjustedAccessType(a, apos, target, path.appendInverse(suffix), result)
}
/** Holds if this relevant access has the type `type` and should satisfy `constraint`. */
predicate hasTypeConstraint(Type type, Type constraint) {
adjustedAccessType(a, apos, target, path, type) and
relevantAccessConstraint(a, target, apos, path, constraint)
}
/** Holds if this relevant access should satisfy `constraint`. */
Type getConstraint() { relevantAccessConstraint(a, target, apos, path, result) }
string toString() {
result = a.toString() + ", " + apos.toString() + ", " + path.toString()
@@ -1142,94 +1234,18 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
Location getLocation() { result = a.getLocation() }
}
private module IsInstantiationOfInput implements IsInstantiationOfInputSig<RelevantAccess> {
predicate potentialInstantiationOf(
RelevantAccess at, TypeAbstraction abs, TypeMention cond
) {
exists(Type constraint, Type type |
at.hasTypeConstraint(type, constraint) and
rootTypesSatisfaction(type, constraint, abs, cond, _) and
// We only need to check instantiations where there are multiple candidates.
countConstraintImplementations(type, constraint) > 1
)
}
predicate relevantTypeMention(TypeMention constraint) {
rootTypesSatisfaction(_, _, _, constraint, _)
private module SatisfiesConstraintInput implements SatisfiesConstraintSig<RelevantAccess> {
predicate relevantConstraint(RelevantAccess at, Type constraint) {
constraint = at.getConstraint()
}
}
/**
* Holds if `at` satisfies `constraint` through `abs`, `sub`, and `constraintMention`.
*/
pragma[nomagic]
private predicate hasConstraintMention(
RelevantAccess at, TypeAbstraction abs, TypeMention sub, Type constraint,
TypeMention constraintMention
) {
exists(Type type | at.hasTypeConstraint(type, constraint) |
not exists(countConstraintImplementations(type, constraint)) and
conditionSatisfiesConstraintTypeAt(abs, sub, constraintMention, _, _) and
resolveTypeMentionRoot(sub) = abs.getATypeParameter() and
constraint = resolveTypeMentionRoot(constraintMention)
or
countConstraintImplementations(type, constraint) > 0 and
rootTypesSatisfaction(type, constraint, abs, sub, constraintMention) and
// When there are multiple ways the type could implement the
// constraint we need to find the right implementation, which is the
// one where the type instantiates the precondition.
if countConstraintImplementations(type, constraint) > 1
then
IsInstantiationOf<RelevantAccess, IsInstantiationOfInput>::isInstantiationOf(at, abs,
sub)
else any()
)
}
pragma[nomagic]
predicate satisfiesConstraintTypeMention0(
RelevantAccess at, Access a, AccessPosition apos, TypePath prefix, Type constraint,
TypeAbstraction abs, TypeMention sub, TypePath path, Type t
) {
exists(TypeMention constraintMention |
at = MkRelevantAccess(a, _, apos, prefix) and
hasConstraintMention(at, abs, sub, constraint, constraintMention) and
conditionSatisfiesConstraintTypeAt(abs, sub, constraintMention, path, t)
)
}
pragma[nomagic]
predicate satisfiesConstraintTypeMention1(
RelevantAccess at, Access a, AccessPosition apos, TypePath prefix, Type constraint,
TypePath path, TypePath pathToTypeParamInSub
) {
exists(TypeAbstraction abs, TypeMention sub, TypeParameter tp |
satisfiesConstraintTypeMention0(at, a, apos, prefix, constraint, abs, sub, path, tp) and
tp = abs.getATypeParameter() and
sub.resolveTypeAt(pathToTypeParamInSub) = tp
)
}
/**
* Holds if the type at `a`, `apos`, and `path` satisfies the constraint
* `constraint` with the type `t` at `path`.
*/
pragma[nomagic]
predicate satisfiesConstraintTypeMention(
Access a, AccessPosition apos, TypePath prefix, Type constraint, TypePath path, Type t
) {
exists(TypeAbstraction abs |
satisfiesConstraintTypeMention0(_, a, apos, prefix, constraint, abs, _, path, t) and
not t = abs.getATypeParameter()
)
or
exists(
RelevantAccess at, TypePath prefix0, TypePath pathToTypeParamInSub, TypePath suffix
|
satisfiesConstraintTypeMention1(at, a, apos, prefix, constraint, prefix0,
pathToTypeParamInSub) and
at.getTypeAt(pathToTypeParamInSub.appendInverse(suffix)) = t and
path = prefix0.append(suffix)
exists(RelevantAccess at | at = MkRelevantAccess(a, _, apos, prefix) |
SatisfiesConstraint<RelevantAccess, SatisfiesConstraintInput>::satisfiesConstraintTypeMention(at,
constraint, path, t)
)
}
}