From 17259fcc1f77242c147df9369613a2625c817c0c Mon Sep 17 00:00:00 2001 From: ParsleyJ Date: Fri, 21 Apr 2023 13:25:40 +0200 Subject: [PATCH] fix bug that prevented correct subtyping in the message type hierarchy --- .../tests/GuideToTestJadeScript.xtend | 15 ++- .../TestDuplicatesCheckInValidator.xtend | 6 ++ .../jadescript/tests/TypeInferrerTests.xtend | 63 +++++++++++++ .../jadescript/JadescriptRuntimeModule.java | 2 + .../expression/TypeExpressionSemantics.java | 14 ++- .../index/BuiltinTypeProvider.java | 9 +- .../jadescripttypes/index/TypeIndex.java | 28 +++--- .../jadescripttypes/index/TypeSolver.java | 30 ++---- .../jadescripttypes/util/AnyMessageType.java | 92 ------------------- .../util/AnyOntologyElementType.java | 4 +- .../Tests/src/tests/context/ContextTests.jade | 5 +- 11 files changed, 132 insertions(+), 136 deletions(-) delete mode 100644 Jadescript/it.unipr.ailab.jadescript/src/it/unipr/ailab/jadescript/semantics/jadescripttypes/util/AnyMessageType.java diff --git a/Jadescript/it.unipr.ailab.jadescript.tests/src/it/unipr/ailab/jadescript/tests/GuideToTestJadeScript.xtend b/Jadescript/it.unipr.ailab.jadescript.tests/src/it/unipr/ailab/jadescript/tests/GuideToTestJadeScript.xtend index 792f8d4..027252b 100644 --- a/Jadescript/it.unipr.ailab.jadescript.tests/src/it/unipr/ailab/jadescript/tests/GuideToTestJadeScript.xtend +++ b/Jadescript/it.unipr.ailab.jadescript.tests/src/it/unipr/ailab/jadescript/tests/GuideToTestJadeScript.xtend @@ -16,7 +16,14 @@ import org.junit.Assert import org.junit.Test import org.junit.runner.RunWith import org.eclipse.xtext.testing.validation.ValidationTestHelper +import org.junit.Before +import org.eclipse.xtext.util.JavaVersion +/** + * Set of example tests (i.e., examples to help create new tests). + * Do not run, as they may fail on new Jadescript versions! + * Please run {@link TestSuite} to run all (valid) tests. + */ @RunWith(XtextRunner) @InjectWith(JadescriptInjectorProvider) class GuideToTestJadeScript { @@ -24,8 +31,12 @@ class GuideToTestJadeScript { ParseHelper parseHelper @Inject extension ValidationTestHelper @Inject extension ReflectExtensions - @Inject extension CompilationTestHelper @Inject extension ParseHelper + @Inject extension CompilationTestHelper + @Before + public def setJavaVersion() { + javaVersion = JavaVersion.JAVA11 + } boolean parsingError @@ -62,7 +73,7 @@ class GuideToTestJadeScript { '''.parse.assertNoIssues } - // 3) Test you correctly generated Java code + // 3) Test that the compiler correctly generated Java code @Test def void testGeneratedJavaCode() { ''' diff --git a/Jadescript/it.unipr.ailab.jadescript.tests/src/it/unipr/ailab/jadescript/tests/TestDuplicatesCheckInValidator.xtend b/Jadescript/it.unipr.ailab.jadescript.tests/src/it/unipr/ailab/jadescript/tests/TestDuplicatesCheckInValidator.xtend index 33ec651..9fe4f5c 100644 --- a/Jadescript/it.unipr.ailab.jadescript.tests/src/it/unipr/ailab/jadescript/tests/TestDuplicatesCheckInValidator.xtend +++ b/Jadescript/it.unipr.ailab.jadescript.tests/src/it/unipr/ailab/jadescript/tests/TestDuplicatesCheckInValidator.xtend @@ -9,6 +9,8 @@ import org.eclipse.xtext.xbase.testing.CompilationTestHelper import com.google.inject.Inject import org.junit.Test import org.junit.Assert +import org.junit.Before +import org.eclipse.xtext.util.JavaVersion /* * Tests to check if the validator correctly flags duplicate elements (variables, features, top-elements) as errors. @@ -20,6 +22,10 @@ class TestDuplicatesCheckInValidator { @Inject ParseHelper parseHelper @Inject extension CompilationTestHelper + @Before + public def setJavaVersion() { + javaVersion = JavaVersion.JAVA11 + } // Agent: test duplicate fields (check only parsing) @Test diff --git a/Jadescript/it.unipr.ailab.jadescript.tests/src/it/unipr/ailab/jadescript/tests/TypeInferrerTests.xtend b/Jadescript/it.unipr.ailab.jadescript.tests/src/it/unipr/ailab/jadescript/tests/TypeInferrerTests.xtend index 440529d..a4ad324 100644 --- a/Jadescript/it.unipr.ailab.jadescript.tests/src/it/unipr/ailab/jadescript/tests/TypeInferrerTests.xtend +++ b/Jadescript/it.unipr.ailab.jadescript.tests/src/it/unipr/ailab/jadescript/tests/TypeInferrerTests.xtend @@ -9,6 +9,8 @@ import org.eclipse.xtext.xbase.testing.CompilationTestHelper import com.google.inject.Inject import org.junit.Test import org.junit.Assert +import org.junit.Before +import org.eclipse.xtext.util.JavaVersion /* * Tests to check if the validator correctly flags duplicate elements (variables, features, top-elements) as errors. @@ -20,6 +22,10 @@ class TypeInferrerTests { @Inject ParseHelper parseHelper @Inject extension CompilationTestHelper + @Before + public def setJavaVersion() { + javaVersion = JavaVersion.JAVA11 + } @@ -128,4 +134,61 @@ class TypeInferrerTests { ] } + @Test + def void testMessageSubtyping(){ + ''' + module exampl + ontology JustAnAction + action TheAction + + cyclic behaviour WaitingARequest + uses ontology JustAnAction + + on message request TheAction do + log f1(message) + log f2(message) + + function f1(m as RequestMessage of TheAction) as text do + return f2(m) + + function f2(m as Message of TheAction) as text do + return (performative of m) as text + '''.compile[ + var msg = "" + if(!errorsAndWarnings.isNullOrEmpty){ + msg = errorsAndWarnings.get(0).message + } + Assert.assertTrue(msg, errorsAndWarnings.isNullOrEmpty) + ] + } + + @Test + def void testMessageSubtypingError(){ + // inverted the type relationships of the arguments of f1 and f2 + ''' + module exampl + ontology JustAnAction + action TheAction + + cyclic behaviour WaitingARequest + uses ontology JustAnAction + + on message request TheAction do + log f1(message) + log f2(message) + + function f1(m as Message of TheAction) as text do + return f2(m) + + function f2(m as RequestMessage of TheAction) as text do + return (performative of m) as text + '''.compile[ + var msg = "" + if(!errorsAndWarnings.isNullOrEmpty){ + msg = errorsAndWarnings.get(0).message + } + Assert.assertFalse(msg, errorsAndWarnings.isNullOrEmpty) + ] + } + } diff --git a/Jadescript/it.unipr.ailab.jadescript/src/it/unipr/ailab/jadescript/JadescriptRuntimeModule.java b/Jadescript/it.unipr.ailab.jadescript/src/it/unipr/ailab/jadescript/JadescriptRuntimeModule.java index ef8226d..c3c7954 100644 --- a/Jadescript/it.unipr.ailab.jadescript/src/it/unipr/ailab/jadescript/JadescriptRuntimeModule.java +++ b/Jadescript/it.unipr.ailab.jadescript/src/it/unipr/ailab/jadescript/JadescriptRuntimeModule.java @@ -36,5 +36,7 @@ public void configureIScopeProviderDelegate(final Binder binder) { .annotatedWith(Names.named(AbstractDeclarativeScopeProvider.NAMED_DELEGATE)) .to(XImportSectionNamespaceScopeProvider.class); } + + } diff --git a/Jadescript/it.unipr.ailab.jadescript/src/it/unipr/ailab/jadescript/semantics/expression/TypeExpressionSemantics.java b/Jadescript/it.unipr.ailab.jadescript/src/it/unipr/ailab/jadescript/semantics/expression/TypeExpressionSemantics.java index 2b20e1c..5c95db5 100644 --- a/Jadescript/it.unipr.ailab.jadescript/src/it/unipr/ailab/jadescript/semantics/expression/TypeExpressionSemantics.java +++ b/Jadescript/it.unipr.ailab.jadescript/src/it/unipr/ailab/jadescript/semantics/expression/TypeExpressionSemantics.java @@ -279,6 +279,7 @@ private IJadescriptType getMessageType( final TypeSolver typeSolver = module.get(TypeSolver.class); final BuiltinTypeProvider builtins = module.get(BuiltinTypeProvider.class); + final Maybe baseTypeName = messageTypeMaybe.__(MessageType::getBaseType); final IJadescriptType contentType = @@ -290,13 +291,20 @@ private IJadescriptType getMessageType( final List contentTypes; if (!isExplicitContentType) { - contentTypes = - typeSolver.getDefaultTypeArguments(baseTypeName.toNullable()); + + if(baseTypeName.wrappedEquals("Message")){ //TODO + return builtins.anyMessage(); + } + + contentTypes = typeSolver.getDefaultTypeArguments( + baseTypeName.toNullable() + ); } else { contentTypes = typeHelper.unpackTuple(contentType); } + return baseTypeName - .__(typeSolver::getMessageTypeSchemaForPerformative) + .__(typeSolver::getMessageTypeSchemaForTypeName) .__(f -> { try { return f.create(contentTypes); diff --git a/Jadescript/it.unipr.ailab.jadescript/src/it/unipr/ailab/jadescript/semantics/jadescripttypes/index/BuiltinTypeProvider.java b/Jadescript/it.unipr.ailab.jadescript/src/it/unipr/ailab/jadescript/semantics/jadescripttypes/index/BuiltinTypeProvider.java index e604676..b9d8c69 100644 --- a/Jadescript/it.unipr.ailab.jadescript/src/it/unipr/ailab/jadescript/semantics/jadescripttypes/index/BuiltinTypeProvider.java +++ b/Jadescript/it.unipr.ailab.jadescript/src/it/unipr/ailab/jadescript/semantics/jadescripttypes/index/BuiltinTypeProvider.java @@ -27,6 +27,7 @@ import it.unipr.ailab.maybe.utils.LazyInit; import jade.core.AID; import jade.lang.acl.ACLMessage; +import jadescript.content.JadescriptOntoElement; import jadescript.core.message.*; import jadescript.java.AgentEnv; import jadescript.java.SideEffectsFlag; @@ -61,13 +62,13 @@ public class BuiltinTypeProvider { /*package-private*/ final LazyInit tVoid = fromModule(JavaVoidType.class); - @BuiltinType + @BuiltinType(JadescriptOntoElement.class) /*package-private*/ final LazyInit tAnyOntologyElement = fromModule(AnyOntologyElementType.class); @BuiltinType - /*package-private*/ final LazyInit tAnyMessage = - fromModule(AnyMessageType.class); + /*package-private*/ final LazyInit tAnyMessage = + lazyInit(() -> message(covariant(anyOntologyElement()))); @BuiltinType(Number.class) /*package-private*/ final LazyInit tNumber = @@ -1923,7 +1924,7 @@ public AnyOntologyElementType anyOntologyElement() { } - public AnyMessageType anyMessage() { + public BaseMessageType anyMessage() { return tAnyMessage.get(); } diff --git a/Jadescript/it.unipr.ailab.jadescript/src/it/unipr/ailab/jadescript/semantics/jadescripttypes/index/TypeIndex.java b/Jadescript/it.unipr.ailab.jadescript/src/it/unipr/ailab/jadescript/semantics/jadescripttypes/index/TypeIndex.java index 9735dfe..6e4cc5d 100644 --- a/Jadescript/it.unipr.ailab.jadescript/src/it/unipr/ailab/jadescript/semantics/jadescripttypes/index/TypeIndex.java +++ b/Jadescript/it.unipr.ailab.jadescript/src/it/unipr/ailab/jadescript/semantics/jadescripttypes/index/TypeIndex.java @@ -78,7 +78,7 @@ private void doInitialize() { continue; } - if(!Supplier.class.isAssignableFrom(declaredField.getType())){ + if (!Supplier.class.isAssignableFrom(declaredField.getType())) { throw new RuntimeException("Wrong type of the builtin-type " + "field '" + declaredField.getName() + "'."); } @@ -141,11 +141,17 @@ private void registerBuiltinParametricType( @Nullable MessageBuiltinType messageAnnotation ) { for (Class jvmClass : builtinTypeAnnotation.value()) { + final JvmTypeReference typeRef = + jvmTypeHelper.get().typeRef(jvmClass); final String fqn = JvmTypeHelper.noGenericsTypeName( - jvmTypeHelper.get().typeRef(jvmClass) - .getQualifiedName('.') + typeRef.getQualifiedName('.') ); + final String simpleName = JvmTypeHelper.noGenericsTypeName( + typeRef.getSimpleName() + ); + + try { final Supplier> parametricTypeSchemaSupplier = @@ -164,7 +170,7 @@ private void registerBuiltinParametricType( final Performative performative = Performative.fromCode(messageAnnotation.value()); - messageClassToPerformativeMap.put(fqn, performative); + messageClassToPerformativeMap.put(simpleName, performative); performativeToMessageSubtypeMap.put( performative, Utils.castSupplier(parametricTypeSchemaSupplier) @@ -186,7 +192,7 @@ private boolean isPackagePrivate(Field field) { } - private void initializeIfNecessary() { + private void initializeIfRequired() { if (!this.initialized) { doInitialize(); } @@ -195,7 +201,7 @@ private void initializeIfNecessary() { /*package-private*/ Map> getTypeTable() { - initializeIfNecessary(); + initializeIfRequired(); return this.typeTable; } @@ -204,14 +210,14 @@ private void initializeIfNecessary() { String, Supplier> > getParametricTypeTable() { - initializeIfNecessary(); + initializeIfRequired(); return this.parametricTypeTable; } /*package-private*/ Map getMessageClassToPerformativeMap() { - initializeIfNecessary(); + initializeIfRequired(); return messageClassToPerformativeMap; } @@ -219,13 +225,13 @@ > getParametricTypeTable() { /*package-private*/ Map< Performative, Supplier> > getPerformativeToMessageSubtypeMap() { - initializeIfNecessary(); + initializeIfRequired(); return performativeToMessageSubtypeMap; } /*package-private*/ Map getExpectedTypeParameters() { - initializeIfNecessary(); + initializeIfRequired(); return expectedTypeParameters; } @@ -234,7 +240,7 @@ public void store( JvmTypeReference input, IJadescriptType output ) { - initializeIfNecessary(); + initializeIfRequired(); typeTable.put( input.getQualifiedName('.'), () -> output diff --git a/Jadescript/it.unipr.ailab.jadescript/src/it/unipr/ailab/jadescript/semantics/jadescripttypes/index/TypeSolver.java b/Jadescript/it.unipr.ailab.jadescript/src/it/unipr/ailab/jadescript/semantics/jadescripttypes/index/TypeSolver.java index d1a989e..a3db713 100644 --- a/Jadescript/it.unipr.ailab.jadescript/src/it/unipr/ailab/jadescript/semantics/jadescripttypes/index/TypeSolver.java +++ b/Jadescript/it.unipr.ailab.jadescript/src/it/unipr/ailab/jadescript/semantics/jadescripttypes/index/TypeSolver.java @@ -413,32 +413,18 @@ public IJadescriptType fromJvmTypePermissive( public ParametricTypeSchema - getMessageTypeSchemaForPerformative( - String performative - ) { + getMessageTypeSchemaForTypeName(String messageTypeName) { return getMessageTypeSchemaForPerformative( - index.getMessageClassToPerformativeMap().get(performative) + index.getMessageClassToPerformativeMap().get(messageTypeName) ); } @SuppressWarnings("unchecked") - public List getDefaultTypeArguments( - String name - ) { - if (name.equals("Message")) { - return List.of(builtinTypes.any( - "There are no type upper bounds for the content " + - "of a message of root type Message." - )); + public List getDefaultTypeArguments(String messageTypeName) { - } - final Performative performative = - index.getMessageClassToPerformativeMap().get(name); - - if (performative == null) { - return List.of(); - } + final @Nullable Performative performative = + index.getMessageClassToPerformativeMap().get(messageTypeName); final IJadescriptType contentBound = getContentBoundForPerformative(performative); @@ -453,8 +439,12 @@ public List getDefaultTypeArguments( public IJadescriptType getContentBoundForPerformative( - Performative performative + @Nullable Performative performative ) { + if(performative == null){ + return builtinTypes.any(""); + } + final List upperBounds = index.getPerformativeToMessageSubtypeMap().get(performative) .get().getUpperBounds(); diff --git a/Jadescript/it.unipr.ailab.jadescript/src/it/unipr/ailab/jadescript/semantics/jadescripttypes/util/AnyMessageType.java b/Jadescript/it.unipr.ailab.jadescript/src/it/unipr/ailab/jadescript/semantics/jadescripttypes/util/AnyMessageType.java deleted file mode 100644 index ced7d53..0000000 --- a/Jadescript/it.unipr.ailab.jadescript/src/it/unipr/ailab/jadescript/semantics/jadescripttypes/util/AnyMessageType.java +++ /dev/null @@ -1,92 +0,0 @@ -package it.unipr.ailab.jadescript.semantics.jadescripttypes.util; - -import it.unipr.ailab.jadescript.semantics.SemanticsModule; -import it.unipr.ailab.jadescript.semantics.helpers.JvmTypeHelper; -import it.unipr.ailab.jadescript.semantics.helpers.TypeHelper; -import it.unipr.ailab.jadescript.semantics.jadescripttypes.IJadescriptType; -import it.unipr.ailab.jadescript.semantics.jadescripttypes.id.TypeCategory; -import it.unipr.ailab.jadescript.semantics.jadescripttypes.id.TypeCategoryAdapter; -import it.unipr.ailab.jadescript.semantics.jadescripttypes.index.BuiltinTypeProvider; -import it.unipr.ailab.jadescript.semantics.jadescripttypes.message.MessageType; -import it.unipr.ailab.jadescript.semantics.jadescripttypes.ontology.OntologyType; -import it.unipr.ailab.jadescript.semantics.namespace.MessageTypeNamespace; -import it.unipr.ailab.maybe.Maybe; -import jadescript.core.message.Message; - -import static it.unipr.ailab.maybe.Maybe.some; - -public class AnyMessageType extends UtilityType implements MessageType { - - - public AnyMessageType(SemanticsModule module) { - super( - module, - TypeHelper.builtinPrefix + "ANYMESSAGE", - "Message", - module.get(JvmTypeHelper.class).typeRef(Message.class) - ); - } - - - - - @Override - public boolean isErroneous() { - return false; - } - - - @Override - public Maybe getDeclaringOntology() { - return some(module.get(BuiltinTypeProvider.class).ontology()); - } - - - @Override - public IJadescriptType getContentType() { - return module.get(BuiltinTypeProvider.class).anyOntologyElement(); - } - - - @Override - public MessageTypeNamespace namespace() { - return MessageTypeNamespace.messageTypeNamespace( - module, - module.get(TypeHelper.class).covariant( - module.get(BuiltinTypeProvider.class).anyOntologyElement() - ), - getLocation() - ); - } - - - @Override - public TypeCategory category() { - return new TypeCategoryAdapter() { - @Override - public boolean isMessage() { - return true; - } - }; - } - - - @Override - public boolean isSendable() { - return true; - } - - - @Override - public String compileNewEmptyInstance() { - return "new jadescript.core.message.Message<>(" + - "jadescript.lang.Performative.UNKNOWN)"; - } - - - @Override - public boolean requiresAgentEnvParameter() { - return false; - } - -} diff --git a/Jadescript/it.unipr.ailab.jadescript/src/it/unipr/ailab/jadescript/semantics/jadescripttypes/util/AnyOntologyElementType.java b/Jadescript/it.unipr.ailab.jadescript/src/it/unipr/ailab/jadescript/semantics/jadescripttypes/util/AnyOntologyElementType.java index 7df382f..758aba7 100644 --- a/Jadescript/it.unipr.ailab.jadescript/src/it/unipr/ailab/jadescript/semantics/jadescripttypes/util/AnyOntologyElementType.java +++ b/Jadescript/it.unipr.ailab.jadescript/src/it/unipr/ailab/jadescript/semantics/jadescripttypes/util/AnyOntologyElementType.java @@ -35,8 +35,8 @@ private AnyOntologyElementType( ) { super( module, - TypeHelper.builtinPrefix + "serializable", - typeRef.getQualifiedName('.'), + TypeHelper.builtinPrefix + "ANY_ONTO_ELEMENT", + "«any ontology element»", typeRef ); } diff --git a/runtime-EclipseXtext/Tests/src/tests/context/ContextTests.jade b/runtime-EclipseXtext/Tests/src/tests/context/ContextTests.jade index f850cb4..51e4349 100644 --- a/runtime-EclipseXtext/Tests/src/tests/context/ContextTests.jade +++ b/runtime-EclipseXtext/Tests/src/tests/context/ContextTests.jade @@ -6,6 +6,7 @@ ontology SuperOntology ontology MyOntology extends SuperOntology concept MyConcept extends SuperConcept + action MyAction agent SuperAgent uses ontology MyOntology @@ -21,7 +22,7 @@ agent MyAgent extends SuperAgent on create do log sax - log __dt__ say + log say log ax activate MyBehaviour @@ -46,7 +47,7 @@ one shot behaviour MyBehaviour extends SuperBehaviour property bx = inform function by as performative do return cfp - + on execute do log __dt__ SuperConcept log __dt__ MyConcept