I am trying to calculate the common supertype in Xtext 2.4 using the new typesystem's API. In my DSL you can define tables, which look like:

def myTable {

| column1 | column2 |

| "value1"| "value4" |

| "value2"| "value3" |

}

Each cell in a table is an XExpression. Now I am trying in my JVMModelInferrer to infer the type of each column by calculating the common supertype of all column's expression. This used to work in Xtext 2.3 without problems. With the new typesystem's API I have the problem that the inferred type of each expression is null:

@Inject extension CommonTypeComputationServices commonTypeComputationServices

@Inject private IBatchTypeResolver typeResolver

...

val context = ...

val expressions = ...

val types = expressions.map[

typeResolver.resolveTypes(context).getActualType(it) <- this is always null

]

val typeReferenceOwner = new StandardTypeReferenceOwner(commonTypeComputationServices, context)

val commonSuperType = typeConformanceComputer.getCommonSuperType(types, typeReferenceOwner)

What I have noticed is that the TypeComputer is never invoked for my expressions. Do I need to register my expressions somehow for them to be included in the type inference?

Cheers,

Sebastian ]]>

please refer to the type computation for switch-expressions, collection

literals or if-expressions: You basically propagate the expected type to

your children and have a look at the Javadoc of the ITypeComputer:

The type of an expression depends on its children.

Expression types may be inferred from the types of contained children.

Therefore the given computation state is directly used to compute their

types. The framework will automatically propagate the common type of all

children to the parent. If- or Switch expression fall into this

category. A simplified implementation would again look like this:

void computeTypes(XIfExpression expression, ITypeComputationState state) {

state.withExpectations(getTypeForName(Boolean.TYPE,

state).computeTypes(expression.getIfExpression());

state.computeTypes(expression.getThen());

state.computeTypes(expression.getElse());

}

The If expression adjusts the expectation for one of its children and

computes its type. Afterwards, it directly reuses the current

expectations to compute the types of its branch expressions. The common

super type of those is assigned to the If expression by the framework.

[/snip]

Instead of using #getActualType, you'd use state.computeTypes(cell).

Since the table expression is similar to a collection literal, I'd dive

into that one, instead. In either situation it's your responsibility to

define the expectation for your children and compute their types

explicitely by calling state.computeTypes(..). The result will be

available for clients after all types have been computed. For that

purpose, you'd have to override

XbaseTypeComputer.computeTypes(XExpression, ITypeComputationState) and

handle your new expression types. A dispatch method should work if you

use Xtend.

Let me know if you have trouble with this approach.

Regards,

Sebastian

--

Looking for professional support for Xtext, Xtend or Eclipse Modeling?

Go visit: http://xtext.itemis.com

Am 02.04.13 16:15, schrieb Sebastian Benz:

> Hi,

>

> I am trying to calculate the common supertype in Xtext 2.4 using the new

> typesystem's API. In my DSL you can define tables, which look like:

>

> def myTable {

> | column1 | column2 |

> | "value1"| "value4" |

> | "value2"| "value3" |

> }

>

> Each cell in a table is an XExpression. Now I am trying in my

> JVMModelInferrer to infer the type of each column by calculating the

> common supertype of all column's expression. This used to work in Xtext

> 2.3 without problems. With the new typesystem's API I have the problem

> that the inferred type of each expression is null:

>

> @Inject extension CommonTypeComputationServices

> commonTypeComputationServices

> @Inject private IBatchTypeResolver typeResolver

>

> ..

>

> val context = ...

> val expressions = ...

> val types = expressions.map[

> typeResolver.resolveTypes(context).getActualType(it) <- this is

> always null

> ]

>

> val typeReferenceOwner = new

> StandardTypeReferenceOwner(commonTypeComputationServices, context)

> val commonSuperType = typeConformanceComputer.getCommonSuperType(types,

> typeReferenceOwner)

>

> What I have noticed is that the TypeComputer is never invoked for my

> expressions. Do I need to register my expressions somehow for them to be

> included in the type inference?

>

> Cheers,

>

> Sebastian]]>

My question is how can I influence for which elements of my DSLs the type computation will be performed? ]]>

> problem is not implementing the TypeComputer but the JvmModelInferrer. I

> need to access the types of the expressions in order to generate a

> corresponding constructor. This is why I am using

> IBatchTypeResolver#getActualType(...). However, this call returns null

> as the type computer is never invoked for the table cell expressions. I

> can fix the latter by extending

> DispatchAndExtensionAwareReentrantTypeResolver to explicitly trigger the

> computation of the types for the tables, but this leads to some other

> problems and does not feel like the correct approach.

> My question is how can I influence for which elements of my DSLs the

> type computation will be performed?

It's actually not allowed to use a computed type in the inferer itself,

since the type computation depends most likely on resolved links which

depend on the available signatures. The type proxies that are available

in the JvmTypesBuilder v2.3 have been superseded by

JvmTypesBuilder#inferredType(XExpression?), so if you need a certain

type to be inferred to put it into a signature, you'd have to use such a

reference and handle it explicitly in the ReentrantTypeResolver.

Type computation will be performed for all expressions in the model,

e.g. primary traversal is done for the JvmModel and its logically

contained expressions and as a last resort for broken models, the source

model is traversed, too. In other words: the tables, their columns and

rows will be travered if they are logically contained in a JVM element.

I'm not sure how this approach suits your needs. Unfortunately I

currently don't have the time to explore the implementation that you had

for 2.3.1 but I'm optimistic that the inferredType(..) approach will

work out for your use-case, too. Please point me to all the stumbling

blocks that I put into your way :-)

Regards,

Sebastian

--

Looking for professional support for Xtext, Xtend or Eclipse Modeling?

Go visit: http://xtext.itemis.com]]>

Am 02.04.13 20:36, schrieb Sebastian Benz:

> Thanks for the quick reply. I might have misphrased my question. My

> problem is not implementing the TypeComputer but the JvmModelInferrer. I

> need to access the types of the expressions in order to generate a

> corresponding constructor. This is why I am using

> IBatchTypeResolver#getActualType(...). However, this call returns null

> as the type computer is never invoked for the table cell expressions. I

> can fix the latter by extending

> DispatchAndExtensionAwareReentrantTypeResolver to explicitly trigger the

> computation of the types for the tables, but this leads to some other

> problems and does not feel like the correct approach.

> My question is how can I influence for which elements of my DSLs the

> type computation will be performed?

It's actually not allowed to use a computed type in the inferer itself,

since the type computation depends most likely on resolved links which

depend on the available signatures. The type proxies that are available

in the JvmTypesBuilder v2.3 have been superseded by

JvmTypesBuilder#inferredType(XExpression?), so if you need a certain

type to be inferred to put it into a signature, you'd have to use such a

reference and handle it explicitly in the ReentrantTypeResolver.

OK, this makes sense. I managed to get a first working version using this approach. The Xtend implementation was actually a good guide on how to use this approach.

Quote:

Type computation will be performed for all expressions in the model,

e.g. primary traversal is done for the JvmModel and its logically

contained expressions and as a last resort for broken models, the source

model is traversed, too. In other words: the tables, their columns and

rows will be travered if they are logically contained in a JVM element.

I'm not sure how this approach suits your needs. Unfortunately I

currently don't have the time to explore the implementation that you had

for 2.3.1 but I'm optimistic that the inferredType(..) approach will

work out for your use-case, too. Please point me to all the stumbling

blocks that I put into your way

Triggering the type computation based on the JVM model definitely makes sense. However, this forces you to have a clean mapping between your domain model and the JVM model as hacks no longer work (like in my case). This can make it a little bit harder, but I think it results in the end in a cleaner solution.

I got a basic version working, but there are some things which still do not work:

- The inferred type for closures in table cells cannot be retrieved. It is computed correctly but serializing the cell type results in a NPE.

- My table cells cannot access fields declared in the same type.

My theory is that both problems result from the table cells not being correctly linked to the JVM model, but I had not yet time to into it in more detail. I have to admit that I haven't yet fully understood when it is important to just associate two elements, when to associate them primary, when to associate a logical container and what the implications of these associations are.

]]>

let me try to answer the questions from the last paragraph:

The associations is basically just a navigation thing (except for

dispatch methods). If a certain region in a Java file should be revealed

in an editor, the association is used to find the original Xtend source

element. Scoping / the type inference uses the logical container. I'm

aware of a bug in 2.3.1 which allowed to use more than one expression as

the *logically contained* body of a constructor / operation. Even though

that could have been used to implement what seemed to be proper scoping,

it could lead to problems. This was fixed, even though not entirely. It

is unfortunately still possible to set the very same JVM element es the

logical container of more than one expression, but only of the

expressions will be considered (there is no exception thrown to indicate

a programming problem but just some quirky misbehavior). We will support

other things like logically contained expressions in other expressions,

but that is currently not possible. Therefore, you'd have to put each of

your cell expressions into an own _init_5_2 method to get proper scoping

semantics. The constructor would be the black-box that delegates to the

init methods.

The NPEs indicate expressions that are not yet linked or that don't have

an associated type, which would be a follow up problem.

Regards,

Sebastian

Am 04.04.13 13:25, schrieb Sebastian Benz:

> Quote:

>> Am 02.04.13 20:36, schrieb Sebastian Benz:

>> > Thanks for the quick reply. I might have misphrased my question. My

>> > problem is not implementing the TypeComputer but the

>> JvmModelInferrer. I

>> > need to access the types of the expressions in order to generate a

>> > corresponding constructor. This is why I am using

>> > IBatchTypeResolver#getActualType(...). However, this call returns null

>> > as the type computer is never invoked for the table cell expressions. I

>> > can fix the latter by extending

>> > DispatchAndExtensionAwareReentrantTypeResolver to explicitly trigger

>> the

>> > computation of the types for the tables, but this leads to some other

>> > problems and does not feel like the correct approach.

>> > My question is how can I influence for which elements of my DSLs the

>> > type computation will be performed?

>>

>> It's actually not allowed to use a computed type in the inferer

>> itself, since the type computation depends most likely on resolved

>> links which depend on the available signatures. The type proxies that

>> are available in the JvmTypesBuilder v2.3 have been superseded by

>> JvmTypesBuilder#inferredType(XExpression?), so if you need a certain

>> type to be inferred to put it into a signature, you'd have to use such

>> a reference and handle it explicitly in the ReentrantTypeResolver.

>

>

> OK, this makes sense. I managed to get a first working version using

> this approach. The Xtend implementation was actually a good guide on how

> to use this approach.

> Quote:

>> Type computation will be performed for all expressions in the model,

>> e.g. primary traversal is done for the JvmModel and its logically

>> contained expressions and as a last resort for broken models, the

>> source model is traversed, too. In other words: the tables, their

>> columns and rows will be travered if they are logically contained in a

>> JVM element. I'm not sure how this approach suits your needs.

>> Unfortunately I currently don't have the time to explore the

>> implementation that you had for 2.3.1 but I'm optimistic that the

>> inferredType(..) approach will work out for your use-case, too. Please

>> point me to all the stumbling blocks that I put into your way :)

>

>

> Triggering the type computation based on the JVM model definitely makes

> sense. However, this forces you to have a clean mapping between your

> domain model and the JVM model as hacks no longer work (like in my

> case). This can make it a little bit harder, but I think it results in

> the end in a cleaner solution.

> I got a basic version working, but there are some things which still do

> not work:

>

> - The inferred type for closures in table cells cannot be retrieved. It

> is computed correctly but serializing the cell type results in a NPE. -

> My table cells cannot access fields declared in the same type.

> My theory is that both problems result from the table cells not being

> correctly linked to the JVM model, but I had not yet time to into it in

> more detail. I have to admit that I haven't yet fully understood when it

> is important to just associate two elements, when to associate them

> primary, when to associate a logical container and what the implications

> of these associations are.]]>