[TableGen] Change !getop and !setop to !getdagop and !setdagop.

Differential Revision: https://reviews.llvm.org/D89814
This commit is contained in:
Paul C. Anagnostopoulos 2020-10-20 13:50:49 -04:00
parent 8a59d4b654
commit 876af264c1
9 changed files with 71 additions and 63 deletions

View File

@ -545,8 +545,8 @@ multiclass Reduction<Type Accumulator, string basename, list<Type> basetypes,
defvar intArgsUnpred = !con(intArgsBase, defvar intArgsUnpred = !con(intArgsBase,
!if(needSign, (? (unsignedflag Scalar)), (?))); !if(needSign, (? (unsignedflag Scalar)), (?)));
defvar intArgsPred = !con(intArgsUnpred, (? $pred)); defvar intArgsPred = !con(intArgsUnpred, (? $pred));
defvar intUnpred = !setop(intArgsUnpred, IRInt<basename, basetypes>); defvar intUnpred = !setdagop(intArgsUnpred, IRInt<basename, basetypes>);
defvar intPred = !setop(intArgsPred, IRInt< defvar intPred = !setdagop(intArgsPred, IRInt<
basename#"_predicated", !listconcat(basetypes, [Predicate])>); basename#"_predicated", !listconcat(basetypes, [Predicate])>);
def "": Intrinsic< def "": Intrinsic<

View File

@ -206,13 +206,13 @@ TableGen provides "bang operators" that have a wide variety of uses:
.. productionlist:: .. productionlist::
BangOperator: one of BangOperator: one of
: !add !and !cast !con !dag : !add !and !cast !con !dag
: !empty !eq !foldl !foreach !ge : !empty !eq !foldl !foreach !ge
: !getop !gt !head !if !isa : !getdagop !gt !head !if !isa
: !le !listconcat !listsplat !lt !mul : !le !listconcat !listsplat !lt !mul
: !ne !not !or !setop !shl : !ne !not !or !setdagop !shl
: !size !sra !srl !strconcat !subst : !size !sra !srl !strconcat !subst
: !tail !xor : !tail !xor
The ``!cond`` operator has a slightly different The ``!cond`` operator has a slightly different
syntax compared to other bang operators, so it is defined separately: syntax compared to other bang operators, so it is defined separately:
@ -1243,7 +1243,7 @@ or to associate an argument in one DAG with a like-named argument in another
DAG. DAG.
The following bang operators are useful for working with DAGs: The following bang operators are useful for working with DAGs:
``!con``, ``!dag``, ``!empty``, ``!foreach``, ``!getop``, ``!setop``, ``!size``. ``!con``, ``!dag``, ``!empty``, ``!foreach``, ``!getdagop``, ``!setdagop``, ``!size``.
Defvar in a record body Defvar in a record body
----------------------- -----------------------
@ -1445,6 +1445,10 @@ operator produces a boolean result, the result value will be 1 for true or 0
for false. When an operator tests a boolean argument, it interprets 0 as false for false. When an operator tests a boolean argument, it interprets 0 as false
and non-0 as true. and non-0 as true.
.. warning::
The ``!getop`` and ``!setop`` bang operators are deprecated in favor of
``!getdagop`` and ``!setdagop``.
``!add(``\ *a*\ ``,`` *b*\ ``, ...)`` ``!add(``\ *a*\ ``,`` *b*\ ``, ...)``
This operator adds *a*, *b*, etc., and produces the sum. This operator adds *a*, *b*, etc., and produces the sum.
@ -1544,26 +1548,27 @@ and non-0 as true.
The arguments must be ``bit``, ``int``, or ``string`` values. The arguments must be ``bit``, ``int``, or ``string`` values.
Use ``!cast<string>`` to compare other types of objects. Use ``!cast<string>`` to compare other types of objects.
``!getop(``\ *dag*\ ``)`` --or-- ``!getop<``\ *type*\ ``>(``\ *dag*\ ``)`` ``!getdagop(``\ *dag*\ ``)`` --or-- ``!getdagop<``\ *type*\ ``>(``\ *dag*\ ``)``
This operator produces the operator of the given *dag* node. This operator produces the operator of the given *dag* node.
Example: ``!getop((foo 1, 2))`` results in ``foo``. Example: ``!getdagop((foo 1, 2))`` results in ``foo``. Recall that
DAG operators are always records.
The result of ``!getop`` can be used directly in a context where The result of ``!getdagop`` can be used directly in a context where
any record value at all is acceptable (typically placing it into any record class at all is acceptable (typically placing it into
another dag value). But in other contexts, it must be explicitly another dag value). But in other contexts, it must be explicitly
cast to a particular class type. The ``<``\ *type*\ ``>`` syntax is cast to a particular class. The ``<``\ *type*\ ``>`` syntax is
provided to make this easy. provided to make this easy.
For example, to assign the result to a value of type ``BaseClass``, you For example, to assign the result to a value of type ``BaseClass``, you
could write either of these:: could write either of these::
BaseClass b = !getop<BaseClass>(someDag); BaseClass b = !getdagop<BaseClass>(someDag);
BaseClass b = !cast<BaseClass>(!getop(someDag)); BaseClass b = !cast<BaseClass>(!getdagop(someDag));
But to create a new DAG node that reuses the operator from another, no But to create a new DAG node that reuses the operator from another, no
cast is necessary:: cast is necessary::
dag d = !dag(!getop(someDag), args, names); dag d = !dag(!getdagop(someDag), args, names);
``!gt(``\ *a*\ `,` *b*\ ``)`` ``!gt(``\ *a*\ `,` *b*\ ``)``
This operator produces 1 if *a* is greater than *b*; 0 otherwise. This operator produces 1 if *a* is greater than *b*; 0 otherwise.
@ -1620,11 +1625,11 @@ and non-0 as true.
result. A logical OR can be performed if all the arguments are either result. A logical OR can be performed if all the arguments are either
0 or 1. 0 or 1.
``!setop(``\ *dag*\ ``,`` *op*\ ``)`` ``!setdagop(``\ *dag*\ ``,`` *op*\ ``)``
This operator produces a DAG node with the same arguments as *dag*, but with its This operator produces a DAG node with the same arguments as *dag*, but with its
operator replaced with *op*. operator replaced with *op*.
Example: ``!setop((foo 1, 2), bar)`` results in ``(bar 1, 2)``. Example: ``!setdagop((foo 1, 2), bar)`` results in ``(bar 1, 2)``.
``!shl(``\ *a*\ ``,`` *count*\ ``)`` ``!shl(``\ *a*\ ``,`` *count*\ ``)``
This operator shifts *a* left logically by *count* bits and produces the resulting This operator shifts *a* left logically by *count* bits and produces the resulting

View File

@ -759,7 +759,7 @@ public:
/// ///
class UnOpInit : public OpInit, public FoldingSetNode { class UnOpInit : public OpInit, public FoldingSetNode {
public: public:
enum UnaryOp : uint8_t { CAST, NOT, HEAD, TAIL, SIZE, EMPTY, GETOP }; enum UnaryOp : uint8_t { CAST, NOT, HEAD, TAIL, SIZE, EMPTY, GETDAGOP };
private: private:
Init *LHS; Init *LHS;
@ -810,7 +810,7 @@ class BinOpInit : public OpInit, public FoldingSetNode {
public: public:
enum BinaryOp : uint8_t { ADD, MUL, AND, OR, XOR, SHL, SRA, SRL, LISTCONCAT, enum BinaryOp : uint8_t { ADD, MUL, AND, OR, XOR, SHL, SRA, SRL, LISTCONCAT,
LISTSPLAT, STRCONCAT, CONCAT, EQ, NE, LE, LT, GE, LISTSPLAT, STRCONCAT, CONCAT, EQ, NE, LE, LT, GE,
GT, SETOP }; GT, SETDAGOP };
private: private:
Init *LHS, *RHS; Init *LHS, *RHS;

View File

@ -801,7 +801,7 @@ Init *UnOpInit::Fold(Record *CurRec, bool IsFinal) const {
return IntInit::get(LHSs->getValue().empty()); return IntInit::get(LHSs->getValue().empty());
break; break;
case GETOP: case GETDAGOP:
if (DagInit *Dag = dyn_cast<DagInit>(LHS)) { if (DagInit *Dag = dyn_cast<DagInit>(LHS)) {
DefInit *DI = DefInit::get(Dag->getOperatorAsDef({})); DefInit *DI = DefInit::get(Dag->getOperatorAsDef({}));
if (!DI->getType()->typeIsA(getType())) { if (!DI->getType()->typeIsA(getType())) {
@ -837,7 +837,7 @@ std::string UnOpInit::getAsString() const {
case TAIL: Result = "!tail"; break; case TAIL: Result = "!tail"; break;
case SIZE: Result = "!size"; break; case SIZE: Result = "!size"; break;
case EMPTY: Result = "!empty"; break; case EMPTY: Result = "!empty"; break;
case GETOP: Result = "!getop"; break; case GETDAGOP: Result = "!getdagop"; break;
} }
return Result + "(" + LHS->getAsString() + ")"; return Result + "(" + LHS->getAsString() + ")";
} }
@ -1009,7 +1009,7 @@ Init *BinOpInit::Fold(Record *CurRec) const {
break; break;
} }
case SETOP: { case SETDAGOP: {
DagInit *Dag = dyn_cast<DagInit>(LHS); DagInit *Dag = dyn_cast<DagInit>(LHS);
DefInit *Op = dyn_cast<DefInit>(RHS); DefInit *Op = dyn_cast<DefInit>(RHS);
if (Dag && Op) { if (Dag && Op) {
@ -1088,7 +1088,7 @@ std::string BinOpInit::getAsString() const {
case LISTCONCAT: Result = "!listconcat"; break; case LISTCONCAT: Result = "!listconcat"; break;
case LISTSPLAT: Result = "!listsplat"; break; case LISTSPLAT: Result = "!listsplat"; break;
case STRCONCAT: Result = "!strconcat"; break; case STRCONCAT: Result = "!strconcat"; break;
case SETOP: Result = "!setop"; break; case SETDAGOP: Result = "!setdagop"; break;
} }
return Result + "(" + LHS->getAsString() + ", " + RHS->getAsString() + ")"; return Result + "(" + LHS->getAsString() + ", " + RHS->getAsString() + ")";
} }

View File

@ -578,8 +578,8 @@ tgtok::TokKind TGLexer::LexExclaim() {
.Case("listconcat", tgtok::XListConcat) .Case("listconcat", tgtok::XListConcat)
.Case("listsplat", tgtok::XListSplat) .Case("listsplat", tgtok::XListSplat)
.Case("strconcat", tgtok::XStrConcat) .Case("strconcat", tgtok::XStrConcat)
.Case("setop", tgtok::XSetOp) .Cases("setdagop", "setop", tgtok::XSetDagOp) // !setop is deprecated.
.Case("getop", tgtok::XGetOp) .Cases("getdagop", "getop", tgtok::XGetDagOp) // !getop is deprecated.
.Default(tgtok::Error); .Default(tgtok::Error);
return Kind != tgtok::Error ? Kind : ReturnError(Start-1, "Unknown operator"); return Kind != tgtok::Error ? Kind : ReturnError(Start-1, "Unknown operator");

View File

@ -54,7 +54,7 @@ namespace tgtok {
XConcat, XADD, XMUL, XNOT, XAND, XOR, XXOR, XSRA, XSRL, XSHL, XConcat, XADD, XMUL, XNOT, XAND, XOR, XXOR, XSRA, XSRL, XSHL,
XListConcat, XListSplat, XStrConcat, XCast, XSubst, XForEach, XFoldl, XListConcat, XListSplat, XStrConcat, XCast, XSubst, XForEach, XFoldl,
XHead, XTail, XSize, XEmpty, XIf, XCond, XEq, XIsA, XDag, XNe, XLe, XHead, XTail, XSize, XEmpty, XIf, XCond, XEq, XIsA, XDag, XNe, XLe,
XLt, XGe, XGt, XSetOp, XGetOp, XLt, XGe, XGt, XSetDagOp, XGetDagOp,
// Integer value. // Integer value.
IntVal, IntVal,

View File

@ -813,12 +813,12 @@ RecTy *TGParser::ParseType() {
TokError("expected '<' after bits type"); TokError("expected '<' after bits type");
return nullptr; return nullptr;
} }
if (Lex.Lex() != tgtok::IntVal) { // Eat '<' if (Lex.Lex() != tgtok::IntVal) { // Eat '<'
TokError("expected integer in bits<n> type"); TokError("expected integer in bits<n> type");
return nullptr; return nullptr;
} }
uint64_t Val = Lex.getCurIntVal(); uint64_t Val = Lex.getCurIntVal();
if (Lex.Lex() != tgtok::greater) { // Eat count. if (Lex.Lex() != tgtok::greater) { // Eat count.
TokError("expected '>' at end of bits<n> type"); TokError("expected '>' at end of bits<n> type");
return nullptr; return nullptr;
} }
@ -914,7 +914,7 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
case tgtok::XSize: case tgtok::XSize:
case tgtok::XEmpty: case tgtok::XEmpty:
case tgtok::XCast: case tgtok::XCast:
case tgtok::XGetOp: { // Value ::= !unop '(' Value ')' case tgtok::XGetDagOp: { // Value ::= !unop '(' Value ')'
UnOpInit::UnaryOp Code; UnOpInit::UnaryOp Code;
RecTy *Type = nullptr; RecTy *Type = nullptr;
@ -955,12 +955,12 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
Code = UnOpInit::EMPTY; Code = UnOpInit::EMPTY;
Type = IntRecTy::get(); Type = IntRecTy::get();
break; break;
case tgtok::XGetOp: case tgtok::XGetDagOp:
Lex.Lex(); // eat the operation Lex.Lex(); // eat the operation
if (Lex.getCode() == tgtok::less) { if (Lex.getCode() == tgtok::less) {
// Parse an optional type suffix, so that you can say // Parse an optional type suffix, so that you can say
// !getop<BaseClass>(someDag) as a shorthand for // !getdagop<BaseClass>(someDag) as a shorthand for
// !cast<BaseClass>(!getop(someDag)). // !cast<BaseClass>(!getdagop(someDag)).
Type = ParseOperatorType(); Type = ParseOperatorType();
if (!Type) { if (!Type) {
@ -969,13 +969,13 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
} }
if (!isa<RecordRecTy>(Type)) { if (!isa<RecordRecTy>(Type)) {
TokError("type for !getop must be a record type"); TokError("type for !getdagop must be a record type");
// but keep parsing, to consume the operand // but keep parsing, to consume the operand
} }
} else { } else {
Type = RecordRecTy::get({}); Type = RecordRecTy::get({});
} }
Code = UnOpInit::GETOP; Code = UnOpInit::GETDAGOP;
break; break;
} }
if (!consume(tgtok::l_paren)) { if (!consume(tgtok::l_paren)) {
@ -1091,7 +1091,7 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
case tgtok::XListConcat: case tgtok::XListConcat:
case tgtok::XListSplat: case tgtok::XListSplat:
case tgtok::XStrConcat: case tgtok::XStrConcat:
case tgtok::XSetOp: { // Value ::= !binop '(' Value ',' Value ')' case tgtok::XSetDagOp: { // Value ::= !binop '(' Value ',' Value ')'
tgtok::TokKind OpTok = Lex.getCode(); tgtok::TokKind OpTok = Lex.getCode();
SMLoc OpLoc = Lex.getLoc(); SMLoc OpLoc = Lex.getLoc();
Lex.Lex(); // eat the operation Lex.Lex(); // eat the operation
@ -1115,9 +1115,9 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
case tgtok::XGe: Code = BinOpInit::GE; break; case tgtok::XGe: Code = BinOpInit::GE; break;
case tgtok::XGt: Code = BinOpInit::GT; break; case tgtok::XGt: Code = BinOpInit::GT; break;
case tgtok::XListConcat: Code = BinOpInit::LISTCONCAT; break; case tgtok::XListConcat: Code = BinOpInit::LISTCONCAT; break;
case tgtok::XListSplat: Code = BinOpInit::LISTSPLAT; break; case tgtok::XListSplat: Code = BinOpInit::LISTSPLAT; break;
case tgtok::XStrConcat: Code = BinOpInit::STRCONCAT; break; case tgtok::XStrConcat: Code = BinOpInit::STRCONCAT; break;
case tgtok::XSetOp: Code = BinOpInit::SETOP; break; case tgtok::XSetDagOp: Code = BinOpInit::SETDAGOP; break;
} }
RecTy *Type = nullptr; RecTy *Type = nullptr;
@ -1126,7 +1126,7 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
default: default:
llvm_unreachable("Unhandled code!"); llvm_unreachable("Unhandled code!");
case tgtok::XConcat: case tgtok::XConcat:
case tgtok::XSetOp: case tgtok::XSetDagOp:
Type = DagRecTy::get(); Type = DagRecTy::get();
ArgType = DagRecTy::get(); ArgType = DagRecTy::get();
break; break;
@ -1259,7 +1259,7 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
// Deal with BinOps whose arguments have different types, by // Deal with BinOps whose arguments have different types, by
// rewriting ArgType in between them. // rewriting ArgType in between them.
switch (Code) { switch (Code) {
case BinOpInit::SETOP: case BinOpInit::SETDAGOP:
// After parsing the first dag argument, switch to expecting // After parsing the first dag argument, switch to expecting
// a record, with no restriction on its superclasses. // a record, with no restriction on its superclasses.
ArgType = RecordRecTy::get({}); ArgType = RecordRecTy::get({});
@ -1417,7 +1417,7 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
case tgtok::XDag: case tgtok::XDag:
case tgtok::XIf: case tgtok::XIf:
case tgtok::XSubst: { // Value ::= !ternop '(' Value ',' Value ',' Value ')' case tgtok::XSubst: { // Value ::= !ternop '(' Value ',' Value ',' Value ')'
TernOpInit::TernaryOp Code; TernOpInit::TernaryOp Code;
RecTy *Type = nullptr; RecTy *Type = nullptr;
@ -2051,7 +2051,7 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType,
case tgtok::l_paren: { // Value ::= '(' IDValue DagArgList ')' case tgtok::l_paren: { // Value ::= '(' IDValue DagArgList ')'
Lex.Lex(); // eat the '(' Lex.Lex(); // eat the '('
if (Lex.getCode() != tgtok::Id && Lex.getCode() != tgtok::XCast && if (Lex.getCode() != tgtok::Id && Lex.getCode() != tgtok::XCast &&
Lex.getCode() != tgtok::question && Lex.getCode() != tgtok::XGetOp) { Lex.getCode() != tgtok::question && Lex.getCode() != tgtok::XGetDagOp) {
TokError("expected identifier in dag init"); TokError("expected identifier in dag init");
return nullptr; return nullptr;
} }
@ -2089,7 +2089,7 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType,
case tgtok::XSize: case tgtok::XSize:
case tgtok::XEmpty: case tgtok::XEmpty:
case tgtok::XCast: case tgtok::XCast:
case tgtok::XGetOp: // Value ::= !unop '(' Value ')' case tgtok::XGetDagOp: // Value ::= !unop '(' Value ')'
case tgtok::XIsA: case tgtok::XIsA:
case tgtok::XConcat: case tgtok::XConcat:
case tgtok::XDag: case tgtok::XDag:
@ -2111,12 +2111,12 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType,
case tgtok::XListConcat: case tgtok::XListConcat:
case tgtok::XListSplat: case tgtok::XListSplat:
case tgtok::XStrConcat: case tgtok::XStrConcat:
case tgtok::XSetOp: // Value ::= !binop '(' Value ',' Value ')' case tgtok::XSetDagOp: // Value ::= !binop '(' Value ',' Value ')'
case tgtok::XIf: case tgtok::XIf:
case tgtok::XCond: case tgtok::XCond:
case tgtok::XFoldl: case tgtok::XFoldl:
case tgtok::XForEach: case tgtok::XForEach:
case tgtok::XSubst: { // Value ::= !ternop '(' Value ',' Value ',' Value ')' case tgtok::XSubst: { // Value ::= !ternop '(' Value ',' Value ',' Value ')'
return ParseOperation(CurRec, ItemType); return ParseOperation(CurRec, ItemType);
} }
} }
@ -2186,7 +2186,7 @@ Init *TGParser::ParseValue(Record *CurRec, RecTy *ItemType, IDParseMode Mode) {
break; break;
} }
case tgtok::dot: { case tgtok::dot: {
if (Lex.Lex() != tgtok::Id) { // eat the . if (Lex.Lex() != tgtok::Id) { // eat the .
TokError("expected field identifier after '.'"); TokError("expected field identifier after '.'");
return nullptr; return nullptr;
} }

View File

@ -3033,7 +3033,7 @@ multiclass MVE_VSHRN_patterns<MVE_shift_imm_partial inst,
defvar outparams = (inst (OutVTI.Vec MQPR:$QdSrc), (InVTI.Vec MQPR:$Qm), defvar outparams = (inst (OutVTI.Vec MQPR:$QdSrc), (InVTI.Vec MQPR:$Qm),
(imm:$imm)); (imm:$imm));
def : Pat<(OutVTI.Vec !setop(inparams, int_arm_mve_vshrn)), def : Pat<(OutVTI.Vec !setdagop(inparams, int_arm_mve_vshrn)),
(OutVTI.Vec outparams)>; (OutVTI.Vec outparams)>;
def : Pat<(OutVTI.Vec !con(inparams, (int_arm_mve_vshrn_predicated def : Pat<(OutVTI.Vec !con(inparams, (int_arm_mve_vshrn_predicated
(InVTI.Pred VCCR:$pred)))), (InVTI.Pred VCCR:$pred)))),
@ -3235,7 +3235,7 @@ multiclass MVE_VSxI_patterns<MVE_VSxI_imm inst, string name,
defvar unpred_int = !cast<Intrinsic>("int_arm_mve_" # name); defvar unpred_int = !cast<Intrinsic>("int_arm_mve_" # name);
defvar pred_int = !cast<Intrinsic>("int_arm_mve_" # name # "_predicated"); defvar pred_int = !cast<Intrinsic>("int_arm_mve_" # name # "_predicated");
def : Pat<(VTI.Vec !setop(inparams, unpred_int)), def : Pat<(VTI.Vec !setdagop(inparams, unpred_int)),
(VTI.Vec outparams)>; (VTI.Vec outparams)>;
def : Pat<(VTI.Vec !con(inparams, (pred_int (VTI.Pred VCCR:$pred)))), def : Pat<(VTI.Vec !con(inparams, (pred_int (VTI.Pred VCCR:$pred)))),
(VTI.Vec !con(outparams, (? ARMVCCThen, VCCR:$pred)))>; (VTI.Vec !con(outparams, (? ARMVCCThen, VCCR:$pred)))>;

View File

@ -3,6 +3,9 @@
// RUN: not llvm-tblgen -DERROR2 %s 2>&1 | FileCheck --check-prefix=ERROR2 %s // RUN: not llvm-tblgen -DERROR2 %s 2>&1 | FileCheck --check-prefix=ERROR2 %s
// RUN: not llvm-tblgen -DERROR3 %s 2>&1 | FileCheck --check-prefix=ERROR3 %s // RUN: not llvm-tblgen -DERROR3 %s 2>&1 | FileCheck --check-prefix=ERROR3 %s
// !setop and !getop are deprecated in favor of !setdagop and !getdagop.
// Two tests retain the old names just to be sure they are still supported.
class Base; class Base;
class OtherBase; class OtherBase;
@ -18,28 +21,28 @@ def test {
dag replaceWithBar = !setop(orig, bar); dag replaceWithBar = !setop(orig, bar);
// CHECK: dag replaceWithBaz = (qux 1, 2:$a, ?:$b); // CHECK: dag replaceWithBaz = (qux 1, 2:$a, ?:$b);
dag replaceWithBaz = !setop(orig, qux); dag replaceWithBaz = !setdagop(orig, qux);
// CHECK: Base getopWithCast = foo; // CHECK: Base getopWithCast = foo;
Base getopWithCast = !getop<Base>(orig); Base getopWithCast = !getop<Base>(orig);
// CHECK: dag getopToSetop = (foo "hello", ?:$world); // CHECK: dag getopToSetop = (foo "hello", ?:$world);
dag getopToSetop = !setop(another, !getop(orig)); dag getopToSetop = !setdagop(another, !getdagop(orig));
// CHECK: dag getopToBangDag = (foo 1:$a, 2:$b, 3:$c); // CHECK: dag getopToBangDag = (foo 1:$a, 2:$b, 3:$c);
dag getopToBangDag = !dag(!getop(orig), [1, 2, 3], ["a", "b", "c"]); dag getopToBangDag = !dag(!getdagop(orig), [1, 2, 3], ["a", "b", "c"]);
// CHECK: dag getopToDagInit = (foo "it worked"); // CHECK: dag getopToDagInit = (foo "it worked");
dag getopToDagInit = (!getop(orig) "it worked"); dag getopToDagInit = (!getdagop(orig) "it worked");
#ifdef ERROR1 #ifdef ERROR1
// !getop(...) has a static type of 'any record at all, with no // !getdagop(...) has a static type of 'any record at all, with no
// required superclasses'. That's too general to use in an // required superclasses'. That's too general to use in an
// assignment whose LHS demands an instance of Base, so we expect a // assignment whose LHS demands an instance of Base, so we expect a
// static (parse-time) type-checking error. // static (parse-time) type-checking error.
// ERROR1: error: Field 'noCast' of type 'Base' is incompatible with value '!getop(orig)' of type '{}' // ERROR1: error: Field 'noCast' of type 'Base' is incompatible with value '!getdagop(orig)' of type '{}'
Base noCast = !getop(orig); Base noCast = !getdagop(orig);
#endif #endif
#ifdef ERROR2 #ifdef ERROR2
@ -47,15 +50,15 @@ def test {
// evaluation time that the operator of 'another' is a record that // evaluation time that the operator of 'another' is a record that
// isn't an instance of the specified base class. // isn't an instance of the specified base class.
// ERROR2: error: Expected type 'Base', got 'OtherBase' in: !getop((qux "hello", ?:$world)) // ERROR2: error: Expected type 'Base', got 'OtherBase' in: !getdagop((qux "hello", ?:$world))
Base badCast = !getop<Base>(another); Base badCast = !getdagop<Base>(another);
#endif #endif
#ifdef ERROR3 #ifdef ERROR3
// Obviously, you shouldn't be able to give any type to !getop that // Obviously, you shouldn't be able to give any type to !getdagop that
// isn't a class type. // isn't a class type.
// ERROR3: error: type for !getop must be a record type // ERROR3: error: type for !getdagop must be a record type
int ridiculousCast = !getop<int>(orig); int ridiculousCast = !getdagop<int>(orig);
#endif #endif
} }