This file contains some remarks on the MPS typesystem.

Node whose type is set by a rule in another node

Assume we have the following structure:

Now we want to make sure the type of the left side is a supertype of the right side. In the case of VariableDeclarationAssignment, its type should also be inferred from the right side.

Both can be achieved by a simple rule:

do {
    infer typeof(assignment.leftSide) :>=: typeof(assignment.rightSide);

After compiling this seems to work in the sandbox.

However, there is one crucial floor: When trying to determine the type of a VariableDeclarationAssignment in isolation, the typesystem cannot infer its type because there is no typesystem rule attached to that concept. According to the mps docs on typesystem dependencies, the typesystem should automatically check the parent node if the type is not concrete. However, in my experience this does not happen in the illustrated case (on MPS 2022.2).

To fix this we need to add a typesystem rule to VariableDeclarationAssignment, which forces the typesystem to evaluate the rule on Assignment. This can be done with the following snippet:

do {

This is also explaine in the mps docs on typesystem dependencies. However, when I first read it, I did not understand it correctly, hence me writing this chapter.

A note on when the problem manifests:

Getting the type of a node

To get the type of a node outside of inference rules, one can usually use the type operation (you need the language jetbrains.mps.lang.typesystem). This is also explained in the mps docs on using the typesystem.

However, as described in Node whose type is set by a rule in another node, it can be the case that the type of a node differs based on whether it was calculated in isolation (e.g. during model checks or in the generator) or in a typechcking session which checked many nodes (as the one of the editor).

To avoid risking to have this difference, it is possible to always force the typesystem to calculate the type in isolation:

node<> myType = TypecheckingFacade.getFromContext().computeIsolated({ => myNode.type; })

(You need the model jetbrains.mps/typechecking@java_stub and the language jetbrains.mps.lang.typesystem.)