Note that there are some explanatory texts on larger screens.

plurals
  1. POXText Chained Dependencies in Type Inference
    primarykey
    data
    text
    <p>In my experiments, it appears that XText cannot resolve variable types when there is a chain of dependencies across multiple XExpression blocks.</p> <p>A minimal example, to illustrate. I have a grammar:</p> <pre><code>grammar eg.types.inference.TypeInferenceExample with org.eclipse.xtext.xbase.Xbase generate typeInferenceExample "example.org/types/inference/TypeInferenceExample" Model: blocks += Block* ; Block: '{' 'name' ':' name=QualifiedName 'from' ':' ('none' | from=[Block|QualifiedName]) 'block' ':' expression=XBlockExpression '}' ; </code></pre> <p>An interface:</p> <pre><code>package eg.lib; public interface IModelBlock { public void push(org.eclipse.xtext.xbase.lib.Pair&lt;String, ?&gt; toPush); } </code></pre> <p>And a JvmModelInferrer:</p> <pre><code>package eg.types.inference.jvmmodel import com.google.inject.Inject import eg.lib.IModelBlock import eg.types.inference.typeInferenceExample.Block import eg.types.inference.typeInferenceExample.Model import org.eclipse.xtext.xbase.XBinaryOperation import org.eclipse.xtext.xbase.XExpression import org.eclipse.xtext.xbase.XFeatureCall import org.eclipse.xtext.xbase.XStringLiteral import org.eclipse.xtext.xbase.jvmmodel.AbstractModelInferrer import org.eclipse.xtext.xbase.jvmmodel.IJvmDeclaredTypeAcceptor import org.eclipse.xtext.xbase.jvmmodel.JvmTypesBuilder class TypeInferenceExampleJvmModelInferrer extends AbstractModelInferrer { @Inject extension JvmTypesBuilder def dispatch void infer(Model model, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) { model.blocks.forEach [block | acceptor.accept(block.toClass(block.name)).initializeLater [ superTypes += block.newTypeRef(typeof(IModelBlock)) members += block.toMethod("invoke", newTypeRef(Void::TYPE)) [ if (block.from != null) { block.from.pushType.forEach [p | parameters += block.toParameter(p.key, p.value) ] } body = block.expression ] ] ] } def private pushType(Block block) { return block.eAllContents.filter[ // List of push calls in this Block it instanceof XFeatureCall &amp;&amp; (it as XFeatureCall).concreteSyntaxFeatureName.equals("push") ].map [ val call = it as XFeatureCall // Add entry for push call as an OutputDeclaration return call.featureCallArguments.map[ if (!(it instanceof XBinaryOperation)) { throw new RuntimeException("Must push using -&gt; operator") } val key = (it as XBinaryOperation).leftOperand val value = (it as XBinaryOperation).rightOperand return key.name -&gt; value.inferredType ] ].head } def private String name(XExpression literal) { if (!(literal instanceof XStringLiteral)) { throw new UnsupportedOperationException("Literal was not a string literal") } return (literal as XStringLiteral).value } } </code></pre> <p>When I create a simple example for this DSL, such as:</p> <pre><code>{ name : BlockOne from : none block : { val i = 42 * 3.6 push("index" -&gt; i) } } { name : BlockTwo from : BlockOne block : { val res = "Another Value from " + index push("result" -&gt; res) } } </code></pre> <p>Code is generated just fine (type inference successfully works out the types of <code>index</code> and <code>res</code> in generating the output Java). I am using the pairs in the call to <code>push</code> on <code>BlockOne</code> to infer an interface on the invoke method for <code>BlockTwo</code>. This <code>push</code> method comes from the <code>IModelBlock</code> interface above. If I add a third Block to this example, thus:</p> <pre><code>{ name : BlockThree from : BlockTwo block : { val out = "This one came from: " + result push("out" -&gt; out) } } </code></pre> <p>Inference fails, with an <code>UnsupportedOperationException: TODO: import a functional handle on the type resolution that delegates to the best available (current, but evolving) result</code> (from <code>OnChangeEvictingCache.execWithoutCacheClear</code>, <code>CachingBatchTypeResolver.resolveTypes</code>).</p> <p><strong>Is there some other technique I should use to derive the types of variables which have chained dependencies like this in XText?</strong></p> <p>Thanks for the help!</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload