From 2cca448105dc5cfa2e4117f724b3905a6e1fc82c Mon Sep 17 00:00:00 2001 From: Graham Nelson Date: Sun, 17 Nov 2024 22:56:07 +0000 Subject: [PATCH] Fixed Jira bug I7-2275 --- docs/basic_inform/S-pd.html | 22 +-- docs/building-module/2-is.html | 3 + docs/building-module/2-tkn.html | 6 + docs/imperative-module/2-cv.html | 2 +- docs/imperative-module/4-cp.html | 4 +- docs/imperative-module/5-ca.html | 2 +- docs/imperative-module/5-cii.html | 140 +++++++++++++----- docs/knowledge-module/3-spr2.html | 1 - inform7/Figures/memory-diagnostics.txt | 14 +- inform7/Figures/timings-diagnostics.txt | 12 +- .../Basic Inform.i7xd/Source/Basic Inform.i7x | 22 +-- .../Tests/Test Cases/ContainmentScanning.txt | 6 +- .../PM_RelationDomainWrongKind--I.txt | 11 ++ .../PM_RelationDomainWrongKind.txt | 14 ++ .../Sections/Phrase Definitions.w | 22 +-- .../Chapter 5/Compile Invocations Inline.w | 56 +++++++ .../Chapter 3/Setting Property Relation.w | 1 - .../building-module/Chapter 2/Inter Schemas.w | 3 + .../building-module/Chapter 2/Tokenisation.w | 6 + .../Examples/RelevantRelations.txt | 6 +- 20 files changed, 262 insertions(+), 91 deletions(-) create mode 100644 inform7/Tests/Test Problems/PM_RelationDomainWrongKind--I.txt create mode 100644 inform7/Tests/Test Problems/PM_RelationDomainWrongKind.txt diff --git a/docs/basic_inform/S-pd.html b/docs/basic_inform/S-pd.html index a164cdceb7..be0853e8b9 100644 --- a/docs/basic_inform/S-pd.html +++ b/docs/basic_inform/S-pd.html @@ -1647,57 +1647,57 @@

To decide which list of Ks is list of (name of kind of value K) that/which/whom (R - relation of Ks to values of kind L) relates (documented at ph_leftdomain): - (- RelationTest({-by-reference:R}, RELS_LIST, {-new:list of K}, RLIST_ALL_X) -). + (- {-match-left-relation-domain:K:R}RelationTest({-by-reference:R}, RELS_LIST, {-new:list of K}, RLIST_ALL_X) -). To decide which list of Ls is list of (name of kind of value L) to which/whom (R - relation of values of kind K to Ls) relates (documented at ph_rightdomain): - (- RelationTest({-by-reference:R}, RELS_LIST, {-new:list of L}, RLIST_ALL_Y) -). + (- {-match-right-relation-domain:L:R}RelationTest({-by-reference:R}, RELS_LIST, {-new:list of L}, RLIST_ALL_Y) -). To decide which list of Ls is list of (name of kind of value L) that/which/whom (R - relation of values of kind K to Ls) relates to (documented at ph_rightdomain): - (- RelationTest({-by-reference:R}, RELS_LIST, {-new:list of L}, RLIST_ALL_Y) -). + (- {-match-right-relation-domain:L:R}RelationTest({-by-reference:R}, RELS_LIST, {-new:list of L}, RLIST_ALL_Y) -). To decide which list of Ks is list of (name of kind of value K) that/which/who relate to (Y - L) by (R - relation of Ks to values of kind L) (documented at ph_leftlookuplist): - (- RelationTest({-by-reference:R}, RELS_LOOKUP_ALL_X, {Y}, {-new:list of K}) -). + (- {-match-left-relation-domain:K:R}RelationTest({-by-reference:R}, RELS_LOOKUP_ALL_X, {Y}, {-new:list of K}) -). To decide which list of Ls is list of (name of kind of value L) to which/whom (X - K) relates by (R - relation of values of kind K to Ls) (documented at ph_rightlookuplist): - (- RelationTest({-by-reference:R}, RELS_LOOKUP_ALL_Y, {X}, {-new:list of L}) -). + (- {-match-right-relation-domain:L:R}RelationTest({-by-reference:R}, RELS_LOOKUP_ALL_Y, {X}, {-new:list of L}) -). To decide which list of Ls is list of (name of kind of value L) that/which/whom (X - K) relates to by (R - relation of values of kind K to Ls) (documented at ph_rightlookuplist): - (- RelationTest({-by-reference:R}, RELS_LOOKUP_ALL_Y, {X}, {-new:list of L}) -). + (- {-match-right-relation-domain:L:R}RelationTest({-by-reference:R}, RELS_LOOKUP_ALL_Y, {X}, {-new:list of L}) -). To decide whether (name of kind of value K) relates to (Y - L) by (R - relation of Ks to values of kind L) (documented at ph_ifright): - (- RelationTest({-by-reference:R}, RELS_LOOKUP_ANY, {Y}, RLANY_CAN_GET_X) -). + (- {-match-left-relation-domain:K:R}RelationTest({-by-reference:R}, RELS_LOOKUP_ANY, {Y}, RLANY_CAN_GET_X) -). To decide whether (X - K) relates to (name of kind of value L) by (R - relation of values of kind K to Ls) (documented at ph_ifleft): - (- RelationTest({-by-reference:R}, RELS_LOOKUP_ANY, {X}, RLANY_CAN_GET_Y) -). + (- {-match-right-relation-domain:L:R}RelationTest({-by-reference:R}, RELS_LOOKUP_ANY, {X}, RLANY_CAN_GET_Y) -). To decide which K is (name of kind of value K) that/which/who relates to (Y - L) by (R - relation of Ks to values of kind L) (documented at ph_leftlookup): - (- RelationTest({-by-reference:R}, RELS_LOOKUP_ANY, {Y}, RLANY_GET_X) -). + (- {-match-left-relation-domain:K:R}RelationTest({-by-reference:R}, RELS_LOOKUP_ANY, {Y}, RLANY_GET_X) -). To decide which L is (name of kind of value L) to which/whom (X - K) relates by (R - relation of values of kind K to Ls) (documented at ph_rightlookup): - (- RelationTest({-by-reference:R}, RELS_LOOKUP_ANY, {X}, RLANY_GET_Y) -). + (- {-match-right-relation-domain:L:R}RelationTest({-by-reference:R}, RELS_LOOKUP_ANY, {X}, RLANY_GET_Y) -). To decide which L is (name of kind of value L) that/which/whom (X - K) relates to by (R - relation of values of kind K to Ls) (documented at ph_rightlookup): - (- RelationTest({-by-reference:R}, RELS_LOOKUP_ANY, {X}, RLANY_GET_Y) -). + (- {-match-right-relation-domain:L:R}RelationTest({-by-reference:R}, RELS_LOOKUP_ANY, {X}, RLANY_GET_Y) -).

§49. Functional Programming. Here we have the ability to use the name of a function as a value, and to apply such a function. diff --git a/docs/building-module/2-is.html b/docs/building-module/2-is.html index c36ea63d80..514a20e070 100644 --- a/docs/building-module/2-is.html +++ b/docs/building-module/2-is.html @@ -413,6 +413,7 @@

enum indexing_routine_ISINC enum strong_kind_ISINC enum weak_kind_ISINC +enum object_kind_ISINC enum backspace_ISINC enum erase_ISINC enum open_brace_ISINC @@ -441,6 +442,8 @@

enum unprotect_ISINC enum copy_ISINC enum initialise_ISINC +enum match_right_relation_domain_ISINC +enum match_left_relation_domain_ISINC enum matches_description_ISINC enum now_matches_description_ISINC enum arithmetic_operation_ISINC diff --git a/docs/building-module/2-tkn.html b/docs/building-module/2-tkn.html index 14a12e0521..68917e3a0d 100644 --- a/docs/building-module/2-tkn.html +++ b/docs/building-module/2-tkn.html @@ -356,6 +356,8 @@

c = strong_kind_ISINC; } else if (Str::eq_wide_string(t->command, U"weak-kind")) { c = weak_kind_ISINC; + } else if (Str::eq_wide_string(t->command, U"object-kind")) { + c = object_kind_ISINC; } else if (Str::eq_wide_string(t->command, U"backspace")) { c = backspace_ISINC; } else if (Str::eq_wide_string(t->command, U"erase")) { @@ -414,6 +416,10 @@

c = initialise_ISINC; } else if (Str::eq_wide_string(t->command, U"matches-description")) { c = matches_description_ISINC; + } else if (Str::eq_wide_string(t->command, U"match-right-relation-domain")) { + c = match_right_relation_domain_ISINC; + } else if (Str::eq_wide_string(t->command, U"match-left-relation-domain")) { + c = match_left_relation_domain_ISINC; } else if (Str::eq_wide_string(t->command, U"now-matches-description")) { c = now_matches_description_ISINC; } else if (Str::eq_wide_string(t->command, U"arithmetic-operation")) { diff --git a/docs/imperative-module/2-cv.html b/docs/imperative-module/2-cv.html index c17712ab5a..5a3a4ca0e4 100644 --- a/docs/imperative-module/2-cv.html +++ b/docs/imperative-module/2-cv.html @@ -163,7 +163,7 @@

void CompileValues::to_code_val(parse_node *value) { CompileValues::to_code_val_inner(value, NULL, COMPILE_SPEC_AS_VALUE); } -void CompileValues::to_code_val_of_kind(parse_node *value, kind *K) { +void CompileValues::to_code_val_of_kind(parse_node *value, kind *K) { CompileValues::to_code_val_inner(value, K, COMPILE_SPEC_AS_VALUE); } void CompileValues::to_fresh_code_val_of_kind(parse_node *value, kind *K) { diff --git a/docs/imperative-module/4-cp.html b/docs/imperative-module/4-cp.html index f59449f81b..d288b93ced 100644 --- a/docs/imperative-module/4-cp.html +++ b/docs/imperative-module/4-cp.html @@ -270,7 +270,7 @@

-void CompilePropositions::to_make_true_about(pcalc_prop *prop, parse_node *t) {
+void CompilePropositions::to_make_true_about(pcalc_prop *prop, parse_node *t) {
     Binding::substitute_var_0_in(prop, t);
     TypecheckPropositions::type_check(prop,
         TypecheckPropositions::tc_no_problem_reporting());
@@ -354,7 +354,7 @@ 

internal_error("no way to compile this without deferral"); } -void CompilePropositions::to_test_if_matches(parse_node *in, parse_node *desc) { +void CompilePropositions::to_test_if_matches(parse_node *in, parse_node *desc) { if (Deferrals::defer_if_matches(in, desc)) return; internal_error("no way to compile this without deferral"); } diff --git a/docs/imperative-module/5-ca.html b/docs/imperative-module/5-ca.html index aebe503245..f8be850d30 100644 --- a/docs/imperative-module/5-ca.html +++ b/docs/imperative-module/5-ca.html @@ -77,7 +77,7 @@

-void CompileArithmetic::perform_arithmetic_emit(int op, equation *eqn,
+void CompileArithmetic::perform_arithmetic_emit(int op, equation *eqn,
     parse_node *X, equation_node *EX, kind *KX,
     parse_node *Y, equation_node *EY, kind *KY) {
     int binary = TRUE;
diff --git a/docs/imperative-module/5-cii.html b/docs/imperative-module/5-cii.html
index 09f467834c..4309cbd884 100644
--- a/docs/imperative-module/5-cii.html
+++ b/docs/imperative-module/5-cii.html
@@ -1004,6 +1004,7 @@ 

if (C == previous_routine_ISINC) Inline command "previous-routine"6.3.4; if (C == strong_kind_ISINC) Inline command "strong-kind"6.3.8; if (C == weak_kind_ISINC) Inline command "weak-kind"6.3.9; + if (C == object_kind_ISINC) Inline command "object-kind"6.3.10;

  • This code is used in §6.

§6.3.1. The following produces a new value of the given kind. If it's stored as a @@ -1141,6 +1142,21 @@

return;

+

§6.3.10. Inline command "object-kind"6.3.10 = +

+ +
+    kind *K = CSIInline::parse_bracing_operand_as_kind(ist->operand,
+        Node::get_kind_variable_declarations(inv));
+    if (K) {
+        if (Kinds::Behaviour::is_object(K))
+            EmitCode::val_iname(K_value, RTKindDeclarations::iname(K));
+        else
+            EmitCode::val_number(0);
+    } else Issue an inline no-such-kind problem6.3.1.2;
+    return;
+
+
  • This code is used in §6.3.

§6.3.1.2. Issue an inline no-such-kind problem6.3.1.2 =

@@ -1149,7 +1165,7 @@

ist->owner->parent_schema->converted_from, "I don't know any kind called '%4'."); - +

§6.4. Typographic commands. These rather clumsy commands are a residue from earlier forms of the markup language, really. {-open-brace} and {-close-brace} are handled for us elsewhere, so we need do nothing. The other two have actually been withdrawn. @@ -1361,11 +1377,13 @@

if (C == unprotect_ISINC) Inline command "unprotect"6.6.2; if (C == copy_ISINC) Inline command "copy"6.6.4; if (C == initialise_ISINC) Inline command "initialise"6.6.3; - if (C == matches_description_ISINC) Inline command "matches-description"6.6.5; - if (C == now_matches_description_ISINC) Inline command "now-matches-description"6.6.6; - if (C == arithmetic_operation_ISINC) Inline command "arithmetic-operation"6.6.7; - if (C == say_ISINC) Inline command "say"6.6.8; - if (C == show_me_ISINC) Inline command "show-me"6.6.9; + if (C == match_right_relation_domain_ISINC) Inline command "match-right-relation-domain"6.6.6; + if (C == match_left_relation_domain_ISINC) Inline command "match-left-relation-domain"6.6.5; + if (C == matches_description_ISINC) Inline command "matches-description"6.6.7; + if (C == now_matches_description_ISINC) Inline command "now-matches-description"6.6.8; + if (C == arithmetic_operation_ISINC) Inline command "arithmetic-operation"6.6.9; + if (C == say_ISINC) Inline command "say"6.6.10; + if (C == show_me_ISINC) Inline command "show-me"6.6.11;
  • This code is used in §6.

§6.6.1. The {-my:name} command creates a local variable for use in the invocation, @@ -1712,14 +1730,70 @@

} -

§6.6.5. The next command generates code able to test if a token in the invocation, +

§6.6.5. These are needed to apply stricter kind-checking to phrases like "the X +which relates to Y by R". For example, if R relates containers to doors then +"the vehicle which relates to the oak door by R" is unsafe because what relates +to the oak door may be a container which is not a vehicle. +

+ +

There are two forms according to which domain is implied. +

+ +

Inline command "match-left-relation-domain"6.6.5 = +

+ +
+    kind *X = CSIInline::parse_bracing_operand_as_kind(ist->operand, Node::get_kind_variable_declarations(inv));
+    parse_node *R = CSIInline::parse_bracing_operand_as_identifier(ist->operand2, idb, tokens, my_vars);
+    kind *KR = Specifications::to_kind(R);
+    if (Kinds::get_construct(KR) == CON_relation) {
+        kind *K = NULL; kind *unwanted = NULL;
+        Kinds::binary_construction_material(KR, &K, &unwanted);
+        Check there is strict conformance on this domain6.6.5.1;
+    }
+    return;
+
+
  • This code is used in §6.6.
+

§6.6.6. Inline command "match-right-relation-domain"6.6.6 = +

+ +
+    kind *X = CSIInline::parse_bracing_operand_as_kind(ist->operand, Node::get_kind_variable_declarations(inv));
+    parse_node *R = CSIInline::parse_bracing_operand_as_identifier(ist->operand2, idb, tokens, my_vars);
+    kind *KR = Specifications::to_kind(R);
+    if (Kinds::get_construct(KR) == CON_relation) {
+        kind *unwanted = NULL; kind *K = NULL;
+        Kinds::binary_construction_material(KR, &unwanted, &K);
+        Check there is strict conformance on this domain6.6.5.1;
+    }
+    return;
+
+
  • This code is used in §6.6.
+

§6.6.5.1. Check there is strict conformance on this domain6.6.5.1 = +

+ +
+    if (Kinds::conforms_to(K, X) == FALSE) {
+        Problems::quote_source(1, current_sentence);
+        Problems::quote_kind(2, X);
+        Problems::quote_kind(3, KR);
+        Problems::quote_kind(4, K);
+        StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_RelationDomainWrongKind));
+        Problems::issue_problem_segment(
+            "You wrote %1, but the kinds here do not quite match: what we "
+            "have is %3, and %4 is not necessarily %2.");
+        Problems::issue_problem_end();
+    }
+
+ +

§6.6.7. The next command generates code able to test if a token in the invocation, or an Inter variable, matches a given description — which need not be constant. For example, if the phrase prototype includes the token (OS - description of objects) then the bracing {-matches-description:1:OS} compiles a condition testing whether the object in variable {-my:1} matches the description or not.

-

Inline command "matches-description"6.6.5 = +

Inline command "matches-description"6.6.7 =

@@ -1741,11 +1815,11 @@ 

return;

-

§6.6.6. This is the same, except that it compiles code to assert that the given +

§6.6.8. This is the same, except that it compiles code to assert that the given variable matches the given description.

-

Inline command "now-matches-description"6.6.6 = +

Inline command "now-matches-description"6.6.8 =

@@ -1768,7 +1842,7 @@ 

return;

-

§6.6.7. Inline command "arithmetic-operation"6.6.7 = +

§6.6.9. Inline command "arithmetic-operation"6.6.9 =

@@ -1777,12 +1851,12 @@ 

if (Kinds::Dimensions::arithmetic_op_is_unary(op)) binary = FALSE; parse_node *X = NULL, *Y = NULL; kind *KX = NULL, *KY = NULL; - Read the operands and their kinds6.6.7.1; + Read the operands and their kinds6.6.9.1; CompileArithmetic::perform_arithmetic_emit(op, NULL, X, NULL, KX, Y, NULL, KY); return;

  • This code is used in §6.6.
-

§6.6.7.1. Read the operands and their kinds6.6.7.1 = +

§6.6.9.1. Read the operands and their kinds6.6.9.1 =

@@ -1795,15 +1869,15 @@ 

KY = Specifications::to_kind(Y); }

- -

§6.6.8. This prints a token or variable using the correct format for its kind. The +

+

§6.6.10. This prints a token or variable using the correct format for its kind. The code below optimises this so that constant text is printed directly, rather than stored as a constant text value and printed by a call to TEXT_TY_Say: this saves 2 words of memory and a function call at print time. But the result would be the same without the optimisation.

-

Inline command "say"6.6.8 = +

Inline command "say"6.6.10 =

@@ -1817,9 +1891,9 @@ 

kind *K = CSIInline::parse_bracing_operand_as_kind(ist->operand2, Node::get_kind_variable_declarations(inv)); - if (Kinds::eq(K, K_text)) Inline say text6.6.8.1; - if (Kinds::eq(K, K_number)) Inline say number6.6.8.2; - if (Kinds::eq(K, K_unicode_character)) Inline say unicode character6.6.8.3; + if (Kinds::eq(K, K_text)) Inline say text6.6.10.1; + if (Kinds::eq(K, K_number)) Inline say number6.6.10.2; + if (Kinds::eq(K, K_unicode_character)) Inline say unicode character6.6.10.3; if (K) { EmitCode::call(RTKindConstructors::printing_fn_iname(K)); EmitCode::down(); @@ -1829,7 +1903,7 @@

return;

-

§6.6.8.1. Inline say text6.6.8.1 = +

§6.6.10.1. Inline say text6.6.10.1 =

@@ -1854,11 +1928,11 @@ 

} return;

- -

§6.6.8.2. Numbers are also handled directly... +

+

§6.6.10.2. Numbers are also handled directly...

-

Inline say number6.6.8.2 = +

Inline say number6.6.10.2 =

@@ -1872,8 +1946,8 @@ 

EmitCode::up(); return;

- -

§6.6.8.3. And similarly for Unicode characters. It would be tidier to abstract this +

+

§6.6.10.3. And similarly for Unicode characters. It would be tidier to abstract this with a function call, but it would cost a function call.

@@ -1881,7 +1955,7 @@

language.

-

Inline say unicode character6.6.8.3 = +

Inline say unicode character6.6.10.3 =

@@ -1903,12 +1977,12 @@ 

} return;

- -

§6.6.9. This is for debugging purposes only: it does the equivalent of the "showme" +

+

§6.6.11. This is for debugging purposes only: it does the equivalent of the "showme" phrase applied to the named variable.

-

Inline command "show-me"6.6.9 = +

Inline command "show-me"6.6.11 =

@@ -2153,7 +2227,7 @@ 

ist->owner->parent_schema->converted_from, "I don't know any local variable called '%4'.");

- +

§8. Parsing the invocation operands. Two ways. First, as an identifier name, which stands for a local Inter variable or for a token in the phrase being invoked. There are three ways we can write this: @@ -2166,7 +2240,7 @@

  • (c) and failing that we have the name of a local Inter variable.
  • -parse_node *CSIInline::parse_bracing_operand_as_identifier(text_stream *operand, id_body *idb,
    +parse_node *CSIInline::parse_bracing_operand_as_identifier(text_stream *operand, id_body *idb,
         tokens_packet *tokens, local_variable **my_vars) {
         local_variable *lvar = NULL;
         if ((Str::get_at(operand, 1) == 0) &&
    @@ -2209,7 +2283,7 @@ 

    (- return {-new:return-kind}; -).

    -kind *CSIInline::parse_bracing_operand_as_kind(text_stream *operand,
    +kind *CSIInline::parse_bracing_operand_as_kind(text_stream *operand,
         kind_variable_declaration *kvd) {
         if (Str::eq_wide_string(operand, U"return-kind"))
             return Frames::get_kind_returned();
    @@ -2403,7 +2477,7 @@ 

    §12.

    -void CSIInline::emit_showme(parse_node *spec) {
    +void CSIInline::emit_showme(parse_node *spec) {
         TEMPORARY_TEXT(OUT)
         if (Node::is(spec, PROPERTY_VALUE_NT))
             spec = Lvalues::underlying_property(spec);
    diff --git a/docs/knowledge-module/3-spr2.html b/docs/knowledge-module/3-spr2.html
    index 07ff5280f9..0a15f53024 100644
    --- a/docs/knowledge-module/3-spr2.html
    +++ b/docs/knowledge-module/3-spr2.html
    @@ -250,7 +250,6 @@ 

     void SettingPropertyRelations::set_property_BP_schemas(binary_predicate *bp,
         property *prn) {
    -    LOG("set_property_BP_schemas sees property %n of kind %u\n", RTProperties::iname(prn), ValueProperties::kind(prn));
         if (Kinds::Behaviour::uses_block_values(ValueProperties::kind(prn))) {
             bp->task_functions[TEST_ATOM_TASK] =
                 Calculus::Schemas::new("ComparePV(*1.%n, *2) == 0", RTProperties::iname(prn));
    diff --git a/inform7/Figures/memory-diagnostics.txt b/inform7/Figures/memory-diagnostics.txt
    index c5567e26af..07b927fed4 100644
    --- a/inform7/Figures/memory-diagnostics.txt
    +++ b/inform7/Figures/memory-diagnostics.txt
    @@ -1,6 +1,6 @@
    -Total memory consumption was 153422K = 150 MB
    +Total memory consumption was 153352K = 150 MB
     
    - ---- was used for 2279849 objects, in 402729 frames in 0 x 800K = 0K = 0 MB:
    + ---- was used for 2279726 objects, in 402705 frames in 0 x 800K = 0K = 0 MB:
     
         28.9%  inter_tree_node_array                    63 x 8192 = 516096 objects, 45418464 bytes
         19.9%  text_stream_array                        5555 x 100 = 555500 objects, 31285760 bytes
    @@ -18,7 +18,7 @@ Total memory consumption was 153422K = 150 MB
          1.4%  inter_name_generator_array               55 x 1000 = 55000 objects, 2201760 bytes
          1.2%  package_request                          22153 objects, 1949464 bytes
          1.2%  vocabulary_entry_array                   168 x 100 = 16800 objects, 1886976 bytes
    -     1.1%  dict_entry_array                         561 x 100 = 56100 objects, 1813152 bytes
    +     1.1%  dict_entry_array                         560 x 100 = 56000 objects, 1809920 bytes
          0.9%  inter_symbols_table                      27946 objects, 1564976 bytes
          0.9%  i6_schema_array                          25 x 100 = 2500 objects, 1500800 bytes
          0.9%  match_trie_array                         11 x 1000 = 11000 objects, 1496352 bytes
    @@ -119,7 +119,7 @@ Total memory consumption was 153422K = 150 MB
          ----  adjective_iname_holder                   337 objects, 13480 bytes
          ----  booking_list                             417 objects, 13344 bytes
          ----  web_bibliographic_datum                  203 objects, 12992 bytes
    -     ----  uniqueness_count                         509 objects, 12216 bytes
    +     ----  uniqueness_count                         486 objects, 11664 bytes
          ----  inter_construct                          32 objects, 11008 bytes
          ----  md_doc_state                             2 objects, 10480 bytes
          ----  heading_tree                             33 objects, 10296 bytes
    @@ -271,7 +271,7 @@ Total memory consumption was 153422K = 150 MB
     
     100.0% was used for memory not allocated for objects:
     
    -    64.4%  text stream storage                      101245812 bytes in 579773 claims
    +    64.4%  text stream storage                      101241876 bytes in 579750 claims
          3.9%  dictionary storage                       6168192 bytes in 8263 claims
          ----  sorting                                  20984 bytes in 2656 claims
          4.5%  source text                              7200000 bytes in 3 claims
    @@ -280,7 +280,7 @@ Total memory consumption was 153422K = 150 MB
          ----  linguistic stock array                   81920 bytes in 2 claims
          ----  small word set array                     105600 bytes in 22 claims
          3.1%  inter symbols storage                    4905872 bytes in 29425 claims
    -    10.7%  inter bytecode storage                   16841636 bytes in 15 claims
    +    10.6%  inter bytecode storage                   16773620 bytes in 15 claims
          3.9%  inter links storage                      6222976 bytes in 11 claims
          0.1%  inter tree location list storage         191232 bytes in 32 claims
          1.7%  instance-of-kind counting                2715904 bytes in 1 claim
    @@ -289,5 +289,5 @@ Total memory consumption was 153422K = 150 MB
          ----  code generation workspace for objects    3616 bytes in 19 claims
          0.1%  emitter array storage                    295200 bytes in 2112 claims
     
    --140.-2% was overhead - -220277832 bytes = -215115K = -210 MB
    +-140.-2% was overhead - -220274048 bytes = -215111K = -210 MB
     
    diff --git a/inform7/Figures/timings-diagnostics.txt b/inform7/Figures/timings-diagnostics.txt
    index 797d40593d..2af8da7332 100644
    --- a/inform7/Figures/timings-diagnostics.txt
    +++ b/inform7/Figures/timings-diagnostics.txt
    @@ -1,8 +1,8 @@
     100.0% in inform7 run
          66.5% in compilation to Inter
    -         44.1% in //Sequence::undertake_queued_tasks//
    -          4.1% in //MajorNodes::pre_pass//
    -          3.4% in //MajorNodes::pass_1//
    +         43.7% in //Sequence::undertake_queued_tasks//
    +          4.4% in //MajorNodes::pre_pass//
    +          3.7% in //MajorNodes::pass_1//
               2.0% in //RTKindConstructors::compile//
               1.7% in //ImperativeDefinitions::assess_all//
               1.3% in //RTPhrasebook::compile_entries//
    @@ -15,7 +15,7 @@
               0.3% in //Sequence::undertake_queued_tasks//
               0.3% in //Sequence::undertake_queued_tasks//
               0.3% in //Task::make_built_in_kind_constructors//
    -          4.8% not specifically accounted for
    +          4.5% not specifically accounted for
          26.2% in running Inter pipeline
               8.6% in step 14/15: generate inform6 -> auto.inf
               6.8% in step 5/15: load-binary-kits
    @@ -26,5 +26,5 @@
               0.3% in step 7/15: shorten-wiring
               0.3% in step 8/15: detect-indirect-calls
               1.8% not specifically accounted for
    -      6.5% in supervisor
    -      0.7% not specifically accounted for
    +      6.8% in supervisor
    +      0.4% not specifically accounted for
    diff --git a/inform7/Internal/Extensions/Graham Nelson/Basic Inform.i7xd/Source/Basic Inform.i7x b/inform7/Internal/Extensions/Graham Nelson/Basic Inform.i7xd/Source/Basic Inform.i7x
    index 48cb51a3b7..e46922e94c 100644
    --- a/inform7/Internal/Extensions/Graham Nelson/Basic Inform.i7xd/Source/Basic Inform.i7x	
    +++ b/inform7/Internal/Extensions/Graham Nelson/Basic Inform.i7xd/Source/Basic Inform.i7x	
    @@ -1249,57 +1249,57 @@ To decide which number is number of steps via (R - relation of objects)
     To decide which list of Ks is list of (name of kind of value K)
     	that/which/whom (R - relation of Ks to values of kind L) relates
     	(documented at ph_leftdomain):
    -	(- RelationTest({-by-reference:R}, RELS_LIST, {-new:list of K}, RLIST_ALL_X) -).
    +	(- {-match-left-relation-domain:K:R}RelationTest({-by-reference:R}, RELS_LIST, {-new:list of K}, RLIST_ALL_X) -).
     
     To decide which list of Ls is list of (name of kind of value L)
     	to which/whom (R - relation of values of kind K to Ls) relates
     	(documented at ph_rightdomain):
    -	(- RelationTest({-by-reference:R}, RELS_LIST, {-new:list of L}, RLIST_ALL_Y) -). [1]
    +	(- {-match-right-relation-domain:L:R}RelationTest({-by-reference:R}, RELS_LIST, {-new:list of L}, RLIST_ALL_Y) -). [1]
     
     To decide which list of Ls is list of (name of kind of value L)
     	that/which/whom (R - relation of values of kind K to Ls) relates to
     	(documented at ph_rightdomain):
    -	(- RelationTest({-by-reference:R}, RELS_LIST, {-new:list of L}, RLIST_ALL_Y) -). [2]
    +	(- {-match-right-relation-domain:L:R}RelationTest({-by-reference:R}, RELS_LIST, {-new:list of L}, RLIST_ALL_Y) -). [2]
     
     To decide which list of Ks is list of (name of kind of value K) that/which/who
     	relate to (Y - L) by (R - relation of Ks to values of kind L)
     	(documented at ph_leftlookuplist):
    -	(- RelationTest({-by-reference:R}, RELS_LOOKUP_ALL_X, {Y}, {-new:list of K}) -).
    +	(- {-match-left-relation-domain:K:R}RelationTest({-by-reference:R}, RELS_LOOKUP_ALL_X, {Y}, {-new:list of K}) -).
     
     To decide which list of Ls is list of (name of kind of value L) to which/whom (X - K)
     	relates by (R - relation of values of kind K to Ls)
     	(documented at ph_rightlookuplist):
    -	(- RelationTest({-by-reference:R}, RELS_LOOKUP_ALL_Y, {X}, {-new:list of L}) -). [1]
    +	(- {-match-right-relation-domain:L:R}RelationTest({-by-reference:R}, RELS_LOOKUP_ALL_Y, {X}, {-new:list of L}) -). [1]
     
     To decide which list of Ls is list of (name of kind of value L)
     	that/which/whom (X - K) relates to by (R - relation of values of kind K to Ls)
     	(documented at ph_rightlookuplist):
    -	(- RelationTest({-by-reference:R}, RELS_LOOKUP_ALL_Y, {X}, {-new:list of L}) -). [2]
    +	(- {-match-right-relation-domain:L:R}RelationTest({-by-reference:R}, RELS_LOOKUP_ALL_Y, {X}, {-new:list of L}) -). [2]
     
     To decide whether (name of kind of value K) relates to (Y - L) by
     	(R - relation of Ks to values of kind L)
     	(documented at ph_ifright):
    -	(- RelationTest({-by-reference:R}, RELS_LOOKUP_ANY, {Y}, RLANY_CAN_GET_X) -).
    +	(- {-match-left-relation-domain:K:R}RelationTest({-by-reference:R}, RELS_LOOKUP_ANY, {Y}, RLANY_CAN_GET_X) -).
     
     To decide whether (X - K) relates to (name of kind of value L) by
     	(R - relation of values of kind K to Ls)
     	(documented at ph_ifleft):
    -	(- RelationTest({-by-reference:R}, RELS_LOOKUP_ANY, {X}, RLANY_CAN_GET_Y) -).
    +	(- {-match-right-relation-domain:L:R}RelationTest({-by-reference:R}, RELS_LOOKUP_ANY, {X}, RLANY_CAN_GET_Y) -).
     
     To decide which K is (name of kind of value K) that/which/who relates to
     	(Y - L) by (R - relation of Ks to values of kind L)
     	(documented at ph_leftlookup):
    -	(- RelationTest({-by-reference:R}, RELS_LOOKUP_ANY, {Y}, RLANY_GET_X) -).
    +	(- {-match-left-relation-domain:K:R}RelationTest({-by-reference:R}, RELS_LOOKUP_ANY, {Y}, RLANY_GET_X) -).
     
     To decide which L is (name of kind of value L) to which/whom (X - K)
     	relates by (R - relation of values of kind K to Ls)
     	(documented at ph_rightlookup):
    -	(- RelationTest({-by-reference:R}, RELS_LOOKUP_ANY, {X}, RLANY_GET_Y) -). [1]
    +	(- {-match-right-relation-domain:L:R}RelationTest({-by-reference:R}, RELS_LOOKUP_ANY, {X}, RLANY_GET_Y) -). [1]
     
     To decide which L is (name of kind of value L) that/which/whom (X - K)
     	relates to by (R - relation of values of kind K to Ls)
     	(documented at ph_rightlookup):
    -	(- RelationTest({-by-reference:R}, RELS_LOOKUP_ANY, {X}, RLANY_GET_Y) -). [2]
    +	(- {-match-right-relation-domain:L:R}RelationTest({-by-reference:R}, RELS_LOOKUP_ANY, {X}, RLANY_GET_Y) -). [2]
     
     Chapter 7 - Functional Programming
     
    diff --git a/inform7/Tests/Test Cases/ContainmentScanning.txt b/inform7/Tests/Test Cases/ContainmentScanning.txt
    index 88d37b2a8a..7d776cd99e 100644
    --- a/inform7/Tests/Test Cases/ContainmentScanning.txt	
    +++ b/inform7/Tests/Test Cases/ContainmentScanning.txt	
    @@ -12,9 +12,9 @@ To say relations for (item - a thing):
     	showme the containment relation;
     
     To describe (R - a relation of objects) for (item - a thing):
    -	say "[item]: [the list of things to which item relates by R with indefinite articles].";
    -	if a thing to which item relates by R is a thing: 
    -		say "[The item] [verb rendering applied to a random verb that means R] [the list of things to which item relates by R with indefinite articles]. [run paragraph on]"
    +	say "[item]: [the list of objects to which item relates by R with indefinite articles].";
    +	if an object to which item relates by R is a thing: 
    +		say "[The item] [verb rendering applied to a random verb that means R] [the list of objects to which item relates by R with indefinite articles]. [run paragraph on]"
     
     To decide which text is the rendering of (V - verb) (this is verb rendering):
     	decide on "[adapt V]".  
    diff --git a/inform7/Tests/Test Problems/PM_RelationDomainWrongKind--I.txt b/inform7/Tests/Test Problems/PM_RelationDomainWrongKind--I.txt
    new file mode 100644
    index 0000000000..856374f674
    --- /dev/null
    +++ b/inform7/Tests/Test Problems/PM_RelationDomainWrongKind--I.txt	
    @@ -0,0 +1,11 @@
    +Inform 7 v10.2.0 has started.
    +I've now read your source text, which is 66 words long.
    +I've also read version 10.2.0 of Basic Inform by Graham Nelson, which is 10687 words long.
    +I've also read version 10.2.0 of English Language by Graham Nelson, which is 2330 words long.
    +I've also read version 10.2.0 of Standard Rules by Graham Nelson, which is 35526 words long.
    +Problem__ PM_RelationDomainWrongKind
    +  >--> You wrote 'showme the vehicle that relates to s1 by the regard relation'
    +    (source text, line 10), but the kinds here do not quite match: what we have
    +    is a relation of containers to supporters, and a container is not
    +    necessarily a vehicle.
    +Inform 7 has finished.
    diff --git a/inform7/Tests/Test Problems/PM_RelationDomainWrongKind.txt b/inform7/Tests/Test Problems/PM_RelationDomainWrongKind.txt
    new file mode 100644
    index 0000000000..ff7885fa8a
    --- /dev/null
    +++ b/inform7/Tests/Test Problems/PM_RelationDomainWrongKind.txt	
    @@ -0,0 +1,14 @@
    +Problem: PM_RelationDomainWrongKind
    +
    +Regard relates one container to one supporter.
    +The verb to respect means the regard relation.
    +
    +s1 is a supporter.
    +c1 is a container.
    +x1 is a vehicle.
    +c1 respects s1.
    +
    +when play begins:
    +	showme the vehicle that relates to s1 by the regard relation;
    +	showme the thing that relates to s1 by the regard relation;
    +	showme the container that relates to s1 by the regard relation;
    diff --git a/inform7/extensions/basic_inform/Sections/Phrase Definitions.w b/inform7/extensions/basic_inform/Sections/Phrase Definitions.w
    index f0defe8d42..f923a440c0 100644
    --- a/inform7/extensions/basic_inform/Sections/Phrase Definitions.w	
    +++ b/inform7/extensions/basic_inform/Sections/Phrase Definitions.w	
    @@ -1507,57 +1507,57 @@ To decide which number is number of steps via (R - relation of objects)
     To decide which list of Ks is list of (name of kind of value K)
     	that/which/whom (R - relation of Ks to values of kind L) relates
     	(documented at ph_leftdomain):
    -	(- RelationTest({-by-reference:R}, RELS_LIST, {-new:list of K}, RLIST_ALL_X) -).
    +	(- {-match-left-relation-domain:K:R}RelationTest({-by-reference:R}, RELS_LIST, {-new:list of K}, RLIST_ALL_X) -).
     
     To decide which list of Ls is list of (name of kind of value L)
     	to which/whom (R - relation of values of kind K to Ls) relates
     	(documented at ph_rightdomain):
    -	(- RelationTest({-by-reference:R}, RELS_LIST, {-new:list of L}, RLIST_ALL_Y) -). [1]
    +	(- {-match-right-relation-domain:L:R}RelationTest({-by-reference:R}, RELS_LIST, {-new:list of L}, RLIST_ALL_Y) -). [1]
     
     To decide which list of Ls is list of (name of kind of value L)
     	that/which/whom (R - relation of values of kind K to Ls) relates to
     	(documented at ph_rightdomain):
    -	(- RelationTest({-by-reference:R}, RELS_LIST, {-new:list of L}, RLIST_ALL_Y) -). [2]
    +	(- {-match-right-relation-domain:L:R}RelationTest({-by-reference:R}, RELS_LIST, {-new:list of L}, RLIST_ALL_Y) -). [2]
     
     To decide which list of Ks is list of (name of kind of value K) that/which/who
     	relate to (Y - L) by (R - relation of Ks to values of kind L)
     	(documented at ph_leftlookuplist):
    -	(- RelationTest({-by-reference:R}, RELS_LOOKUP_ALL_X, {Y}, {-new:list of K}) -).
    +	(- {-match-left-relation-domain:K:R}RelationTest({-by-reference:R}, RELS_LOOKUP_ALL_X, {Y}, {-new:list of K}) -).
     
     To decide which list of Ls is list of (name of kind of value L) to which/whom (X - K)
     	relates by (R - relation of values of kind K to Ls)
     	(documented at ph_rightlookuplist):
    -	(- RelationTest({-by-reference:R}, RELS_LOOKUP_ALL_Y, {X}, {-new:list of L}) -). [1]
    +	(- {-match-right-relation-domain:L:R}RelationTest({-by-reference:R}, RELS_LOOKUP_ALL_Y, {X}, {-new:list of L}) -). [1]
     
     To decide which list of Ls is list of (name of kind of value L)
     	that/which/whom (X - K) relates to by (R - relation of values of kind K to Ls)
     	(documented at ph_rightlookuplist):
    -	(- RelationTest({-by-reference:R}, RELS_LOOKUP_ALL_Y, {X}, {-new:list of L}) -). [2]
    +	(- {-match-right-relation-domain:L:R}RelationTest({-by-reference:R}, RELS_LOOKUP_ALL_Y, {X}, {-new:list of L}) -). [2]
     
     To decide whether (name of kind of value K) relates to (Y - L) by
     	(R - relation of Ks to values of kind L)
     	(documented at ph_ifright):
    -	(- RelationTest({-by-reference:R}, RELS_LOOKUP_ANY, {Y}, RLANY_CAN_GET_X) -).
    +	(- {-match-left-relation-domain:K:R}RelationTest({-by-reference:R}, RELS_LOOKUP_ANY, {Y}, RLANY_CAN_GET_X) -).
     
     To decide whether (X - K) relates to (name of kind of value L) by
     	(R - relation of values of kind K to Ls)
     	(documented at ph_ifleft):
    -	(- RelationTest({-by-reference:R}, RELS_LOOKUP_ANY, {X}, RLANY_CAN_GET_Y) -).
    +	(- {-match-right-relation-domain:L:R}RelationTest({-by-reference:R}, RELS_LOOKUP_ANY, {X}, RLANY_CAN_GET_Y) -).
     
     To decide which K is (name of kind of value K) that/which/who relates to
     	(Y - L) by (R - relation of Ks to values of kind L)
     	(documented at ph_leftlookup):
    -	(- RelationTest({-by-reference:R}, RELS_LOOKUP_ANY, {Y}, RLANY_GET_X) -).
    +	(- {-match-left-relation-domain:K:R}RelationTest({-by-reference:R}, RELS_LOOKUP_ANY, {Y}, RLANY_GET_X) -).
     
     To decide which L is (name of kind of value L) to which/whom (X - K)
     	relates by (R - relation of values of kind K to Ls)
     	(documented at ph_rightlookup):
    -	(- RelationTest({-by-reference:R}, RELS_LOOKUP_ANY, {X}, RLANY_GET_Y) -). [1]
    +	(- {-match-right-relation-domain:L:R}RelationTest({-by-reference:R}, RELS_LOOKUP_ANY, {X}, RLANY_GET_Y) -). [1]
     
     To decide which L is (name of kind of value L) that/which/whom (X - K)
     	relates to by (R - relation of values of kind K to Ls)
     	(documented at ph_rightlookup):
    -	(- RelationTest({-by-reference:R}, RELS_LOOKUP_ANY, {X}, RLANY_GET_Y) -). [2]
    +	(- {-match-right-relation-domain:L:R}RelationTest({-by-reference:R}, RELS_LOOKUP_ANY, {X}, RLANY_GET_Y) -). [2]
     
     @h Functional Programming.
     Here we have the ability to use the name of a function as a value, and to
    diff --git a/inform7/imperative-module/Chapter 5/Compile Invocations Inline.w b/inform7/imperative-module/Chapter 5/Compile Invocations Inline.w
    index 5929ce70ae..430915c65f 100644
    --- a/inform7/imperative-module/Chapter 5/Compile Invocations Inline.w	
    +++ b/inform7/imperative-module/Chapter 5/Compile Invocations Inline.w	
    @@ -771,6 +771,7 @@ We'll start with a suite of details about kinds:
     	if (C == previous_routine_ISINC) @;
     	if (C == strong_kind_ISINC)      @;
     	if (C == weak_kind_ISINC)        @;
    +	if (C == object_kind_ISINC)      @;
     
     @ The following produces a new value of the given kind. If it's stored as a
     word value, this will just be the default value, so |{-new:time}| will output
    @@ -863,6 +864,17 @@ proposition.
     	else @;
     	return;
     
    +@ =
    +	kind *K = CSIInline::parse_bracing_operand_as_kind(ist->operand,
    +		Node::get_kind_variable_declarations(inv));
    +	if (K) {
    +		if (Kinds::Behaviour::is_object(K))
    +			EmitCode::val_iname(K_value, RTKindDeclarations::iname(K));
    +		else
    +			EmitCode::val_number(0);
    +	} else @;
    +	return;
    +
     @ =
     	StandardProblems::inline_problem(_p_(PM_InlineNew), idb,
     		ist->owner->parent_schema->converted_from,
    @@ -1014,6 +1026,8 @@ a command, which is why it isn't here.)
     	if (C == unprotect_ISINC)               @;
     	if (C == copy_ISINC)                    @;
     	if (C == initialise_ISINC)              @;
    +	if (C == match_right_relation_domain_ISINC) @;
    +	if (C == match_left_relation_domain_ISINC)  @;
     	if (C == matches_description_ISINC)     @;
     	if (C == now_matches_description_ISINC) @;
     	if (C == arithmetic_operation_ISINC)    @;
    @@ -1293,6 +1307,48 @@ story title).
     		return;
     	}
     
    +@ These are needed to apply stricter kind-checking to phrases like "the X
    +which relates to Y by R". For example, if R relates containers to doors then
    +"the vehicle which relates to the oak door by R" is unsafe because what relates
    +to the oak door may be a container which is not a vehicle.
    +
    +There are two forms according to which domain is implied.
    +
    +@ =
    +	kind *X = CSIInline::parse_bracing_operand_as_kind(ist->operand, Node::get_kind_variable_declarations(inv));
    +	parse_node *R = CSIInline::parse_bracing_operand_as_identifier(ist->operand2, idb, tokens, my_vars);
    +	kind *KR = Specifications::to_kind(R);
    +	if (Kinds::get_construct(KR) == CON_relation) {
    +		kind *K = NULL; kind *unwanted = NULL;
    +		Kinds::binary_construction_material(KR, &K, &unwanted);
    +		@;
    +	}
    +	return;
    +
    +@ =
    +	kind *X = CSIInline::parse_bracing_operand_as_kind(ist->operand, Node::get_kind_variable_declarations(inv));
    +	parse_node *R = CSIInline::parse_bracing_operand_as_identifier(ist->operand2, idb, tokens, my_vars);
    +	kind *KR = Specifications::to_kind(R);
    +	if (Kinds::get_construct(KR) == CON_relation) {
    +		kind *unwanted = NULL; kind *K = NULL; 
    +		Kinds::binary_construction_material(KR, &unwanted, &K);
    +		@;
    +	}
    +	return;
    +
    +@ =
    +	if (Kinds::conforms_to(K, X) == FALSE) {
    +		Problems::quote_source(1, current_sentence);
    +		Problems::quote_kind(2, X);
    +		Problems::quote_kind(3, KR);
    +		Problems::quote_kind(4, K);
    +		StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_RelationDomainWrongKind));
    +		Problems::issue_problem_segment(
    +			"You wrote %1, but the kinds here do not quite match: what we "
    +			"have is %3, and %4 is not necessarily %2.");
    +		Problems::issue_problem_end();
    +	}
    +
     @ The next command generates code able to test if a token in the invocation,
     or an Inter variable, matches a given description -- which need not be constant.
     For example, if the phrase prototype includes the token |(OS - description of objects)|
    diff --git a/inform7/knowledge-module/Chapter 3/Setting Property Relation.w b/inform7/knowledge-module/Chapter 3/Setting Property Relation.w
    index 73be4c0887..23eaa484ad 100644
    --- a/inform7/knowledge-module/Chapter 3/Setting Property Relation.w	
    +++ b/inform7/knowledge-module/Chapter 3/Setting Property Relation.w	
    @@ -159,7 +159,6 @@ and simplicity.
     =
     void SettingPropertyRelations::set_property_BP_schemas(binary_predicate *bp,
     	property *prn) {
    -	LOG("set_property_BP_schemas sees property %n of kind %u\n", RTProperties::iname(prn), ValueProperties::kind(prn));
     	if (Kinds::Behaviour::uses_block_values(ValueProperties::kind(prn))) {
     		bp->task_functions[TEST_ATOM_TASK] =
     			Calculus::Schemas::new("ComparePV(*1.%n, *2) == 0", RTProperties::iname(prn));
    diff --git a/inter/building-module/Chapter 2/Inter Schemas.w b/inter/building-module/Chapter 2/Inter Schemas.w
    index 416302a198..0a1a65697a 100644
    --- a/inter/building-module/Chapter 2/Inter Schemas.w	
    +++ b/inter/building-module/Chapter 2/Inter Schemas.w	
    @@ -329,6 +329,7 @@ inter_schema_token *InterSchemas::new_token(int type, text_stream *material,
     @e indexing_routine_ISINC
     @e strong_kind_ISINC
     @e weak_kind_ISINC
    +@e object_kind_ISINC
     @e backspace_ISINC
     @e erase_ISINC
     @e open_brace_ISINC
    @@ -357,6 +358,8 @@ inter_schema_token *InterSchemas::new_token(int type, text_stream *material,
     @e unprotect_ISINC
     @e copy_ISINC
     @e initialise_ISINC
    +@e match_right_relation_domain_ISINC
    +@e match_left_relation_domain_ISINC
     @e matches_description_ISINC
     @e now_matches_description_ISINC
     @e arithmetic_operation_ISINC
    diff --git a/inter/building-module/Chapter 2/Tokenisation.w b/inter/building-module/Chapter 2/Tokenisation.w
    index 9b784adaff..c15a3a1db0 100644
    --- a/inter/building-module/Chapter 2/Tokenisation.w	
    +++ b/inter/building-module/Chapter 2/Tokenisation.w	
    @@ -257,6 +257,8 @@ a bracing.
     			c = strong_kind_ISINC;
     		} else if (Str::eq_wide_string(t->command, U"weak-kind")) {
     			c = weak_kind_ISINC;
    +		} else if (Str::eq_wide_string(t->command, U"object-kind")) {
    +			c = object_kind_ISINC;
     		} else if (Str::eq_wide_string(t->command, U"backspace")) {
     			c = backspace_ISINC;
     		} else if (Str::eq_wide_string(t->command, U"erase")) {
    @@ -315,6 +317,10 @@ a bracing.
     			c = initialise_ISINC;
     		} else if (Str::eq_wide_string(t->command, U"matches-description")) {
     			c = matches_description_ISINC;
    +		} else if (Str::eq_wide_string(t->command, U"match-right-relation-domain")) {
    +			c = match_right_relation_domain_ISINC;
    +		} else if (Str::eq_wide_string(t->command, U"match-left-relation-domain")) {
    +			c = match_left_relation_domain_ISINC;
     		} else if (Str::eq_wide_string(t->command, U"now-matches-description")) {
     			c = now_matches_description_ISINC;
     		} else if (Str::eq_wide_string(t->command, U"arithmetic-operation")) {
    diff --git a/resources/Documentation/Examples/RelevantRelations.txt b/resources/Documentation/Examples/RelevantRelations.txt
    index d8ca7eb6bf..b485cd9cc6 100644
    --- a/resources/Documentation/Examples/RelevantRelations.txt
    +++ b/resources/Documentation/Examples/RelevantRelations.txt
    @@ -63,9 +63,9 @@ The following uses what is, strictly speaking, a piece of internal machinery not
     	Before printing the name of something (called mentioned target) while writing a paragraph about something:
     		add the mentioned target to the current paragraph, if absent.
     	
    -	To describe (R - a relation of objects) for (item - a thing):
    -		if a thing to which item relates by R is a thing:
    -			say "[The item with pronoun] [verb rendering applied to a random verb that means R] [the list of things to which item relates by R with indefinite articles]. [run paragraph on]"
    +	To describe (R - a relation of objects) for (item - an object):
    +		if an object to which item relates by R is a thing:
    +			say "[The item with pronoun] [verb rendering applied to a random verb that means R] [the list of objects to which item relates by R with indefinite articles]. [run paragraph on]"
     	
     	To decide which text is the rendering of (V - verb) (this is verb rendering):
     		decide on "[adapt V]".