diff --git a/compiler/AST/AggregateType.cpp b/compiler/AST/AggregateType.cpp index d8b84a474415..a743f83f4dbe 100644 --- a/compiler/AST/AggregateType.cpp +++ b/compiler/AST/AggregateType.cpp @@ -2297,7 +2297,8 @@ void AggregateType::buildDefaultInitializer() { } else { USR_FATAL(this, "Unable to generate initializer for type '%s'", this->symbol->name); } - } else { + } else { // Handle unions + /* 0-arg initializer */ DefExpr* def = new DefExpr(fn); symbol->defPoint->insertBefore(def); @@ -2311,6 +2312,91 @@ void AggregateType::buildDefaultInitializer() { normalize(fn); methods.add(fn); + + /* 1-arg initializers */ + for_fields(fieldDefExpr, this) { + SET_LINENO(this); + FnSymbol* fn = new FnSymbol("init"); + fn->cname = fn->name; + + fn->addFlag(FLAG_COMPILER_GENERATED); + fn->addFlag(FLAG_LAST_RESORT); + fn->addFlag(FLAG_SUPPRESS_LVALUE_ERRORS); + + ArgSymbol* _mt = new ArgSymbol(INTENT_BLANK, "_mt", dtMethodToken); + fn->insertFormalAtTail(_mt); + + ArgSymbol* _this = new ArgSymbol(INTENT_BLANK, "this", this); + fn->_this = _this; + _this->addFlag(FLAG_ARG_THIS); + fn->insertFormalAtTail(_this); + + fn->insertAtTail(new CallExpr(PRIM_SET_UNION_ID, + fn->_this, + new_IntSymbol(-1))); + + { + SET_LINENO(fieldDefExpr); + VarSymbol* field = toVarSymbol(fieldDefExpr); + if (!field) { + INT_FATAL("unexpected: fieldDefExpr can't be made a VarSymbol"); + } + assert(!field->hasFlag(FLAG_SUPER_CLASS)); + + DefExpr* defPoint = field->defPoint; + const char* name = field->name; + ArgSymbol* arg = new ArgSymbol(INTENT_IN, name, dtUnknown); + + if (field->hasEitherFlag(FLAG_TYPE_VARIABLE, FLAG_PARAM)) { + USR_FATAL(arg, "union types don't currently support `type` or `param` fields"); + } + + { + SET_LINENO(field); + + if (field->hasFlag(FLAG_UNSAFE)) + arg->addFlag(FLAG_UNSAFE); + + // TODO: We should really do this somewhere else, and let this + // method focus on the initializer and not modify the type's fields. + if (LoopExpr* fe = toLoopExpr(defPoint->init)) { + if (field->isType() == false) { + if (defPoint->exprType == NULL) { + CallExpr* copy = new CallExpr(astr_initCopy); + defPoint->init->replace(copy); + + Symbol *definedConst = defPoint->sym->hasFlag(FLAG_CONST) ? + gTrue : gFalse; + copy->insertAtTail(fe); + copy->insertAtTail(definedConst); + } + } + } + + if (defPoint->exprType == NULL) { + USR_FATAL(field, "currently, union fields must have a declared type"); + } else if (defPoint->init == NULL) { + fieldToArgType(defPoint, arg); + } else { + USR_FATAL(field, "currently, union fields cannot have initializer expressions"); + } + fn->insertFormalAtTail(arg); + fn->insertAtTail(new CallExpr("=", new CallExpr(".", + fn->_this, + new_CStringSymbol(name)), + arg)); + } + } + + DefExpr* def = new DefExpr(fn); + symbol->defPoint->insertBefore(def); + fn->setMethod(true); + fn->addFlag(FLAG_METHOD_PRIMARY); + preNormalizeInitMethod(fn); + normalize(fn); + checkUseBeforeDefs(fn); + methods.add(fn); + } } builtDefaultInit = true; @@ -3141,6 +3227,14 @@ void AggregateType::setCreationStyle(TypeSymbol* t, FnSymbol* fn) { USR_FATAL(fn, "an initializer cannot be declared without parentheses"); } + // For a user-defined union initializer to work properly, the active + // field indicator must be initialized to -1 + if (ct->isUnion()) { + fn->insertAtHead(new CallExpr(PRIM_SET_UNION_ID, + fn->_this, + new_IntSymbol(-1))); + } + if (ct->hasUserDefinedInit == false) { // We hadn't previously seen an initializer definition. // Update the field on the type appropriately. diff --git a/test/classes/diten/constructUnion.bad b/test/classes/diten/constructUnion.bad deleted file mode 100644 index 6bb558ddd45d..000000000000 --- a/test/classes/diten/constructUnion.bad +++ /dev/null @@ -1,4 +0,0 @@ -constructUnion.chpl:6: error: unresolved call 'IntOrReal.init(i=1)' -constructUnion.chpl:1: note: this candidate did not match: IntOrReal.init() -constructUnion.chpl:6: note: because call uses named argument i -constructUnion.chpl:1: note: but function contains no formal named i diff --git a/test/classes/diten/constructUnion.future b/test/classes/diten/constructUnion.future deleted file mode 100644 index 0775dfe15625..000000000000 --- a/test/classes/diten/constructUnion.future +++ /dev/null @@ -1,2 +0,0 @@ -design: union should be initializable with a single field -#15189 diff --git a/test/library/standard/Reflection/field-queries-ok.chpl b/test/library/standard/Reflection/field-queries-ok.chpl index 1769d1a3b3d1..0fe8a089a80f 100644 --- a/test/library/standard/Reflection/field-queries-ok.chpl +++ b/test/library/standard/Reflection/field-queries-ok.chpl @@ -64,11 +64,4 @@ union UCon { test(UCon); -union UGen { - var f1, f2, f3, f4, f5, f6; -} - -test(UGen(?)); - - compilerError("=== done ==="); diff --git a/test/library/standard/Reflection/field-queries-ok.good b/test/library/standard/Reflection/field-queries-ok.good index 4c97145879d6..ec09d27c8996 100644 --- a/test/library/standard/Reflection/field-queries-ok.good +++ b/test/library/standard/Reflection/field-queries-ok.good @@ -145,11 +145,4 @@ field-queries-ok.chpl:64: warning: hasField true field-queries-ok.chpl:64: warning: getFieldIndex 5 field-queries-ok.chpl:64: warning: isFieldBound 5 true field-queries-ok.chpl:64: warning: isFieldBound f6 true -field-queries-ok.chpl:71: warning: ===== UGen -field-queries-ok.chpl:71: warning: getNumFields 6 -field-queries-ok.chpl:71: warning: getFieldName f6 -field-queries-ok.chpl:71: warning: hasField true -field-queries-ok.chpl:71: warning: getFieldIndex 5 -field-queries-ok.chpl:71: warning: isFieldBound 5 false -field-queries-ok.chpl:71: warning: isFieldBound f6 false -field-queries-ok.chpl:74: error: === done === +field-queries-ok.chpl:67: error: === done === diff --git a/test/types/unions/union-compgen-init.chpl b/test/types/unions/union-compgen-init.chpl new file mode 100644 index 000000000000..4891633d904d --- /dev/null +++ b/test/types/unions/union-compgen-init.chpl @@ -0,0 +1,18 @@ +union u { + var w: int; + var x: int; + var y: real; + var z: string; +} + +var u0 = new u(), + u1 = new u(w=45), + u2 = new u(x=78), + u3 = new u(y=33.3), + u4 = new u(z="hi"); + +writeln(u0); +writeln(u1); +writeln(u2); +writeln(u3); +writeln(u4); diff --git a/test/types/unions/union-compgen-init.good b/test/types/unions/union-compgen-init.good new file mode 100644 index 000000000000..916c37bf17b3 --- /dev/null +++ b/test/types/unions/union-compgen-init.good @@ -0,0 +1,5 @@ +() +(w = 45) +(x = 78) +(y = 33.3) +(z = hi) diff --git a/test/types/unions/union-init1.good b/test/types/unions/union-init1.good index 758ff5464b69..1260bc9e8962 100644 --- a/test/types/unions/union-init1.good +++ b/test/types/unions/union-init1.good @@ -3,3 +3,6 @@ union-init1.chpl:7: error: unresolved call 'U.init(x=1, y=20.0)' union-init1.chpl:1: note: this candidate did not match: U.init() union-init1.chpl:7: note: because call uses named argument x union-init1.chpl:1: note: but function contains no formal named x +union-init1.chpl:7: note: other candidates are: +union-init1.chpl:1: note: U.init(x: int(64)) +union-init1.chpl:1: note: U.init(y: real(64)) diff --git a/test/types/unions/union-init2.bad b/test/types/unions/union-init2.bad deleted file mode 100644 index da5f245419e4..000000000000 --- a/test/types/unions/union-init2.bad +++ /dev/null @@ -1,5 +0,0 @@ -union-init2.chpl:6: In function 'main': -union-init2.chpl:7: error: unresolved call 'U.init(y=20.0)' -union-init2.chpl:1: note: this candidate did not match: U.init() -union-init2.chpl:7: note: because call uses named argument y -union-init2.chpl:1: note: but function contains no formal named y diff --git a/test/types/unions/union-init2.future b/test/types/unions/union-init2.future deleted file mode 100644 index 0775dfe15625..000000000000 --- a/test/types/unions/union-init2.future +++ /dev/null @@ -1,2 +0,0 @@ -design: union should be initializable with a single field -#15189 diff --git a/test/types/unions/union-init3.future b/test/types/unions/union-init3.future deleted file mode 100644 index a8880a23ada8..000000000000 --- a/test/types/unions/union-init3.future +++ /dev/null @@ -1,2 +0,0 @@ -design: should be able to write single arg initializer for union -#15189 diff --git a/test/types/unions/union-init3.skipif b/test/types/unions/union-init3.skipif deleted file mode 100644 index 393ecc867dde..000000000000 --- a/test/types/unions/union-init3.skipif +++ /dev/null @@ -1 +0,0 @@ -CHPL_TEST_VGRND_EXE != on diff --git a/test/types/unions/union-typelessField.chpl b/test/types/unions/union-typelessField.chpl new file mode 100644 index 000000000000..cf3bce506a87 --- /dev/null +++ b/test/types/unions/union-typelessField.chpl @@ -0,0 +1,9 @@ +union u { + var x, y, z; +} + +var myU: u; +myU.x = 42; +writeln(myU); +myU.y = "hi"; + diff --git a/test/types/unions/union-typelessField.good b/test/types/unions/union-typelessField.good new file mode 100644 index 000000000000..64f9dea6843b --- /dev/null +++ b/test/types/unions/union-typelessField.good @@ -0,0 +1 @@ +union-typelessField.chpl:2: error: currently, union fields must have a declared type diff --git a/test/types/unions/union-typelessField2.chpl b/test/types/unions/union-typelessField2.chpl new file mode 100644 index 000000000000..4945f914c915 --- /dev/null +++ b/test/types/unions/union-typelessField2.chpl @@ -0,0 +1,11 @@ +union u { + var x; + var y; + var z; +} + +var myU: u; +myU.x = 42; +writeln(myU); +myU.y = "hi"; + diff --git a/test/types/unions/union-typelessField2.good b/test/types/unions/union-typelessField2.good new file mode 100644 index 000000000000..dfffabd5d04c --- /dev/null +++ b/test/types/unions/union-typelessField2.good @@ -0,0 +1,3 @@ +union-typelessField2.chpl:2: error: union fields must have an explicit type +union-typelessField2.chpl:3: error: union fields must have an explicit type +union-typelessField2.chpl:4: error: union fields must have an explicit type