Skip to content

Commit

Permalink
Adjust PRIM_QUERY for fileReader/fileWriter (chapel-lang#23308)
Browse files Browse the repository at this point in the history
This PR adjusts the implementation of PRIM_QUERY during resolution
specifically for the ``fileReader`` and ``fileWriter`` types. While
these types have had their ``kind`` field deprecated, it is still
technically the first generic field in the type. This PR modifies the
PRIM_QUERY implementation to skip the 'kind' field unless it is
explicitly specified. A deprecation test is also added exercising
various queries.

Note: The production compiler currently inserts PRIM_QUERY calls into a
'where' clause during the ``normalize`` pass even when queries are not
present. For example, a type expression like ``R(int)`` would see a
where-clause generated comparing ``int`` to the first generic field in
``R``.

[reviewed-by @mppf]
  • Loading branch information
benharsh authored Sep 12, 2023
2 parents abc2232 + 74afa0f commit d4880d6
Show file tree
Hide file tree
Showing 3 changed files with 410 additions and 1 deletion.
25 changes: 24 additions & 1 deletion compiler/resolution/preFold.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2982,7 +2982,19 @@ static Symbol* determineQueriedField(CallExpr* call) {

} else {
Vec<Symbol*> args;
int position = var->immediate->int_value();
int position = var->immediate->int_value();

// A couple of variables to help us deal with the deprecated 'kind' field
// in fileReader and fileWriter.
bool isReaderWriter = false;
bool specifiesKind = false;

{
AggregateType* root = at->getRootInstantiation();
isReaderWriter = root->getModule() == ioModule &&
(strcmp(root->symbol->name, "fileReader") == 0 ||
strcmp(root->symbol->name, "fileWriter") == 0);
}

if (at->symbol->hasFlag(FLAG_TUPLE)) {
return at->getField(position);
Expand Down Expand Up @@ -3019,6 +3031,11 @@ static Symbol* determineQueriedField(CallExpr* call) {

INT_ASSERT(var->immediate->const_kind == CONST_KIND_STRING);

if (isReaderWriter &&
strcmp("kind", var->immediate->v_string.c_str()) == 0) {
specifiesKind = true;
}

for (int j = 0; j < args.n; j++) {
if (args.v[j] != NULL &&
strcmp(args.v[j]->name, var->immediate->v_string.c_str()) == 0) {
Expand All @@ -3027,6 +3044,12 @@ static Symbol* determineQueriedField(CallExpr* call) {
}
}

// Need to increment by one so that expressions like 'fileWriter(false)'
// match up correctly.
if (isReaderWriter && !specifiesKind) {
position += 1;
}

forv_Vec(Symbol, arg, args) {
if (arg != NULL) {
if (position == 1) {
Expand Down
106 changes: 106 additions & 0 deletions test/deprecated/IO/iokind/kind-queries.chpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
use IO;
use JSON;

// Part 1: make sure we can specify locking and (de)serializerType
// positionally.

proc foo(writer: fileWriter(?)) {
writeln("foo: fully generic: ", writer.type:string);
}

proc foo(writer: fileWriter(false, defaultSerializer)) {
writeln("foo: fileWriter(false): ", writer.type:string);
}

proc foo(reader: fileReader(?)) {
writeln("foo: fully generic: ", reader.type:string);
}

proc foo(reader: fileReader(false, defaultDeserializer)) {
writeln("foo: fileReader(false): ", reader.type:string);
}

// Part 2: make sure we can specify kind with a named arg

proc bar(writer: fileWriter(?)) {
writeln("bar: fileWriter(?): ", writer.type:string);
}

proc bar(writer: fileWriter(kind=_iokind.native, ?)) {
writeln("bar: fileWriter(kind=iokind.native, ?): ", writer.type:string);
}

proc bar(reader: fileReader(?)) {
writeln("bar: fileReader(?): ", reader.type:string);
}

proc bar(reader: fileReader(kind=_iokind.native, ?)) {
writeln("bar: fileReader(kind=iokind.native, ?): ", reader.type:string);
}

// Part 3: various actual queries of generic fields

proc query(writer: fileWriter(?L, ?ST)) {
writeln("L = ", L:string, " :: ST = ", ST:string);
}

proc query(reader: fileReader(?L, ?DT)) {
writeln("L = ", L:string, " :: DT = ", DT:string);
}

proc queryNamed(writer: fileWriter(locking=?L, serializerType=?ST)) {
writeln("L = ", L:string, " :: ST = ", ST:string);
}

proc queryNamed(reader: fileReader(locking=?L, deserializerType=?DT)) {
writeln("L = ", L:string, " :: DT = ", DT:string);
}

proc queryKind(writer: fileWriter(kind=?K, ?L, ?ST)) {
writeln("L = ", L:string, " :: ST = ", ST:string, " :: K = ", K:string);
}

proc queryKind(reader: fileReader(kind=?K, ?L, ?DT)) {
writeln("L = ", L:string, " :: DT = ", DT:string, " :: K = ", K:string);
}

proc queryKindLast(writer: fileWriter(?L, ?ST, kind=?K)) {
writeln("L = ", L:string, " :: ST = ", ST:string, " :: K = ", K:string);
}

proc queryKindLast(reader: fileReader(?L, ?DT, kind=?K)) {
writeln("L = ", L:string, " :: DT = ", DT:string, " :: K = ", K:string);
}

proc helper(type channel, param locking: bool, type deserType) {
type T = if channel == fileWriter(?) then deserType
else if deserType == defaultSerializer then defaultDeserializer
else if deserType == jsonSerializer then jsonDeserializer
else nothing;
var w : channel(locking, T);
writeln("----- ", w.type:string, " -----");
foo(w);
bar(w);
query(w);
queryNamed(w);
queryKind(w);
queryKindLast(w);
{
var nw : channel(_iokind.native, locking, T);
bar(nw);
queryKind(nw);
}
writeln();
}

proc helper(param locking: bool, type deserType) {
helper(fileWriter(?), locking, deserType);
helper(fileReader(?), locking, deserType);
}

proc main() {
helper(true, defaultSerializer);
helper(false, defaultSerializer);
helper(true, jsonSerializer);
helper(false, jsonSerializer);
}
Loading

0 comments on commit d4880d6

Please sign in to comment.