From 87b3b717850449fd29fbf24f2e75923315e590c5 Mon Sep 17 00:00:00 2001 From: Graham Nelson Date: Wed, 18 May 2022 00:45:14 +0100 Subject: [PATCH] Fix for Jira bug I7-2118 --- README.md | 2 +- build.txt | 4 +-- docs/imperative-module/5-cii.html | 31 +++++++++++++++++-- docs/runtime-module/2-dv.html | 19 +++++++++--- docs/runtime-module/5-prp.html | 2 +- docs/runtime-module/5-vrb.html | 3 +- docs/values-module/5-dsh.html | 17 +++++----- inform7/Figures/timings-diagnostics.txt | 23 +++++++------- .../Chapter 5/Compile Invocations Inline.w | 27 ++++++++++++++-- .../runtime-module/Chapter 2/Default Values.w | 17 +++++++--- inform7/runtime-module/Chapter 5/Properties.w | 2 +- inform7/runtime-module/Chapter 5/Variables.w | 3 +- inform7/values-module/Chapter 5/Dash.w | 17 +++++----- 13 files changed, 122 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index 65286d3f5..1488e8d9b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Inform 7 -v10.1.0-beta+6V09 'Krypton' (17 May 2022) +v10.1.0-beta+6V10 'Krypton' (18 May 2022) ## About Inform 7 diff --git a/build.txt b/build.txt index 3f2b40623..9c47c1eb6 100644 --- a/build.txt +++ b/build.txt @@ -1,3 +1,3 @@ Prerelease: beta -Build Date: 17 May 2022 -Build Number: 6V09 +Build Date: 18 May 2022 +Build Number: 6V10 diff --git a/docs/imperative-module/5-cii.html b/docs/imperative-module/5-cii.html index 00bf4c43a..3d2c96d86 100644 --- a/docs/imperative-module/5-cii.html +++ b/docs/imperative-module/5-cii.html @@ -1373,6 +1373,34 @@ but the point is that locals of that kind are automatically set to their default values when created, so they are always typesafe anyway.

+

Note also that the Dash typechecker allows the creation of local variables +whose kinds are subkinds of objects which may have no instances. For example, +in this program: +

+ +
+    A cat is a kind of animal.
+    To discuss the felines:
+        let C be a cat;
+        ...
+
+

...it is legal to construct the variable C with kind cat, even though there +are no cats in the world, so that a call to DefaultValues::val would +generate a problem message. But we call DefaultValues::val_allowing_nothing +instead, so that C is created but with the value nothing. +

+ +

This would be easier to understand if Inform's kinds system supported "optionals". +In the Swift language, for example, there would be a clear distinction between +the types Cat (runtime values must be instances of cat) and Cat? (runtime +values must be instances of cat or else nothing). In Inform, cat-valued global +variables and properties have the type Cat, but cat-valued locals have the +type Cat?. We do this to make it more convenient to write functions about +cats which will compile whether or not any cats exist; an extension might provide +such functions, for example, providing functionality which is only used if cats +do exist, but which should still compile without errors even if they do not. +

+

Inline command "initialise"6.5.3 =

@@ -1402,9 +1430,8 @@ default values when created, so they are always typesafe anyway. EmitCode::down(); inter_symbol *lvar_s = LocalVariables::declare(lvar); EmitCode::ref_symbol(K_value, lvar_s); - rv = DefaultValues::val(K, Node::get_text(V), "value"); + rv = DefaultValues::val_allowing_nothing(K, Node::get_text(V), "value"); EmitCode::up(); - if (rv == FALSE) { Problems::quote_source(1, current_sentence); Problems::quote_kind(2, K); diff --git a/docs/runtime-module/2-dv.html b/docs/runtime-module/2-dv.html index c0f96c4d6..da71fa828 100644 --- a/docs/runtime-module/2-dv.html +++ b/docs/runtime-module/2-dv.html @@ -88,19 +88,25 @@ messages.
 int DefaultValues::array_entry(kind *K, wording W, char *storage_name) {
     value_holster VH = Holsters::new(INTER_DATA_VHMODE);
-    int rv = DefaultValues::to_holster(&VH, K, W, storage_name);
+    int rv = DefaultValues::to_holster(&VH, K, W, storage_name, FALSE);
     inter_pair val = Holsters::unholster_to_pair(&VH);
     EmitArrays::generic_entry(val);
     return rv;
 }
 int DefaultValues::val(kind *K, wording W, char *storage_name) {
     value_holster VH = Holsters::new(INTER_DATA_VHMODE);
-    int rv = DefaultValues::to_holster(&VH, K, W, storage_name);
+    int rv = DefaultValues::to_holster(&VH, K, W, storage_name, FALSE);
+    Holsters::unholster_to_code_val(Emit::tree(), &VH);
+    return rv;
+}
+int DefaultValues::val_allowing_nothing(kind *K, wording W, char *storage_name) {
+    value_holster VH = Holsters::new(INTER_DATA_VHMODE);
+    int rv = DefaultValues::to_holster(&VH, K, W, storage_name, TRUE);
     Holsters::unholster_to_code_val(Emit::tree(), &VH);
     return rv;
 }
 int DefaultValues::to_holster(value_holster *VH, kind *K,
-    wording W, char *storage_name) {
+    wording W, char *storage_name, int allow_nothing_object_as_default) {
     if (Kinds::eq(K, K_value))
         "Value" is too vague to be the kind of a variable1.3;
     if (Kinds::Behaviour::definite(K) == FALSE)
@@ -122,7 +128,10 @@ messages.
 

-    if (Wordings::nonempty(W)) {
+    if (allow_nothing_object_as_default) {
+        Holsters::holster_pair(VH, DefaultValues::to_value_pair(K_object));
+        return TRUE;
+    } else if (Wordings::nonempty(W)) {
         Problems::quote_wording_as_source(1, W);
         Problems::quote_kind(2, K);
         Problems::quote_text(3, storage_name);
@@ -199,7 +208,7 @@ for example, the default value of 
-inter_pair DefaultValues::to_value_pair(kind *K) {
+inter_pair DefaultValues::to_value_pair(kind *K) {
     if (K == NULL) return InterValuePairs::undef();
     Constructed kinds stored as block values2.1;
     Base kinds stored as block values2.2;
diff --git a/docs/runtime-module/5-prp.html b/docs/runtime-module/5-prp.html
index 00a270c7a..e943ed5b7 100644
--- a/docs/runtime-module/5-prp.html
+++ b/docs/runtime-module/5-prp.html
@@ -315,7 +315,7 @@ typesafe for those.
         return TRUE;
     }
     kind *K = ValueProperties::kind(prn);
-    return DefaultValues::to_holster(VH, K, prn->name, "property");
+    return DefaultValues::to_holster(VH, K, prn->name, "property", FALSE);
 }
 

§9. Schemas. "Value" properties (those which are not either-or) can be tested or set with diff --git a/docs/runtime-module/5-vrb.html b/docs/runtime-module/5-vrb.html index e658a2aae..7c0a76a8a 100644 --- a/docs/runtime-module/5-vrb.html +++ b/docs/runtime-module/5-vrb.html @@ -522,7 +522,8 @@ which makes its kind safe.

-    if (DefaultValues::to_holster(VH, nlv->nlv_kind, nlv->name, "variable") == FALSE) {
+    if (DefaultValues::to_holster(VH, nlv->nlv_kind, nlv->name, "variable", FALSE)
+        == FALSE) {
         if (nlv->var_is_allowed_to_be_zero) {
             Holsters::holster_pair(VH, InterValuePairs::number(0));
         } else {
diff --git a/docs/values-module/5-dsh.html b/docs/values-module/5-dsh.html
index f13147ad3..fdeba2dcc 100644
--- a/docs/values-module/5-dsh.html
+++ b/docs/values-module/5-dsh.html
@@ -2744,9 +2744,10 @@ kind, which is good enough.
 

Otherwise, we either know the kind already from polymorphism calculations, or -we can work it out by seeing what the initial value evaluates to. As usual, -we "round up to objects"; if the let-value is a kind of object, we make -the variable have kind "object", rather than some subkind. +we can work it out by seeing what the initial value evaluates to. Note that +with values which are objects, we guess the kind as the broadest subkind of +"object" to which the value belongs: in practice that means usually a thing, +a room or a region.

We make one exception to allow lines like — @@ -2784,12 +2785,14 @@ of a relation. Fail: the initial value of the local is the empty list13.1.1.2; if (Kinds::Behaviour::definite(seems_to_be) == FALSE) Fail: the initial value can't be stored13.1.1.3; - LOGIF(MATCHING, "(4A.c.1) Local variable seems to have kind: %u\n", seems_to_be); + LOGIF(MATCHING, "(4A.c.1) Local variable seems to have kind: %u (kind-like: %d)\n", + seems_to_be, Specifications::is_kind_like(initial_value)); K = seems_to_be; - if (Kinds::Behaviour::is_subkind_of_object(K)) - while (Kinds::eq(Latticework::super(K), K_object) == FALSE) - K = Latticework::super(K); + if (Specifications::is_kind_like(initial_value) == FALSE) + if (Kinds::Behaviour::is_subkind_of_object(K)) + while (Kinds::eq(Latticework::super(K), K_object) == FALSE) + K = Latticework::super(K); LOGIF(MATCHING, "(4A.c.1) Local variable inferred to have kind: %u\n", K);

diff --git a/inform7/Figures/timings-diagnostics.txt b/inform7/Figures/timings-diagnostics.txt index 914774a1c..df4ffa682 100644 --- a/inform7/Figures/timings-diagnostics.txt +++ b/inform7/Figures/timings-diagnostics.txt @@ -1,32 +1,33 @@ 100.0% in inform7 run - 71.1% in compilation to Inter - 50.4% in //Sequence::undertake_queued_tasks// - 4.7% in //MajorNodes::pre_pass// + 71.4% in compilation to Inter + 51.0% in //Sequence::undertake_queued_tasks// + 4.6% in //MajorNodes::pre_pass// 3.4% in //MajorNodes::pass_1// 1.8% in //ImperativeDefinitions::assess_all// 1.8% in //RTPhrasebook::compile_entries// 1.4% in //RTKindConstructors::compile// 1.0% in //Sequence::lint_inter// + 0.6% in //MajorNodes::pass_2// 0.6% in //Sequence::undertake_queued_tasks// 0.6% in //World::stage_V// 0.4% in //ImperativeDefinitions::compile_first_block// - 0.4% in //MajorNodes::pass_2// 0.4% in //Sequence::undertake_queued_tasks// 0.2% in //CompletionModule::compile// 0.2% in //InferenceSubjects::emit_all// 0.2% in //RTKindConstructors::compile_permissions// 0.2% in //Task::make_built_in_kind_constructors// - 3.1% not specifically accounted for - 26.2% in running Inter pipeline - 10.2% in step 14/15: generate inform6 -> auto.inf - 5.7% in step 5/15: load-binary-kits - 5.5% in step 6/15: make-synoptic-module + 0.2% in //World::stages_II_and_III// + 2.8% not specifically accounted for + 25.7% in running Inter pipeline + 10.4% in step 14/15: generate inform6 -> auto.inf + 5.6% in step 5/15: load-binary-kits + 5.2% in step 6/15: make-synoptic-module 1.4% in step 9/15: make-identifiers-unique 0.4% in step 12/15: eliminate-redundant-operations 0.4% in step 4/15: compile-splats 0.4% in step 7/15: shorten-wiring 0.4% in step 8/15: detect-indirect-calls 0.2% in step 11/15: eliminate-redundant-labels - 1.5% not specifically accounted for - 2.2% in supervisor + 1.3% not specifically accounted for + 2.4% in supervisor 0.5% not specifically accounted for diff --git a/inform7/imperative-module/Chapter 5/Compile Invocations Inline.w b/inform7/imperative-module/Chapter 5/Compile Invocations Inline.w index 2ba7471e9..f6762debd 100644 --- a/inform7/imperative-module/Chapter 5/Compile Invocations Inline.w +++ b/inform7/imperative-module/Chapter 5/Compile Invocations Inline.w @@ -1011,6 +1011,30 @@ of block value, like "list of numbers", it does nothing. This may seem odd, but the point is that locals of that kind are automatically set to their default values when created, so they are always typesafe anyway. +Note also that the Dash typechecker allows the creation of local variables +whose kinds are subkinds of objects which may have no instances. For example, +in this program: += (text) + A cat is a kind of animal. + To discuss the felines: + let C be a cat; + ... += +...it is legal to construct the variable |C| with kind |cat|, even though there +are no cats in the world, so that a call to |DefaultValues::val| would +generate a problem message. But we call |DefaultValues::val_allowing_nothing| +instead, so that |C| is created but with the value |nothing|. + +This would be easier to understand if Inform's kinds system supported "optionals". +In the Swift language, for example, there would be a clear distinction between +the types |Cat| (runtime values must be instances of cat) and |Cat?| (runtime +values must be instances of cat or else |nothing|). In Inform, cat-valued global +variables and properties have the type |Cat|, but cat-valued locals have the +type |Cat?|. We do this to make it more convenient to write functions about +cats which will compile whether or not any cats exist; an extension might provide +such functions, for example, providing functionality which is only used if cats +do exist, but which should still compile without errors even if they do not. + @ = parse_node *V = CSIInline::parse_bracing_operand_as_identifier(ist->operand, idb, tokens, my_vars); @@ -1037,9 +1061,8 @@ default values when created, so they are always typesafe anyway. EmitCode::down(); inter_symbol *lvar_s = LocalVariables::declare(lvar); EmitCode::ref_symbol(K_value, lvar_s); - rv = DefaultValues::val(K, Node::get_text(V), "value"); + rv = DefaultValues::val_allowing_nothing(K, Node::get_text(V), "value"); EmitCode::up(); - if (rv == FALSE) { Problems::quote_source(1, current_sentence); Problems::quote_kind(2, K); diff --git a/inform7/runtime-module/Chapter 2/Default Values.w b/inform7/runtime-module/Chapter 2/Default Values.w index 1d23b064d..cfba7d868 100644 --- a/inform7/runtime-module/Chapter 2/Default Values.w +++ b/inform7/runtime-module/Chapter 2/Default Values.w @@ -16,19 +16,25 @@ messages. = int DefaultValues::array_entry(kind *K, wording W, char *storage_name) { value_holster VH = Holsters::new(INTER_DATA_VHMODE); - int rv = DefaultValues::to_holster(&VH, K, W, storage_name); + int rv = DefaultValues::to_holster(&VH, K, W, storage_name, FALSE); inter_pair val = Holsters::unholster_to_pair(&VH); EmitArrays::generic_entry(val); return rv; } int DefaultValues::val(kind *K, wording W, char *storage_name) { value_holster VH = Holsters::new(INTER_DATA_VHMODE); - int rv = DefaultValues::to_holster(&VH, K, W, storage_name); + int rv = DefaultValues::to_holster(&VH, K, W, storage_name, FALSE); + Holsters::unholster_to_code_val(Emit::tree(), &VH); + return rv; +} +int DefaultValues::val_allowing_nothing(kind *K, wording W, char *storage_name) { + value_holster VH = Holsters::new(INTER_DATA_VHMODE); + int rv = DefaultValues::to_holster(&VH, K, W, storage_name, TRUE); Holsters::unholster_to_code_val(Emit::tree(), &VH); return rv; } int DefaultValues::to_holster(value_holster *VH, kind *K, - wording W, char *storage_name) { + wording W, char *storage_name, int allow_nothing_object_as_default) { if (Kinds::eq(K, K_value)) @<"Value" is too vague to be the kind of a variable@>; if (Kinds::Behaviour::definite(K) == FALSE) @@ -47,7 +53,10 @@ int DefaultValues::to_holster(value_holster *VH, kind *K, } @ = - if (Wordings::nonempty(W)) { + if (allow_nothing_object_as_default) { + Holsters::holster_pair(VH, DefaultValues::to_value_pair(K_object)); + return TRUE; + } else if (Wordings::nonempty(W)) { Problems::quote_wording_as_source(1, W); Problems::quote_kind(2, K); Problems::quote_text(3, storage_name); diff --git a/inform7/runtime-module/Chapter 5/Properties.w b/inform7/runtime-module/Chapter 5/Properties.w index e964fa98b..56c577b51 100644 --- a/inform7/runtime-module/Chapter 5/Properties.w +++ b/inform7/runtime-module/Chapter 5/Properties.w @@ -235,7 +235,7 @@ int RTProperties::compile_vp_default_value(value_holster *VH, property *prn) { return TRUE; } kind *K = ValueProperties::kind(prn); - return DefaultValues::to_holster(VH, K, prn->name, "property"); + return DefaultValues::to_holster(VH, K, prn->name, "property", FALSE); } @h Schemas. diff --git a/inform7/runtime-module/Chapter 5/Variables.w b/inform7/runtime-module/Chapter 5/Variables.w index 510f7dccc..ea6f784f7 100644 --- a/inform7/runtime-module/Chapter 5/Variables.w +++ b/inform7/runtime-module/Chapter 5/Variables.w @@ -431,7 +431,8 @@ void RTVariables::holster_initial_value(value_holster *VH, nonlocal_variable *nl } @ = - if (DefaultValues::to_holster(VH, nlv->nlv_kind, nlv->name, "variable") == FALSE) { + if (DefaultValues::to_holster(VH, nlv->nlv_kind, nlv->name, "variable", FALSE) + == FALSE) { if (nlv->var_is_allowed_to_be_zero) { Holsters::holster_pair(VH, InterValuePairs::number(0)); } else { diff --git a/inform7/values-module/Chapter 5/Dash.w b/inform7/values-module/Chapter 5/Dash.w index 428cf130b..35076bc87 100644 --- a/inform7/values-module/Chapter 5/Dash.w +++ b/inform7/values-module/Chapter 5/Dash.w @@ -2181,9 +2181,10 @@ This doesn't give us an initial value as such, but it explicitly tells us the kind, which is good enough. Otherwise, we either know the kind already from polymorphism calculations, or -we can work it out by seeing what the initial value evaluates to. As usual, -we "round up to objects"; if the let-value is a kind of object, we make -the variable have kind "object", rather than some subkind. +we can work it out by seeing what the initial value evaluates to. Note that +with values which are objects, we guess the kind as the broadest subkind of +"object" to which the value belongs: in practice that means usually a thing, +a room or a region. We make one exception to allow lines like -- @@ -2213,12 +2214,14 @@ of a relation. @; if (Kinds::Behaviour::definite(seems_to_be) == FALSE) @; - LOGIF(MATCHING, "(4A.c.1) Local variable seems to have kind: %u\n", seems_to_be); + LOGIF(MATCHING, "(4A.c.1) Local variable seems to have kind: %u (kind-like: %d)\n", + seems_to_be, Specifications::is_kind_like(initial_value)); K = seems_to_be; - if (Kinds::Behaviour::is_subkind_of_object(K)) - while (Kinds::eq(Latticework::super(K), K_object) == FALSE) - K = Latticework::super(K); + if (Specifications::is_kind_like(initial_value) == FALSE) + if (Kinds::Behaviour::is_subkind_of_object(K)) + while (Kinds::eq(Latticework::super(K), K_object) == FALSE) + K = Latticework::super(K); LOGIF(MATCHING, "(4A.c.1) Local variable inferred to have kind: %u\n", K); @ =