[580143] Introduce oclBase() / oclExtension()
diff --git a/plugins/org.eclipse.ocl.pivot/model/OCL-2.5.oclstdlib b/plugins/org.eclipse.ocl.pivot/model/OCL-2.5.oclstdlib
index ea1b93b..edc15bc 100644
--- a/plugins/org.eclipse.ocl.pivot/model/OCL-2.5.oclstdlib
+++ b/plugins/org.eclipse.ocl.pivot/model/OCL-2.5.oclstdlib
@@ -1027,6 +1027,26 @@
 --		post IsType: result.oclIsKindOf(type);
 	}
 	/**
+	Returns the application class that is extended by this extension element. Returns null for an orphan extension of nothing.
+	*/
+	operation oclBase() : OclType[?] => 'org.eclipse.ocl.pivot.library.oclany.OclElementOclBaseOperation';
+	/**
+	Returns the application class conforming to base extended by this extension element. Returns null if no such class.
+	*/
+	operation oclBase(base : OclType[1]) : OclType[?] => 'org.eclipse.ocl.pivot.library.oclany.OclElementOclBaseOperation';
+	/**
+	Returns the application instance of the Stereotype that conforms to stereotype applied to this element. Returns invalid if more than one.
+	*/
+	operation oclExtension(stereotype : OclStereotype[1]) : OclElement[?] invalidating => 'org.eclipse.ocl.pivot.library.oclany.OclElementOclExtensionOperation';
+	/**
+	Returns the application instances of the Stereotypes that conform to stereotype applied to this element.
+	*/
+	operation oclExtensions(stereotype : OclStereotype[1]) : Set(OclElement[*|1]) => 'org.eclipse.ocl.pivot.library.oclany.OclElementOclExtensionsOperation';
+	/**
+	Returns the application instances of all Stereotypes applied to this element.
+	*/
+	operation oclExtensions() : Set(OclElement[*|1]) => 'org.eclipse.ocl.pivot.library.oclany.OclElementOclExtensionsOperation';
+	/**
 	Returns the object for which self is a composed content or null if there is no such object.
 	*/
 	operation oclContainer() : OclElement[?] => 'org.eclipse.ocl.pivot.library.classifier.ClassifierOclContainerOperation';
@@ -1981,7 +2001,7 @@
 	*/
 	operation allInstances() : Set(OclSelf) => 'org.eclipse.ocl.pivot.library.classifier.ClassifierAllInstancesOperation';
 }
-type Stereotype {
+type Stereotype conformsTo OclStereotype {
 	/**
 	Return a set of all instances of the stereotype and derived types of self.
 	*/
diff --git a/plugins/org.eclipse.ocl.pivot/src/org/eclipse/ocl/pivot/internal/library/ExtensionProperty.java b/plugins/org.eclipse.ocl.pivot/src/org/eclipse/ocl/pivot/internal/library/ExtensionProperty.java
index d741047..bf384ea 100644
--- a/plugins/org.eclipse.ocl.pivot/src/org/eclipse/ocl/pivot/internal/library/ExtensionProperty.java
+++ b/plugins/org.eclipse.ocl.pivot/src/org/eclipse/ocl/pivot/internal/library/ExtensionProperty.java
@@ -27,6 +27,7 @@
 import org.eclipse.ocl.pivot.internal.utilities.EnvironmentFactoryInternal.EnvironmentFactoryInternalExtension;
 import org.eclipse.ocl.pivot.library.AbstractProperty;
 import org.eclipse.ocl.pivot.utilities.ParserException;
+import org.eclipse.ocl.pivot.utilities.PivotUtil;
 import org.eclipse.ocl.pivot.utilities.ValueUtil;
 import org.eclipse.ocl.pivot.values.InvalidValueException;
 
@@ -36,18 +37,10 @@
  */
 public class ExtensionProperty extends AbstractProperty
 {
-	protected final @NonNull Property property;
-
-	public ExtensionProperty(@NonNull Property property) {
-		this.property = property;
-	}
-
-	@Override
-	public @Nullable Object evaluate(@NonNull Executor executor, @NonNull TypeId returnTypeId, @Nullable Object sourceValue) {
-		Type staticType = property.getType();
-		if (staticType == null) {
-			return null;
-		}
+	/**
+	 * @since 1.18
+	 */
+	public static @Nullable List<@NonNull ElementExtension> selectExtensions(@NonNull Executor executor, @Nullable Type staticType, @NonNull Object sourceValue) {
 		Element element = null;
 		if (sourceValue instanceof Element) {
 			element = (Element)sourceValue;
@@ -56,34 +49,48 @@
 			try {
 				element = ((EnvironmentFactoryInternalExtension)executor.getEnvironmentFactory()).getASOf(Element.class, (EObject)sourceValue);
 			} catch (ParserException e) {
-				return new InvalidValueException(e, "Failed to parse " + property);
+				throw new InvalidValueException(e, "Failed to access Stereotype extensions");
 			}
 		}
-		if (element != null) {
-			List<ElementExtension> selectedExtensions = null;
-			for (ElementExtension elementExtension : element.getOwnedExtensions()) {
-				Stereotype dynamicStereotype = elementExtension.getStereotype();
-				if (dynamicStereotype.conformsTo(executor.getStandardLibrary(), staticType)) {
-					if (selectedExtensions == null) {
-						selectedExtensions = new ArrayList<ElementExtension>();
-					}
-					selectedExtensions.add(elementExtension);
+		if (element == null) {
+			return null;
+		}
+		List<@NonNull ElementExtension> selectedExtensions = null;
+		for (@NonNull ElementExtension elementExtension : PivotUtil.getOwnedExtensions(element)) {
+			Stereotype dynamicStereotype = elementExtension.getStereotype();
+			if ((staticType == null) || dynamicStereotype.conformsTo(executor.getStandardLibrary(), staticType)) {
+				if (selectedExtensions == null) {
+					selectedExtensions = new ArrayList<>();
 				}
-			}
-			if (selectedExtensions == null) {
-				return null;
-			}
-			TypeId typeId = property.getTypeId();
-			if (typeId instanceof CollectionTypeId) {
-				return ValueUtil.createSetValue((CollectionTypeId) typeId, selectedExtensions);
-			}
-			else if (selectedExtensions.size() == 1) {
-				return selectedExtensions.get(0);
-			}
-			else {
-				return new InvalidValueException("Multiple applied stereotypes for " + property);
+				selectedExtensions.add(elementExtension);
 			}
 		}
-		return staticType;
+		return (selectedExtensions != null) && (selectedExtensions.size() > 0) ? selectedExtensions : null;
+	}
+
+	protected final @NonNull Property property;
+
+	public ExtensionProperty(@NonNull Property property) {
+		this.property = property;
+	}
+
+	@Override
+	public @Nullable Object evaluate(@NonNull Executor executor, @NonNull TypeId returnTypeId, @Nullable Object sourceValue) {
+		Type staticType = PivotUtil.getType(property);
+		assert sourceValue != null;
+		List<@NonNull ElementExtension> selectedExtensions = selectExtensions(executor, staticType, sourceValue);
+		if (selectedExtensions == null) {
+			return null;
+		}
+		TypeId typeId = property.getTypeId();
+		if (typeId instanceof CollectionTypeId) {
+			return ValueUtil.createSetValue((CollectionTypeId) typeId, selectedExtensions);
+		}
+		else if (selectedExtensions.size() == 1) {
+			return selectedExtensions.get(0);
+		}
+		else {
+			return new InvalidValueException("Multiple applied stereotypes for " + property);
+		}
 	}
 }
\ No newline at end of file
diff --git a/plugins/org.eclipse.ocl.pivot/src/org/eclipse/ocl/pivot/internal/manager/Orphanage.java b/plugins/org.eclipse.ocl.pivot/src/org/eclipse/ocl/pivot/internal/manager/Orphanage.java
index f4cd44e..f80e1cb 100644
--- a/plugins/org.eclipse.ocl.pivot/src/org/eclipse/ocl/pivot/internal/manager/Orphanage.java
+++ b/plugins/org.eclipse.ocl.pivot/src/org/eclipse/ocl/pivot/internal/manager/Orphanage.java
@@ -419,6 +419,8 @@
 
 	/**
 	 * Return the global Orphanage.
+	 *
+	 * @since 1.18
 	 */
 	public static @NonNull Orphanage getOrphanage() {
 		OrphanResource orphanResource = ORPHAN_RESOURCE;
diff --git a/plugins/org.eclipse.ocl.pivot/src/org/eclipse/ocl/pivot/library/oclany/OclElementOclBaseOperation.java b/plugins/org.eclipse.ocl.pivot/src/org/eclipse/ocl/pivot/library/oclany/OclElementOclBaseOperation.java
new file mode 100644
index 0000000..a421dcf
--- /dev/null
+++ b/plugins/org.eclipse.ocl.pivot/src/org/eclipse/ocl/pivot/library/oclany/OclElementOclBaseOperation.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (c) 2022 Willink Transformations and others.
+ * All rights reserved.   This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v20.html
+ *
+ * Contributors:
+ *   E.D.Willink - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ocl.pivot.library.oclany;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.ocl.pivot.Element;
+import org.eclipse.ocl.pivot.ElementExtension;
+import org.eclipse.ocl.pivot.StandardLibrary;
+import org.eclipse.ocl.pivot.Type;
+import org.eclipse.ocl.pivot.evaluation.Executor;
+import org.eclipse.ocl.pivot.ids.TypeId;
+import org.eclipse.ocl.pivot.library.AbstractPolyOperation;
+import org.eclipse.ocl.pivot.utilities.ValueUtil;
+import org.eclipse.ocl.pivot.values.InvalidValueException;
+
+/**
+ * OclElementOclBaseOperation realises the OclElement::oclBase()  and OclElement::oclBase(stereotype) library operations.
+ *
+ * @since 1.18
+ */
+public class OclElementOclBaseOperation extends AbstractPolyOperation
+{
+	public static final @NonNull OclElementOclBaseOperation INSTANCE = new OclElementOclBaseOperation();
+
+	@Override
+	public @Nullable Object evaluate(@NonNull Executor executor, @NonNull TypeId returnTypeId, @Nullable Object sourceValue, @Nullable Object typeValue) {
+		assert sourceValue != null;
+		assert typeValue != null;
+		ElementExtension asElementExtension = ValueUtil.getASorASofES(executor, ElementExtension.class, sourceValue);
+		Type asType = ValueUtil.getASorASofES(executor, Type.class, typeValue);
+		Element asBase = asElementExtension.getBase();
+		StandardLibrary standardLibrary = executor.getStandardLibrary();
+		Type baseType = (Type)asBase; //executor.getIdResolver().getDynamicTypeOf(asBase);
+		boolean result = baseType.conformsTo(standardLibrary, asType);	// FIXME this can fail because ExecutableStandardLibrary.getMetaclass is bad
+		if (!result) {
+			return null;
+		}
+		else if (asElementExtension == sourceValue) {
+			return asBase;
+		}
+		else {
+			return asBase.getESObject();
+		}
+	}
+
+	@Override
+	public @Nullable Object evaluate(@NonNull Executor executor, @NonNull TypeId returnTypeId, @Nullable Object sourceValue) {
+		assert sourceValue != null;
+		ElementExtension asElementExtension = ValueUtil.getASorASofES(executor, ElementExtension.class, sourceValue);
+		Element asBase = asElementExtension.getBase();
+		if (asElementExtension == sourceValue) {
+			return asBase;
+		}
+		else {
+			return asBase.getESObject();
+		}
+	}
+
+	@Override
+	public @Nullable Object evaluate(@NonNull Executor executor, @NonNull TypeId returnTypeId,
+			@Nullable Object sourceValue, @Nullable Object firstArgumentValue, @Nullable Object secondArgumentValue) {
+		throw new InvalidValueException("too many arguments for oclBase()");
+	}
+}
diff --git a/plugins/org.eclipse.ocl.pivot/src/org/eclipse/ocl/pivot/library/oclany/OclElementOclExtensionOperation.java b/plugins/org.eclipse.ocl.pivot/src/org/eclipse/ocl/pivot/library/oclany/OclElementOclExtensionOperation.java
new file mode 100644
index 0000000..a0fb2b1
--- /dev/null
+++ b/plugins/org.eclipse.ocl.pivot/src/org/eclipse/ocl/pivot/library/oclany/OclElementOclExtensionOperation.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2022 Willink Transformations and others.
+ * All rights reserved.   This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v20.html
+ *
+ * Contributors:
+ *   E.D.Willink - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ocl.pivot.library.oclany;
+
+import java.util.List;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.ocl.pivot.Element;
+import org.eclipse.ocl.pivot.ElementExtension;
+import org.eclipse.ocl.pivot.Stereotype;
+import org.eclipse.ocl.pivot.evaluation.Executor;
+import org.eclipse.ocl.pivot.ids.TypeId;
+import org.eclipse.ocl.pivot.internal.library.ExtensionProperty;
+import org.eclipse.ocl.pivot.library.AbstractBinaryOperation;
+import org.eclipse.ocl.pivot.utilities.ValueUtil;
+import org.eclipse.ocl.pivot.values.InvalidValueException;
+
+/**
+ * OclElementOclExtensionOperation realises the OclElement::oclExtension(stereotype) library operation.
+ *
+ * @since 1.18
+ */
+public class OclElementOclExtensionOperation extends AbstractBinaryOperation
+{
+	public static final @NonNull OclElementOclExtensionOperation INSTANCE = new OclElementOclExtensionOperation();
+
+	@Override
+	public @Nullable Object evaluate(@NonNull Executor executor, @NonNull TypeId returnTypeId, @Nullable Object sourceValue, @Nullable Object stereotypeValue) {
+		assert sourceValue != null;
+		Element asSource = ValueUtil.getASorASofES(executor, Element.class, sourceValue);
+		Stereotype asStereotype = stereotypeValue != null ? ValueUtil.getASorASofES(executor, Stereotype.class, stereotypeValue) : null;
+		List<@NonNull ElementExtension> selectedExtensions = ExtensionProperty.selectExtensions(executor, asStereotype, asSource);
+		if (selectedExtensions == null) {
+			return null;
+		}
+		int size = selectedExtensions.size();
+		if (size == 0) {
+			return null;
+		}
+		if (size > 1) {
+			throw new InvalidValueException("More than one Stereotype applied");
+		}
+		ElementExtension asExtension = selectedExtensions.get(0);
+		if (asSource == sourceValue) {
+			return asExtension;
+		}
+		else {
+			return asExtension.getESObject();
+		}
+	}
+}
diff --git a/plugins/org.eclipse.ocl.pivot/src/org/eclipse/ocl/pivot/library/oclany/OclElementOclExtensionsOperation.java b/plugins/org.eclipse.ocl.pivot/src/org/eclipse/ocl/pivot/library/oclany/OclElementOclExtensionsOperation.java
new file mode 100644
index 0000000..2a7f68a
--- /dev/null
+++ b/plugins/org.eclipse.ocl.pivot/src/org/eclipse/ocl/pivot/library/oclany/OclElementOclExtensionsOperation.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * Copyright (c) 2022 Willink Transformations and others.
+ * All rights reserved.   This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v20.html
+ *
+ * Contributors:
+ *   E.D.Willink - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ocl.pivot.library.oclany;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.ocl.pivot.Element;
+import org.eclipse.ocl.pivot.ElementExtension;
+import org.eclipse.ocl.pivot.Stereotype;
+import org.eclipse.ocl.pivot.evaluation.Executor;
+import org.eclipse.ocl.pivot.ids.CollectionTypeId;
+import org.eclipse.ocl.pivot.ids.TypeId;
+import org.eclipse.ocl.pivot.internal.library.ExtensionProperty;
+import org.eclipse.ocl.pivot.library.AbstractPolyOperation;
+import org.eclipse.ocl.pivot.utilities.ValueUtil;
+import org.eclipse.ocl.pivot.values.InvalidValueException;
+import org.eclipse.ocl.pivot.values.SetValue;
+
+/**
+ * OclElementOclExtensionsOperation realises the OclElement::oclExtensions()
+ * and OclElement::oclExtensions(stereotype) library operation.
+ *
+ * @since 1.18
+ */
+public class OclElementOclExtensionsOperation extends AbstractPolyOperation
+{
+	public static final @NonNull OclElementOclExtensionsOperation INSTANCE = new OclElementOclExtensionsOperation();
+
+	protected @NonNull SetValue createASorESvalues(@Nullable List<@NonNull ElementExtension> selectedExtensions, @NonNull CollectionTypeId collectionTypeId, boolean isAS) {
+		if (selectedExtensions == null) {
+			return ValueUtil.createSetOfEach(collectionTypeId);
+		}
+		else if (isAS) {
+			return ValueUtil.createSetValue(collectionTypeId, selectedExtensions);
+		}
+		else {
+			List<@NonNull EObject> esExtensions = new ArrayList<>(selectedExtensions.size());
+			for (@NonNull ElementExtension selectedExtension : selectedExtensions) {
+				EObject esObject = selectedExtension.getESObject();
+				assert esObject != null;
+				esExtensions.add(esObject);
+			}
+			return ValueUtil.createSetValue(collectionTypeId, esExtensions);
+		}
+	}
+
+	@Override
+	public @NonNull SetValue evaluate(@NonNull Executor executor, @NonNull TypeId returnTypeId, @Nullable Object sourceValue) {
+		assert sourceValue != null;
+		Element asSource = ValueUtil.getASorASofES(executor, Element.class, sourceValue);
+		List<@NonNull ElementExtension> selectedExtensions = ExtensionProperty.selectExtensions(executor, null, asSource);
+		return createASorESvalues(selectedExtensions, (CollectionTypeId)returnTypeId, asSource == sourceValue);
+	}
+
+	@Override
+	public @Nullable Object evaluate(@NonNull Executor executor, @NonNull TypeId returnTypeId,
+			@Nullable Object sourceValue, @Nullable Object stereotypeValue) {
+		assert sourceValue != null;
+		Element asSource = ValueUtil.getASorASofES(executor, Element.class, sourceValue);
+		Stereotype asStereotype = stereotypeValue != null ? ValueUtil.getASorASofES(executor, Stereotype.class, stereotypeValue) : null;
+		List<@NonNull ElementExtension> selectedExtensions = ExtensionProperty.selectExtensions(executor, asStereotype, asSource);
+		return createASorESvalues(selectedExtensions, (CollectionTypeId)returnTypeId, asSource == sourceValue);
+	}
+
+	@Override
+	public @Nullable Object evaluate(@NonNull Executor executor, @NonNull TypeId returnTypeId,
+			@Nullable Object sourceValue, @Nullable Object firstArgumentValue, @Nullable Object secondArgumentValue) {
+		throw new InvalidValueException("too many arguments for oclExtensions()");
+	}
+}
diff --git a/plugins/org.eclipse.ocl.pivot/src/org/eclipse/ocl/pivot/utilities/PivotUtil.java b/plugins/org.eclipse.ocl.pivot/src/org/eclipse/ocl/pivot/utilities/PivotUtil.java
index 7484497..09869f1f 100644
--- a/plugins/org.eclipse.ocl.pivot/src/org/eclipse/ocl/pivot/utilities/PivotUtil.java
+++ b/plugins/org.eclipse.ocl.pivot/src/org/eclipse/ocl/pivot/utilities/PivotUtil.java
@@ -54,6 +54,7 @@
 import org.eclipse.ocl.pivot.Constraint;
 import org.eclipse.ocl.pivot.DataType;
 import org.eclipse.ocl.pivot.Element;
+import org.eclipse.ocl.pivot.ElementExtension;
 import org.eclipse.ocl.pivot.EnumLiteralExp;
 import org.eclipse.ocl.pivot.Enumeration;
 import org.eclipse.ocl.pivot.EnumerationLiteral;
@@ -1514,6 +1515,13 @@
 	}
 
 	/**
+	 * @since 1.18
+	 */
+	public static @NonNull Iterable<@NonNull ElementExtension> getOwnedExtensions(Element asElement) {
+		return ClassUtil.nullFree(asElement.getOwnedExtensions());
+	}
+
+	/**
 	 * @since 1.3
 	 */
 	public static @NonNull OCLExpression getOwnedFirst(@NonNull CollectionRange collectionRange) {
diff --git a/plugins/org.eclipse.ocl.pivot/src/org/eclipse/ocl/pivot/utilities/ValueUtil.java b/plugins/org.eclipse.ocl.pivot/src/org/eclipse/ocl/pivot/utilities/ValueUtil.java
index 20d6682..fe3fdec 100644
--- a/plugins/org.eclipse.ocl.pivot/src/org/eclipse/ocl/pivot/utilities/ValueUtil.java
+++ b/plugins/org.eclipse.ocl.pivot/src/org/eclipse/ocl/pivot/utilities/ValueUtil.java
@@ -30,8 +30,10 @@
 import org.eclipse.jdt.annotation.Nullable;
 import org.eclipse.ocl.pivot.CollectionType;
 import org.eclipse.ocl.pivot.Element;
+import org.eclipse.ocl.pivot.ElementExtension;
 import org.eclipse.ocl.pivot.EnumerationLiteral;
 import org.eclipse.ocl.pivot.MapType;
+import org.eclipse.ocl.pivot.Stereotype;
 import org.eclipse.ocl.pivot.TemplateParameters;
 import org.eclipse.ocl.pivot.Type;
 import org.eclipse.ocl.pivot.evaluation.EvaluationVisitor;
@@ -46,6 +48,7 @@
 import org.eclipse.ocl.pivot.ids.TupleTypeId;
 import org.eclipse.ocl.pivot.ids.TypeId;
 import org.eclipse.ocl.pivot.internal.resource.StandaloneProjectMap;
+import org.eclipse.ocl.pivot.internal.utilities.EnvironmentFactoryInternal.EnvironmentFactoryInternalExtension;
 import org.eclipse.ocl.pivot.internal.values.BagImpl;
 import org.eclipse.ocl.pivot.internal.values.BagValueImpl;
 import org.eclipse.ocl.pivot.internal.values.BigIntegerValueImpl;
@@ -183,6 +186,18 @@
 		}
 	}
 
+	/**
+	 * @since 1.18
+	 */
+	public static @NonNull ElementExtension asElementExtension(@Nullable Object value) {
+		if (value instanceof ElementExtension) {
+			return (ElementExtension)value;
+		}
+		else {
+			throw new InvalidValueException(PivotMessages.TypedValueRequired, "ElementExtension", getTypeName(value));
+		}
+	}
+
 	public static @NonNull Integer asInteger(@Nullable Object value) {
 		if (value instanceof Value) {
 			return ((Value)value).asInteger();
@@ -335,6 +350,18 @@
 		}
 	}
 
+	/**
+	 * @since 1.18
+	 */
+	public static @NonNull Stereotype asStereotype(@Nullable Object value) {
+		if (value instanceof Stereotype) {
+			return (Stereotype)value;
+		}
+		else {
+			throw new InvalidValueException(PivotMessages.TypedValueRequired, "Stereotype", getTypeName(value));
+		}
+	}
+
 	public static @NonNull String asString(@Nullable Object value) {
 		if (value instanceof String) {
 			return (String)value;
@@ -707,6 +734,30 @@
 		}
 	}
 
+	/**
+	 * If value is a jClass AS value return it as is, else return the jClass counterpart of the ES value.
+	 *
+	 * @since 1.18
+	 */
+	public static <T extends Element> @NonNull T getASorASofES(@NonNull Executor executor, @NonNull Class<T> jClass, @NonNull Object value) {
+		/* if (value == null) {
+			return null;
+		}
+		else */ if (jClass.isAssignableFrom(value.getClass())) {
+			@SuppressWarnings("unchecked")
+			T castValue = (T)value;
+			return castValue;
+		}
+		else {
+			try {
+				EnvironmentFactoryInternalExtension environmentFactory = (EnvironmentFactoryInternalExtension)executor.getEnvironmentFactory();
+				return ClassUtil.nonNullState(environmentFactory.getASOf(jClass, (EObject)value));
+			} catch (Throwable e) {
+				throw new InvalidValueException(e, "Failed to access AS of " + value);
+			}
+		}
+	}
+
 	public static @NonNull String getElementIdName(@NonNull ElementId elementId) {
 		String name = elementId.toString();
 		if (name.startsWith(METAMODEL_NAME_PREFIX)) {