Cannot instantiate generics in tree editor [message #1843062] |
Tue, 13 July 2021 20:25 |
Elie Richa Messages: 72 Registered: February 2016 |
Member |
|
|
Hello folks,
I'm trying to use generics in Ecore but I ended up with a metamodel where the tree editor refuses to offer creating children that I think are valid.
I'm attaching the metamodel and an instance of it that can be opened in the reflective editor if the files are in the same directory.
My goal is to model objects that have variants. The variants would be children of the object. There are two kinds of variants: either based on a range, or on a pattern. And each variant would have as a child, another instance of the parent object with a different content specific to that variant.
Because I intend to have multiple classes with such variability, I decided to use generics to instantiate the same pattern multiple times.
A class T requiring variability inherits WithVariability<T> . WithVariability<T> defines a list of contained Variant<T>. Variant<T> has a child variantObject of type T. Variant<T> is itself abstract and has two concrete sub-classes RangeVariant<T> and ConcreteVariant<T>.
I instantiate this pattern twice for these classes where I want variability:
- ClassAWithVariability which inherits WithVariability<ClassAWithVariability>
- ClassBWithVariability which inherits WithVariability<ClassBWithVariability>
I created a Root class that can contain instances of ClassAWithVariability and ClassBWithVariability for demonstration.
My expectation in the tree editor is that right-clicking a ClassAWithVariability would allow me to create children RangeVariants and PatternVariants. But it's not the case. It doesn't offer anything.
When I change Variant from abstract to non-abstract, the editor starts offering to create Variant instances, but not RangeVariant and PatternVariant.
With some debugging I found that org.eclipse.emf.edit.provider.ItemProviderAdapter at line 837 is removing the child descriptors for RangeVariant and PatternVariant because it judges that they are not compatible with the expected reified type Variant<ClassAWithVariability>. I suspect for example that the child descriptor provides a child instance of RangeVariant, but the instance cannot hold information about the generic instantiation. So it is judged incompatible with the expected reified type Variant<ClassAWithVariability> which does have the information about the generic instantiation.
Is there something wrong in my metamodel? A workaround? Or is EMF lacking something here?
Thanks in advance for any help! :)
Elie Richa, Ph.D
Software Engineer, AdaCore
https://www.adacore.com
|
|
|
|
|
|
|
|
Re: Cannot instantiate generics in tree editor [message #1843189 is a reply to message #1843164] |
Mon, 19 July 2021 14:41 |
Elie Richa Messages: 72 Registered: February 2016 |
Member |
|
|
Hello Ed,
Thank you for the explanation and the link to 382774. The initial use case described by Jean-Francois Brazeau is exactly the one I have and where I don't get a satisfactory behavior in the editor. As the last message by Jean-François is "I will test it as soon as possible.", I suspect that he didn't get around to test it because I think he would have gotten the same behavior I'm seeing: inability to create children objects in the tree editor.
Now regarding the API/code, I understand and agree that we shouldn't break existing behavior. So I came up with the following attempt at detecting the situation I have and returning an optimistic result for lack of accurate typing information.
I ran all of "Test EMF Core" which includes ReificationTest and didn't get any regressions. It's likely that Reification.ecore does not include a case similar to mine. So if this change seems roughly reasonable, I can open a bug and submit the patch + corresponding test cases on Gerrit.
diff --git a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EGenericTypeImpl.java b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EGenericTypeImpl.java
index 8385bbb7f..a687bb713 100644
--- a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EGenericTypeImpl.java
+++ b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/impl/EGenericTypeImpl.java
@@ -708,41 +708,55 @@ public class EGenericTypeImpl extends MinimalEObjectImpl.Container implements EG
for (EGenericType eGenericSuperType : instanceEClass.getEAllGenericSuperTypes())
{
if (eGenericSuperType.getEClassifier() == eClass)
{
// If it's specified as a raw type, we're done.
//
EList<EGenericType> instanceETypeArguments = eGenericSuperType.getETypeArguments();
if (instanceETypeArguments.isEmpty())
{
return true;
}
else
{
// Look for a contradiction between the type arguments of this generic type and the type arguments specified for the instance.
//
for (int i = 0; i < size; ++i)
{
EGenericType instanceETypeArgument = instanceETypeArguments.get(i);
EGenericType eTypeArgument = eTypeArguments.get(i);
EGenericType reifiedType = EcoreUtil.getReifiedType(instanceEClass, instanceETypeArgument);
- if (eTypeArgument.getETypeParameter() == null ? !isCompatibleArgument(reifiedType, eTypeArgument) : !isSuperType(reifiedType, eTypeArgument))
+ if (eTypeArgument.getETypeParameter() == null)
+ {
+ if (reifiedType.getETypeParameter() != null && reifiedType.getETypeParameter().getEBounds().isEmpty())
+ {
+ // The reified type has a type parameter that was not resolved and that has no bound information
+ // so we cannot determine any relevant compatibility information. Return an optimistic result.
+ //
+ return true;
+ }
+ else if (!isCompatibleArgument(reifiedType, eTypeArgument))
+ {
+ return false;
+ }
+ }
+ else if (!isSuperType(reifiedType, eTypeArgument))
{
return false;
}
}
return true;
}
}
}
// We should not get here.
//
return false;
}
}
}
}
}
}
Elie Richa, Ph.D
Software Engineer, AdaCore
https://www.adacore.com
|
|
|
|
|
|
Powered by
FUDForum. Page generated in 0.02796 seconds