use of org.eclipse.n4js.ts.types.InferenceVariable in project n4js by eclipse.
the class BoundSet method combineInvVar.
/**
* Case: first bound is an equality, while the second isn't: `α = S` and `β Φ T` with Φ either {@code <:} or
* {@code :>}.
*/
private TypeConstraint combineInvVar(TypeBound boundS, TypeBound boundT) {
final InferenceVariable alpha = boundS.left;
final InferenceVariable beta = boundT.left;
final TypeRef S = boundS.right;
final TypeRef T = boundT.right;
final Variance Phi = boundT.variance;
if (alpha == beta) {
// (1) `α = S` and `α Φ T` implies `S Φ T`
return new TypeConstraint(S, T, Phi);
}
// both bounds have different inference variables, i.e. α != β
if (alpha == T.getDeclaredType()) {
// (2) `α = S` and `β Φ α` implies `β Φ S`
return new TypeConstraint(typeRef(beta), S, Phi);
}
if (TypeUtils.isInferenceVariable(S)) {
// first bound is of the form `α = γ` (with γ being another inference variable)
final InferenceVariable gamma = (InferenceVariable) S.getDeclaredType();
if (gamma == beta) {
// (3) `α = β` and `β Φ T` implies `α Φ T`
return new TypeConstraint(typeRef(alpha), T, Phi);
}
if (gamma == T.getDeclaredType()) {
// (4) `α = γ` and `β Φ γ` implies `β Φ α`
return new TypeConstraint(typeRef(beta), typeRef(alpha), Phi);
}
}
// so, S is not an inference variable
if (TypeUtils.isProper(S) && TypeUtils.getReferencedTypeVars(T).contains(alpha)) {
// (5) `α = S` (where S is proper) and `β Φ T` implies `β Φ T[α:=U]`
// returns T[α:=U]
final TypeRef T_subst = substituteInferenceVariable(T, alpha, S);
// performance tweak: avoid unnecessary growth of bounds
removeBound(boundT);
return new TypeConstraint(typeRef(beta), T_subst, Phi);
}
return null;
}
use of org.eclipse.n4js.ts.types.InferenceVariable in project n4js by eclipse.
the class BoundSet method combineContraCo.
/**
* Case: `α :> S` and `β <: T`.
*/
private TypeConstraint combineContraCo(TypeBound boundS, TypeBound boundT) {
final InferenceVariable alpha = boundS.left;
final InferenceVariable beta = boundT.left;
final TypeRef S = boundS.right;
final TypeRef T = boundT.right;
if (alpha == beta) {
// α :> S and α <: T implies S <: T
return new TypeConstraint(S, T, CO);
}
// so, α and β are different
if (TypeUtils.isInferenceVariable(S)) {
final InferenceVariable gamma = (InferenceVariable) S.getDeclaredType();
if (gamma == T.getDeclaredType()) {
// α :> γ and β <: γ implies α :> β
return new TypeConstraint(typeRef(alpha), typeRef(beta), CONTRA);
}
}
return null;
}
use of org.eclipse.n4js.ts.types.InferenceVariable in project n4js by eclipse.
the class InferenceContext method getSmallestVariableSet.
/**
* Given a set <code>infVars</code> of inference variables of the receiving inference context, this method returns
* the smallest, non-empty set S such that
* <ul>
* <li>all α ∈ S are uninstantiated inference variables of the receiving inference context,
* <li>one of the elements in S is also in <code>infVars</code>: ∃ α ∈ S: α ∈ <code>infVars</code>,
* <li>if an α ∈ S depends on the resolution of another variable β, then either β is instantiated or β ∈
* S,</li>
* <li>there exists no non-empty proper subset of S with this property.</li>
* </ul>
* Returns <code>null</code> if no such set exists, e.g. because <code>infVars</code> was empty or did not contain
* any uninstantiated inference variables.
* <p>
* The returned set, if non-null, is guaranteed to be non-empty.
*/
private Set<InferenceVariable> getSmallestVariableSet(Set<InferenceVariable> infVars) {
Set<InferenceVariable> result = null;
Set<InferenceVariable> deferred = null;
int min = Integer.MAX_VALUE;
for (InferenceVariable currentVariable : infVars) {
if (!currentBounds.isInstantiated(currentVariable)) {
// With the following code, we defer processing of β until α has been instantiated to A.
if (currentBounds.isUnbounded(currentVariable)) {
final boolean gotAtLeastOneDependantIV = infVars.stream().anyMatch(iv -> currentBounds.dependsOnResolutionOf(iv, currentVariable));
if (gotAtLeastOneDependantIV) {
final boolean defer = infVars.stream().filter(iv -> currentBounds.dependsOnResolutionOf(iv, currentVariable)).allMatch(iv -> {
final List<TypeBound> bs = currentBounds.getBounds(iv).stream().filter(b -> !(b.left == iv && b.right.getDeclaredType() == currentVariable)).collect(Collectors.toList());
return !bs.isEmpty() && bs.stream().allMatch(b -> TypeUtils.isProper(b.right));
});
if (defer) {
if (deferred == null) {
deferred = new HashSet<>();
}
deferred.add(currentVariable);
continue;
}
}
}
final Set<InferenceVariable> set = new LinkedHashSet<>();
if (addDependencies(currentVariable, min, set)) {
final int curr = set.size();
if (curr == 1) {
// 'set' contains only currentVariable -> no need to remove deferred variables
return set;
}
if (curr < min) {
result = set;
min = curr;
}
}
}
}
if ((result == null) || result.isEmpty()) {
return null;
}
// deferred variables may have been added via #addDependencies() above, so remove them
if (deferred != null) {
// note: because deferred variables can only end up in 'result' via #addDependencies(), we can safely
// remove all deferred variables and be sure that 'result' won't be empty afterwards
result.removeAll(deferred);
}
return result;
}
use of org.eclipse.n4js.ts.types.InferenceVariable in project n4js by eclipse.
the class InferenceContext method resolve.
// ###############################################################################################################
// RESOLUTION
/**
* Performs resolution of all inference variables of the receiving inference context. This might trigger further
* reduction and incorporation steps.
* <p>
* If a solution is found, <code>true</code> is returned and {@link #currentBounds} will contain instantiations for
* all inference variables. Otherwise, <code>false</code> is returned and {@link #currentBounds} will be in an
* undefined state.
*/
private boolean resolve() {
Set<InferenceVariable> currVariableSet;
while ((currVariableSet = getSmallestVariableSet(inferenceVariables)) != null) {
for (InferenceVariable currVariable : currVariableSet) {
if (DEBUG) {
log("======");
log("trying to resolve inference variable: " + str(currVariable));
log("based on this bound set:");
Arrays.stream(currentBounds.getAllBounds()).forEachOrdered(b -> log(" " + b.toString()));
}
final TypeRef instantiation = chooseInstantiation(currVariable);
if (instantiation == null) {
if (DEBUG) {
log("NO INSTANTIATION found for inference variable: " + str(currVariable));
}
return false;
} else {
if (DEBUG) {
log("choosing instantiation " + str(currVariable) + " := " + str(instantiation));
}
instantiate(currVariable, instantiation);
}
}
currentBounds.incorporate();
if (isDoomed()) {
return false;
}
}
return true;
}
use of org.eclipse.n4js.ts.types.InferenceVariable in project n4js by eclipse.
the class BoundSet method combineBothCoOrBothContra.
/**
* Case: inequalities of same direction, i.e.
* <ul>
* <li>`α <: S` and `β <: T` or
* <li>`α :> S` and `β :> T`.
* </ul>
*/
private TypeConstraint combineBothCoOrBothContra(TypeBound boundS, TypeBound boundT) {
final InferenceVariable alpha = boundS.left;
final InferenceVariable beta = boundT.left;
final TypeRef S = boundS.right;
final TypeRef T = boundT.right;
if (alpha == T.getDeclaredType()) {
// α :> S and β :> α implies β :> S
return new TypeConstraint(typeRef(beta), S, boundS.variance);
}
if (S.getDeclaredType() == beta) {
// α :> β and β :> T implies α :> T
return new TypeConstraint(typeRef(alpha), T, boundS.variance);
}
return null;
}
Aggregations