diff --git a/exist-core/src/main/java/org/exist/xquery/ContextItemExpression.java b/exist-core/src/main/java/org/exist/xquery/ContextItemExpression.java
index 23d18223b70..a67e7efb8ae 100644
--- a/exist-core/src/main/java/org/exist/xquery/ContextItemExpression.java
+++ b/exist-core/src/main/java/org/exist/xquery/ContextItemExpression.java
@@ -29,8 +29,6 @@
public class ContextItemExpression extends LocationStep {
- private int returnType = Type.ITEM;
-
public ContextItemExpression(final XQueryContext context) {
// TODO: create class AnyItemTest (one private implementation found in saxon)
super(context, Constants.SELF_AXIS, new AnyNodeTest());
@@ -40,7 +38,7 @@ public ContextItemExpression(final XQueryContext context) {
public void analyze(AnalyzeContextInfo contextInfo) throws XPathException {
contextInfo.addFlag(DOT_TEST);
// set return type to static type to allow for index use in optimization step
- returnType = contextInfo.getStaticType();
+ staticReturnType = contextInfo.getStaticType();
super.analyze(contextInfo);
}
@@ -69,7 +67,8 @@ public Sequence eval(final Sequence contextSequence, final Item contextItem) thr
@Override
public int returnsType() {
- return returnType;
+ // "." will have the same type as the parent expression
+ return staticReturnType;
}
@Override
diff --git a/exist-core/src/main/java/org/exist/xquery/LocationStep.java b/exist-core/src/main/java/org/exist/xquery/LocationStep.java
index e902a369b53..624795add20 100644
--- a/exist-core/src/main/java/org/exist/xquery/LocationStep.java
+++ b/exist-core/src/main/java/org/exist/xquery/LocationStep.java
@@ -263,40 +263,61 @@ public void analyze(final AnalyzeContextInfo contextInfo) throws XPathException
this.axis = Constants.DESCENDANT_AXIS;
}
+ final Expression contextStep;
+ final NodeTest stepTest;
+ final NodeTest contextStepTest;
+
// static analysis for empty-sequence
switch (axis) {
case Constants.SELF_AXIS:
- if (getTest().getType() != Type.NODE) {
- final Expression contextStep = contextInfo.getContextStep();
- if (contextStep instanceof LocationStep cStep) {
-
- // WM: the following checks will only work on simple filters like //a[self::b], so we
- // have to make sure they are not applied to more complex expression types
- if (parent.getSubExpressionCount() == 1 && !Type.subTypeOf(getTest().getType(), cStep.getTest().getType())) {
- throw new XPathException(this,
- ErrorCodes.XPST0005, "Got nothing from self::" + getTest() + ", because parent node kind " + Type.getTypeName(cStep.getTest().getType()));
- }
+ if (getTest().getType() == Type.NODE) {
+ break;
+ }
- if (parent.getSubExpressionCount() == 1 && !(cStep.getTest().isWildcardTest() || getTest().isWildcardTest()) && !cStep.getTest().equals(getTest())) {
- throw new XPathException(this,
- ErrorCodes.XPST0005, "Self::" + getTest() + " called on set of nodes which do not contain any nodes of this name.");
- }
- }
+ // WM: the following checks will only work on simple filters like //a[self::b], so we
+ // have to make sure they are not applied to more complex expression types
+ if (parent.getSubExpressionCount() > 1) {
+ break;
+ }
+
+ contextStep = contextInfo.getContextStep();
+ if (!(contextStep instanceof LocationStep cStep)) {
+ break;
+ }
+
+ stepTest = getTest();
+ contextStepTest = cStep.getTest();
+
+ if (!Type.subTypeOf(stepTest.getType(), contextStepTest.getType())) {
+ // return empty sequence
+ contextInfo.setStaticType(Type.EMPTY_SEQUENCE);
+ staticReturnType = Type.EMPTY_SEQUENCE;
+ break;
+ }
+
+ if (!stepTest.isWildcardTest() &&
+ !contextStepTest.isWildcardTest() &&
+ !contextStepTest.equals(stepTest)) {
+ // return empty sequence
+ contextInfo.setStaticType(Type.EMPTY_SEQUENCE);
+ staticReturnType = Type.EMPTY_SEQUENCE;
}
break;
-// case Constants.DESCENDANT_AXIS:
+// case Constants.DESCENDANT_AXIS:
case Constants.DESCENDANT_SELF_AXIS:
- final Expression contextStep = contextInfo.getContextStep();
- if (contextStep instanceof LocationStep cStep) {
-
- if ((
- cStep.getTest().getType() == Type.ATTRIBUTE ||
- cStep.getTest().getType() == Type.TEXT
- )
- && cStep.getTest() != getTest()) {
- throw new XPathException(this,
- ErrorCodes.XPST0005, "Descendant-or-self::" + getTest() + " from an attribute gets nothing.");
- }
+ contextStep = contextInfo.getContextStep();
+ if (!(contextStep instanceof LocationStep cStep)) {
+ break;
+ }
+
+ stepTest = getTest();
+ contextStepTest = cStep.getTest();
+
+ if ((contextStepTest.getType() == Type.ATTRIBUTE || contextStepTest.getType() == Type.TEXT) &&
+ contextStepTest != stepTest) {
+ // return empty sequence
+ contextInfo.setStaticType(Type.EMPTY_SEQUENCE);
+ staticReturnType = Type.EMPTY_SEQUENCE;
}
break;
// case Constants.PARENT_AXIS:
diff --git a/exist-core/src/test/xquery/no-static-typing.xqm b/exist-core/src/test/xquery/no-static-typing.xqm
new file mode 100644
index 00000000000..200cfc9fda1
--- /dev/null
+++ b/exist-core/src/test/xquery/no-static-typing.xqm
@@ -0,0 +1,66 @@
+(:
+ : eXist-db Open Source Native XML Database
+ : Copyright (C) 2001 The eXist-db Authors
+ :
+ : info@exist-db.org
+ : http://www.exist-db.org
+ :
+ : This library is free software; you can redistribute it and/or
+ : modify it under the terms of the GNU Lesser General Public
+ : License as published by the Free Software Foundation; either
+ : version 2.1 of the License, or (at your option) any later version.
+ :
+ : This library is distributed in the hope that it will be useful,
+ : but WITHOUT ANY WARRANTY; without even the implied warranty of
+ : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ : Lesser General Public License for more details.
+ :
+ : You should have received a copy of the GNU Lesser General Public
+ : License along with this library; if not, write to the Free Software
+ : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ :)
+xquery version "3.1";
+
+(:
+ : Tests created for issue https://github.com/exist-db/exist/issues/2445
+ :)
+module namespace tnst="http://exist-db.org/xquery/test/no-static-typing";
+
+import module namespace test="http://exist-db.org/xquery/xqsuite" at "resource:org/exist/xquery/lib/xqsuite/xqsuite.xql";
+
+declare
+ %test:assertEmpty
+function tnst:self-other-node-name() {
+ [self::b]
+};
+
+declare
+ %test:assertEmpty
+function tnst:element-after-attribute() {
+ /@b/c
+};
+
+declare
+ %test:assertEmpty
+function tnst:element-after-text() {
+ /text()/b
+};
+
+declare
+ %test:assertEmpty
+function tnst:descendant-or-self-other-node-name() {
+ [descendant-or-self::b]
+};
+
+declare
+ %test:assertEmpty
+function tnst:element-after-descendant-or-self-attribute() {
+ /descendant-or-self::attribute(b)/c
+};
+
+declare
+ %test:assertEmpty
+function tnst:element-after-descendant-or-self-text() {
+ /descendant-or-self::text()/b
+};
+