Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 95 additions & 1 deletion compiler/AST/AggregateType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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;
Expand Down Expand Up @@ -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.
Expand Down
4 changes: 0 additions & 4 deletions test/classes/diten/constructUnion.bad

This file was deleted.

2 changes: 0 additions & 2 deletions test/classes/diten/constructUnion.future

This file was deleted.

7 changes: 0 additions & 7 deletions test/library/standard/Reflection/field-queries-ok.chpl
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,4 @@ union UCon {
test(UCon);


union UGen {
var f1, f2, f3, f4, f5, f6;
}

test(UGen(?));


compilerError("=== done ===");
9 changes: 1 addition & 8 deletions test/library/standard/Reflection/field-queries-ok.good
Original file line number Diff line number Diff line change
Expand Up @@ -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 ===
18 changes: 18 additions & 0 deletions test/types/unions/union-compgen-init.chpl
Original file line number Diff line number Diff line change
@@ -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);
5 changes: 5 additions & 0 deletions test/types/unions/union-compgen-init.good
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
()
(w = 45)
(x = 78)
(y = 33.3)
(z = hi)
3 changes: 3 additions & 0 deletions test/types/unions/union-init1.good
Original file line number Diff line number Diff line change
Expand Up @@ -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))
5 changes: 0 additions & 5 deletions test/types/unions/union-init2.bad

This file was deleted.

2 changes: 0 additions & 2 deletions test/types/unions/union-init2.future

This file was deleted.

2 changes: 0 additions & 2 deletions test/types/unions/union-init3.future

This file was deleted.

1 change: 0 additions & 1 deletion test/types/unions/union-init3.skipif

This file was deleted.

9 changes: 9 additions & 0 deletions test/types/unions/union-typelessField.chpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
union u {
var x, y, z;
}

var myU: u;
myU.x = 42;
writeln(myU);
myU.y = "hi";

1 change: 1 addition & 0 deletions test/types/unions/union-typelessField.good
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
union-typelessField.chpl:2: error: currently, union fields must have a declared type
11 changes: 11 additions & 0 deletions test/types/unions/union-typelessField2.chpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
union u {
var x;
var y;
var z;
}

var myU: u;
myU.x = 42;
writeln(myU);
myU.y = "hi";

3 changes: 3 additions & 0 deletions test/types/unions/union-typelessField2.good
Original file line number Diff line number Diff line change
@@ -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