A colleague has recently wondered why his project has an error but he can build it successfully nevertheless. MPS was underlining a piece of code with red squigglies, telling him that a certain reference was out of scope and the target module should be imported, yet it could generate and compile the code just fine.

So why does the line above compile even though MyConcept is out of scope? Let’s examine it closer.

The first occurrence of MyConcept is on the left-hand side of the assignment, as part of the variable type. Here, the type node<MyConcept> is translated into simple SNode Java type (this is analogous to the type erasure process that all generic types undergo in Java). Thus, to generate code for this part we do not need the target of the reference at all.

The second time MyConcept occurs in new node<MyConcept>. To translate this code the generator does need some information about MyConcept: its name, identifier, and the identifier of its language.

Although it may seem at first that an “out of scope” reference is somehow illegal and thus cannot be followed, this is not the case. The reference target is a valid, existing node that just happens to be outside of the set of allowed targets for the reference, as computed by the reference’s scope. But MPS knows where to find the target.

In fact, if you examine the model file, you will find that MPS still imported the target model but marked the import as implicit:

<import
    index="cdvr"
    ref="r:28a14757-93a8-419f-8131-d580829fbb0f(MyLanguage.structure)"
    implicit="true" />

So, the reference can indeed be followed, and the generator can examine the concept declaration of MyConcept, get the information it needs, and produce the code:

SNode x = SConceptOperations.createNewNode(
    MetaAdapterFactory.getConcept(
        0x8e57a5acf98c4246L,
        0xbe43fb7dcc7fa92eL,
        0x18a5b4eb5743700cL,
        "MyLanguage.structure.MyConcept"));

In this particular case the produced code does not refer to any classes from the code that MPS generated for the target language, thus it can be compiled without any problems.

However, the “out of scope” and “module should be imported” are not completely useless. Sometimes, the generated code will fail to compile. That’s because adding a dependency on another module also causes MPS to add this module to the compilation class path, making its classes visible to the Java code of the module that depends on it. Without the dependency Java compilation would fail with an error that a certain import could not be resolved.

Thus, there are some corner cases where a missing import will not cause your code to fail to build, but these errors are still important and you should make sure you have your dependencies in order.