eclipse-ocl / org.eclipse.ocl

Eclipse Public License 2.0
0 stars 0 forks source link

[pivot] UnsupportedOperationException for '->size()' operation on collection with generics #1696

Open eclipse-ocl-bot opened 2 hours ago

eclipse-ocl-bot commented 2 hours ago

| --- | --- | | Bugzilla Link | 492801 | | Status | NEW | | Importance | P3 normal | | Reported | May 02, 2016 04:50 EDT | | Modified | Sep 13, 2017 09:54 EDT | | Depends on | 518424, 518573 | | Blocks | 493371 | | Reporter | Rolf Theunissen |

Description

Created attachment 261401\ Ecore model with 'size' invariant

Calling '->size()' in an OCL constraint on a attribute with a generic type, results in a UnsupportedOperationException, both in OCLinEcore and CompleteOCL.

Furthermore, when the CompleteOCL specification is loaded (at least on a dynamic instance), and the model is saved, the following error occurs:

Resource '/.../model/size' does not exist

example.ecore

eclipse-ocl-bot commented 2 hours ago

By Rolf Theunissen on May 02, 2016 04:50

Created attachment 261402 Complete OCL specifcation with 'size' invariant

Spec.ocl

eclipse-ocl-bot commented 2 hours ago

By Ed Willink on May 02, 2016 08:26

I don't see this in my workspace; perhaps it's been fixed. Certainly a couple of UOEs have.

You don't identiy what code version you are using.

You don't provide the stack trace.

eclipse-ocl-bot commented 2 hours ago

By Rolf Theunissen on May 02, 2016 09:05

I experience the problem in both Mars.2 and the current HEAD. The stack trace below is from current HEAD.

Actually the stack trace is swallowed by the tooling. This is the stack trace copied from a breakpoint in the debugger when the UnsupportedOperationException is thrown.

UMLIdResolver(AbstractIdResolver).visitTemplateParameterId(TemplateParameterId) line: 1760 \ UMLIdResolver(AbstractIdResolver).visitTemplateParameterId(TemplateParameterId) line: 1 \ TemplateParameterIdImpl.accept(IdVisitor) line: 41 \ UMLIdResolver(PivotIdResolver).getType(TypeId, Object) line: 138 \ UMLIdResolver(AbstractIdResolver).getCollectionType(CollectionTypeId, boolean, IntegerValue, UnlimitedNaturalValue) line: 768 \ UMLIdResolver(AbstractIdResolver).getCollectionType(CollectionTypeId) line: 738 \ UMLIdResolver(AbstractIdResolver).visitCollectionTypeId(CollectionTypeId) line: 1547 \ UMLIdResolver(AbstractIdResolver).visitCollectionTypeId(CollectionTypeId) line: 1 \ SpecializedCollectionTypeIdImpl.accept(IdVisitor) line: 30 \ UMLIdResolver(AbstractIdResolver).getStaticTypeOf(Object) line: 949 \ UMLIdResolver(PivotIdResolver).getStaticTypeOf(Object) line: 97 \ UMLIdResolver.getStaticTypeOf(Object) line: 158 \ BasicEvaluationVisitor.visitOperationCallExp(OperationCallExp) line: 649 \ OperationCallExpImpl.accept(Visitor) line: 528 \ BasicEvaluationVisitor.visitOperationCallExp(OperationCallExp) line: 598 \ OperationCallExpImpl.accept(Visitor) line: 528 \ OCLValidationDelegate$1(AbstractConstraintEvaluator).evaluate(EvaluationVisitor) line: 86 \ OCLValidationDelegate$1(OCLValidationDelegate$CheckingConstraintEvaluator).evaluate(EvaluationVisitor) line: 71 \ OCLValidationDelegate$1(OCLValidationDelegate$CheckingConstraintEvaluator).evaluate(EvaluationVisitor) line: 1 \ OCLValidationDelegate.validateExpressionInOCL(EClassifier, Object, DiagnosticChain, Map<Object,Object>, String, String, int, ExpressionInOCL) line: 296 \ OCLValidationDelegate.validatePivot(EClassifier, Object, DiagnosticChain, Map<Object,Object>, String, String, int) line: 316 \ OCLValidationDelegate.validate(EClass, EObject, Map<Object,Object>, String, String) line: 239 \ OCLValidationDelegateFactory$Global(OCLValidationDelegateFactory).validate(EClass, EObject, Map<Object,Object>, String, String) line: 77 \ EObjectValidator.validate(EClass, EObject, DiagnosticChain, Map<Object,Object>, String, String, String, int, String, int) line: 227 \ EObjectValidator$1(EObjectValidator$DynamicEClassValidator).validateDelegatedConstraints(EClass, EObject, DiagnosticChain, Map<Object,Object>) line: 1397 \ EObjectValidator$1(EObjectValidator$DynamicEClassValidator).validate(EClass, EObject, DiagnosticChain, Map<Object,Object>) line: 1414 \ EObjectValidator$1(EObjectValidator$DynamicEClassValidator).validate(EClass, EObject, DiagnosticChain, Map<Object,Object>) line: 1423 \ EObjectValidator.validate(EClass, EObject, DiagnosticChain, Map<Object,Object>) line: 333 \ ComposedEValidator.validate(EClass, EObject, DiagnosticChain, Map<Object,Object>) line: 125 \ ValidateAction$3(Diagnostician).doValidate(EValidator, EClass, EObject, DiagnosticChain, Map<Object,Object>) line: 171 \ ValidateAction$3.doValidate(EValidator, EClass, EObject, DiagnosticChain, Map<Object,Object>) line: 309 \ ValidateAction$3(Diagnostician).validate(EClass, EObject, DiagnosticChain, Map<Object,Object>) line: 158 \ ValidateAction$3(Diagnostician).validate(EObject, DiagnosticChain, Map<Object,Object>) line: 137 \ ValidateAction.validate(IProgressMonitor) line: 264 \ ValidateAction$1.run(IProgressMonitor) line: 176 \ ModalContext$ModalContextThread.run() line: 119

eclipse-ocl-bot commented 2 hours ago

By Rolf Theunissen on May 06, 2016 02:18

Created attachment 261504 Proper stacktrace

I overlooked a stack trace which was somewhat hidden in a dialog. See attachment for stack trace.

:notepad_spiral: stacktrace.txt

eclipse-ocl-bot commented 2 hours ago

By Ed Willink on May 06, 2016 05:30

(In reply to Rolf Theunissen from comment #4)

See attachment for stack trace.

UMLIdResolver(AbstractIdResolver).visitTemplateParameterId(TemplateParameterId) line: 1760

is still a UOE so you've found a new problem.

eclipse-ocl-bot commented 2 hours ago

By Ed Willink on May 10, 2016 07:21

The stack trace gives me some hints, but I still cannot reproduce your problem although I see a couple of NPE issues that make OCL->Validate bad for me.

It would be much easier for me if you:

a) provided a zipped project - I suspect that the .classpath is significant.

b) provided the steps that enable you to see the stack trace.

eclipse-ocl-bot commented 2 hours ago

By Ed Willink on May 10, 2016 08:50

(In reply to Ed Willink from comment #6)

although I see a couple of NPE issues that make OCL->Validate bad for me.

Bug 493322.

eclipse-ocl-bot commented 2 hours ago

By Rolf Theunissen on May 10, 2016 09:13

Created attachment 261595 Two projects showing errors

In org.example.ocl.bug.generics.validate, the UOE occurs when validating. This is a plain eclipse plugin project.

Validation on the same models in my.emf.project (a Java Plugin project) results in an OCLDelegateException, Caused by: java.lang.IllegalArgumentException: The feature 'events' is not a valid feature.

to reproduce:

:compression: validatebug.zip

eclipse-ocl-bot commented 2 hours ago

By Ed Willink on May 10, 2016 11:39

(In reply to Rolf Theunissen from comment #8)

  • Open CallInterface.xmi with reflective ecore editor

Thanks. I was opening .ecore / .ocl.

eclipse-ocl-bot commented 2 hours ago

By Ed Willink on May 10, 2016 11:57

The UnsupportedOperationException is correctly thrown by an insoluble problem; returning the concrete specialized type of the generalized type-id OrderedSet($0)<$0:$0> when $0 is unknown.

The insoluble problem is caused by the failure of the analysis leading to a PropertyCallExp to specialize the referenced property (in the same way as an OperationCallExp specializes).

eclipse-ocl-bot commented 2 hours ago

By Ed Willink on May 10, 2016 12:25

(In reply to Ed Willink from comment #10)

The insoluble problem is caused by the failure of the analysis leading to a PropertyCallExp to specialize the referenced property.

The property is specialized, but in the ParserContext of the declared Constraint.eContainer rather than the constrained type.

eclipse-ocl-bot commented 2 hours ago

By Ed Willink on May 10, 2016 13:02

(In reply to Ed Willink from comment #11)

The property is specialized, but in the ParserContext of the declared Constraint.eContainer rather than the constrained type.

This undermines the Pivot design whereby ExpressionInOCL extends LanguageExpression extends ValueSpecification allowing an in place parsed cached value to co-exist with /supersede an unparsed string value.

A string OCL expression defined in a generic type must be differently parsed in each derived concrete type. Even for ordinary types, a constraint may be differently optimized in derived classes.

The design can be simpler; LanguageExpression extends ValueSpecification in the defining classes. ExpressionInOCL extends ?? in each CompleteClass. No magic instanceof conversions.

eclipse-ocl-bot commented 2 hours ago

By Ed Willink on May 10, 2016 13:07

(In reply to Ed Willink from comment #12)

This undermines the Pivot design

which will not be changed significantly for Neon.

Workaround: (re-)define Constraints in specialized types.

(Templated types are not part of OCL <= 2.4. The Pivot-based OCL provides a prototype solution for a future OCL in which problems such as this can be flushed out.)

eclipse-ocl-bot commented 2 hours ago

By Ed Willink on May 11, 2016 02:22

(In reply to Ed Willink from comment #10)

The insoluble problem is caused by the failure of the analysis leading to a PropertyCallExp to specialize the referenced property (in the same way as an OperationCallExp specializes).

Only insoluble at compile time. The UOE occurs at run-time where the required value of the template parameter should be available on the stack/in the evaluation environment.

(Migrating the parsed ExpressionInOCL cache is a really bad idea since it requires semi-redundant re-parsing.)

eclipse-ocl-bot commented 2 hours ago

By Ed Willink on May 11, 2016 03:01

(In reply to Ed Willink from comment #14)

template parameter should be available on the stack/in the evaluation environment.

UMLIdResolver.getStaticTypeOf(Object) line: 158 \ BasicEvaluationVisitor.visitOperationCallExp(OperationCallExp) line: 649

is where the template parameter or rather the self object gets lost.

Why is a "getStaticTypeOf" being called at run-time?

getStaticTypeOf has been renamed a couple of times to try to make its API intuitive, but as the trace shows it has a magic UML-specific override.

There is a getDynamicTypeOf, but it has no context object and so uses null internally.

TupleIdResolver is a fudge addressing the issue with a derived knowledge of the template parameter list.

? two choices

eclipse-ocl-bot commented 2 hours ago

By Ed Willink on May 11, 2016 03:39

(In reply to Ed Willink from comment #15)

? two choices

  • a derived (UML)EvaluationIdResolver that is context/Evaluator-aware
  • a revised getDynamicTypeOf API with a context object parameter

Resolution of complex types requires the code to pass through

type = typeId.accept(this);

so "this" must be a context-aware IdVisitor (which IdResolver implements).

Adding a context field, or supporting a DecoratedIdVisitor would both temporarily modify the IdResolver and so inhibit evolution to support concurrent evaluations. Only a derived IdResolver will do.

Perhaps

New DynamicIdResolver interface extending (Static)IdResolver\ getDynamicTypeOf() in IdResolver is deprecated\ getDynamicTypeInOf() in DynamicIdResolver replaces it

PivotDynamicIdResolver - new context-aware PivotIdResolver derivation\ UMLDynamicIdResolver - new context-aware UMLIdResolver derivation

Ideally find some way to support the UMLisms without a duplicate derivation as UMLIdResolver, UMLDynamicIdResolver.

eclipse-ocl-bot commented 2 hours ago

By Ed Willink on May 11, 2016 06:20

(In reply to Ed Willink from comment #16)

Perhaps

New DynamicIdResolver interface extending (Static)IdResolver

After Neon, when the API tooling will force compatibility, investigate two new interfaces.

Currently compile-time dynamic type (which may be a partially specialized/refined type) is not properly distinguished from run-time dynamic type (which is a fully specialized type). Distinct interfaces for the two cases may make it all sensible.

eclipse-ocl-bot commented 2 hours ago

By Ed Willink on Jun 17, 2017 07:45

(In reply to Ed Willink from comment #17)

After Neon, when the API tooling will force compatibility, investigate two new interfaces.

Oops. After Oxygen.

Branch ewillink/492801 is rebased on Oxygen with a still failing test case.

eclipse-ocl-bot commented 2 hours ago

By Ed Willink on Jun 17, 2017 08:03

(In reply to Ed Willink from comment #15)

? two choices

  • a derived (UML)EvaluationIdResolver that is context/Evaluator-aware
  • a revised getDynamicTypeOf API with a context object parameter

The above choices support lazy run-time specialization of constraints on templated types.

Alternatively the constraint can be lazily specialized at 'use-time' prior to execution.

The latter approach requires no changes to the evaluator and shares repeated specialization costs at the expense of multiple copies per specialization.

This 'use-time' specialization may be needed for operation bodies, property initializers as well as constraints.

eclipse-ocl-bot commented 2 hours ago

By Ed Willink on Jun 18, 2017 05:23

Bug 475212 has been marked as a duplicate of this bug.

eclipse-ocl-bot commented 2 hours ago

By Ed Willink on Jun 18, 2017 05:30

(In reply to Ed Willink from comment #19)

This 'use-time' specialization may be needed for operation bodies, property initializers as well as constraints.

The specialized CompleteClass or rather its PartialClasses should supervise the feature/constraint specializations.

Support for invariants in PartialClasses is missing. Bug 518424.

eclipse-ocl-bot commented 2 hours ago

By Ed Willink on Jun 18, 2017 11:50

The returns from CompleteClass.getSuperCompleteClasses() are the unspecialized classes; should be the specialized with the corresponding feature specializations.

eclipse-ocl-bot commented 2 hours ago

By Ed Willink on Jun 21, 2017 08:35

This bug is a specific challenge to a general design issue.

Bug 518573 raised for the design issue.

eclipse-ocl-bot commented 2 hours ago

By Matthias Schoettle on Sep 13, 2017 09:54

I stumbled upon a similar problem I think. In bug 475212 you referred to this bug and mentioned "features of templated types need to be specialized by their specializations." so I wonder if below problem corresponds to this bug, if not I will file a new one.

I have a derived property and define the derivation using Pivot OCL. The derivation accesses templated classes with templated properties, e.g., Mapping with a reference of type T.

When I tested it (using a second/runtime Eclipse instance) it worked, but suddenly (running standalone) I received the exception (below at the end of this comment). However, when I try to access the property again, it works. I debugged and noticed that in org.eclipse.ocl.pivot.internal.delegate.OCLSettingDelegate.get(...), the first time the query is initialized and SettingBehavior.INSTANCE.validate(property2) is called, which eventually leads to the exception. The second time it is called the query is just executed without any problems.

Running it from a second/runtime Eclipse instance suppresses the exception, but it's noticeable because no value is displayed for the property in the Properties view.

Exception & stacktrace:

Caused by: java.lang.ClassCastException: org.eclipse.ocl.pivot.internal.TemplateParameterImpl cannot be cast to org.eclipse.ocl.pivot.Class\ at org.eclipse.ocl.pivot.internal.manager.TemplateSpecialisation.getSpecialisation(TemplateSpecialisation.java:137)\ at org.eclipse.ocl.pivot.internal.PropertyCallExpImpl.getSpecializedReferredPropertyType(PropertyCallExpImpl.java:478)\ at org.eclipse.ocl.pivot.internal.PropertyCallExpImpl.validateCompatibleResultType(PropertyCallExpImpl.java:740)\ at org.eclipse.ocl.pivot.util.PivotValidator.validatePropertyCallExp_validateCompatibleResultType(PivotValidator.java:3607)\ at org.eclipse.ocl.pivot.util.PivotValidator.validatePropertyCallExp(PivotValidator.java:3559)\ at org.eclipse.ocl.pivot.util.PivotValidator.validate(PivotValidator.java:977)\ [...]