1 module d.ir.type; 2 3 import d.ir.error; 4 import d.ir.symbol; 5 6 public import d.common.builtintype; 7 public import d.common.qualifier; 8 9 import source.context; 10 import d.common.type; 11 12 // Conflict with Interface in object.di 13 alias Interface = d.ir.symbol.Interface; 14 15 enum TypeKind : ubyte { 16 Builtin, 17 18 // Symbols 19 Alias, 20 Struct, 21 Class, 22 Interface, 23 Union, 24 Enum, 25 26 // Context 27 Context, 28 29 // Type constructors 30 Pointer, 31 Slice, 32 Array, 33 34 // Sequence 35 Sequence, 36 37 // Complex types 38 Function, 39 40 // Template Pattern matching for IFTI. 41 Pattern, 42 43 // Error 44 Error, 45 } 46 47 struct Type { 48 private: 49 mixin TypeMixin!(TypeKind, Payload); 50 51 this(Desc d, inout Payload p = Payload.init) inout { 52 desc = d; 53 payload = p; 54 } 55 56 import util.fastcast; 57 this(Desc d, inout Symbol s) inout { 58 this(d, fastCast!(inout Payload)(s)); 59 } 60 61 this(Desc d, inout Type* t) inout { 62 this(d, fastCast!(inout Payload)(t)); 63 } 64 65 this(Desc d, inout Pattern.Payload p) inout { 66 this(d, fastCast!(inout Payload)(p)); 67 } 68 69 this(Desc d, inout CompileError e) inout { 70 this(d, fastCast!(inout Payload)(e)); 71 } 72 73 Type getConstructedType(this T)(TypeKind k, TypeQualifier q) { 74 return qualify(q).getConstructedMixin(k, q); 75 } 76 77 auto acceptImpl(T)(T t) { 78 final switch(kind) with(TypeKind) { 79 case Builtin: 80 return t.visit(builtin); 81 82 case Struct: 83 return t.visit(dstruct); 84 85 case Class: 86 return t.visit(dclass); 87 88 case Enum: 89 return t.visit(denum); 90 91 case Alias: 92 // XXX: consider how to propagate the qualifier properly. 93 return t.visit(dalias); 94 95 case Interface: 96 return t.visit(dinterface); 97 98 case Union: 99 return t.visit(dunion); 100 101 case Context: 102 return t.visit(context); 103 104 case Pointer: 105 return t.visitPointerOf(element); 106 107 case Slice: 108 return t.visitSliceOf(element); 109 110 case Array: 111 return t.visitArrayOf(size, element); 112 113 case Sequence: 114 return t.visit(sequence); 115 116 case Function: 117 return t.visit(asFunctionType()); 118 119 case Pattern: 120 return t.visit(pattern); 121 122 case Error: 123 return t.visit(error); 124 } 125 } 126 127 public: 128 auto accept(T)(ref T t) if(is(T == struct)) { 129 return acceptImpl(&t); 130 } 131 132 auto accept(T)(T t) if(is(T == class)) { 133 return acceptImpl(t); 134 } 135 136 Type qualify(TypeQualifier q) { 137 auto nq = q.add(qualifier); 138 if (nq == qualifier) { 139 return Type(desc, payload); 140 } 141 142 switch(kind) with(TypeKind) { 143 case Builtin, Struct, Class, Enum, Alias : 144 case Interface, Union, Context, Function : 145 auto d = desc; 146 d.qualifier = nq; 147 return Type(d, payload); 148 149 case Pointer : 150 return element.qualify(nq).getPointer(nq); 151 152 case Slice : 153 return element.qualify(nq).getSlice(nq); 154 155 case Array : 156 return element.qualify(nq).getArray(size, nq); 157 158 default : 159 assert(0, "Not implemented"); 160 } 161 } 162 163 Type unqual() { 164 auto d = desc; 165 d.qualifier = TypeQualifier.Mutable; 166 return Type(d, payload); 167 } 168 169 @property 170 BuiltinType builtin() inout in { 171 assert(kind == TypeKind.Builtin, "Not a builtin type."); 172 } do { 173 return cast(BuiltinType) desc.data; 174 } 175 176 bool isAggregate() const { 177 return (kind >= TypeKind.Struct) && (kind <= TypeKind.Union); 178 } 179 180 @property 181 auto aggregate() inout in { 182 assert(isAggregate, "Not an aggregate type."); 183 } do { 184 return payload.agg; 185 } 186 187 @property 188 auto dstruct() inout in { 189 assert(kind == TypeKind.Struct); 190 } do { 191 return payload.dstruct; 192 } 193 194 @property 195 auto dclass() inout in { 196 assert(kind == TypeKind.Class); 197 } do { 198 return payload.dclass; 199 } 200 201 @property 202 auto denum() inout in { 203 assert(kind == TypeKind.Enum); 204 } do { 205 return payload.denum; 206 } 207 208 @property 209 auto dalias() inout in { 210 assert(kind == TypeKind.Alias); 211 } do { 212 return payload.dalias; 213 } 214 215 auto getCanonical() { 216 auto t = this; 217 auto q = qualifier; 218 while(t.kind == TypeKind.Alias) { 219 // FIXME: Make sure alias is signed. 220 t = t.dalias.type; 221 q = q.add(t.qualifier); 222 } 223 224 return t.qualify(q); 225 } 226 227 auto getCanonicalAndPeelEnum() { 228 auto t = this.getCanonical(); 229 auto q = qualifier; 230 while(t.kind == TypeKind.Enum) { 231 // FIXME: Make sure enum is signed. 232 t = t.denum.type.getCanonical(); 233 q = q.add(t.qualifier); 234 } 235 236 return t.qualify(q); 237 } 238 239 @property 240 auto dinterface() inout in { 241 assert(kind == TypeKind.Interface); 242 } do { 243 return payload.dinterface; 244 } 245 246 @property 247 auto dunion() inout in { 248 assert(kind == TypeKind.Union); 249 } do { 250 return payload.dunion; 251 } 252 253 @property 254 auto context() inout in { 255 assert(kind == TypeKind.Context); 256 } do { 257 return payload.context; 258 } 259 260 @property 261 auto pattern() inout in { 262 assert(kind == TypeKind.Pattern); 263 } do { 264 return inout(Pattern)(desc, payload.patternPayload); 265 } 266 267 @property 268 auto error() inout in { 269 assert(kind == TypeKind.Error); 270 } do { 271 return payload.error; 272 } 273 274 Type getPointer(TypeQualifier q = TypeQualifier.Mutable) { 275 return getConstructedType(TypeKind.Pointer, q); 276 } 277 278 Type getSlice(TypeQualifier q = TypeQualifier.Mutable) { 279 return getConstructedType(TypeKind.Slice, q); 280 } 281 282 Type getArray(uint size, TypeQualifier q = TypeQualifier.Mutable) { 283 auto t = qualify(q); 284 285 // XXX: Consider caching in context. 286 auto n = new Type(t.desc, t.payload); 287 return Type(Desc(TypeKind.Array, q, size), n); 288 } 289 290 bool hasElement() const { 291 return (kind >= TypeKind.Pointer) && (kind <= TypeKind.Array); 292 } 293 294 @property 295 auto element() inout in { 296 assert(hasElement, "element called on a type with no element."); 297 } do { 298 if (kind == TypeKind.Array) { 299 return *payload.next; 300 } 301 302 return getElementMixin(); 303 } 304 305 @property 306 uint size() const in { 307 assert(kind == TypeKind.Array, "Only array have size."); 308 } do { 309 assert(desc.data <= uint.max); 310 return cast(uint) desc.data; 311 } 312 313 @property 314 auto sequence() inout in { 315 assert(kind == TypeKind.Sequence, "Not a sequence type."); 316 } do { 317 return payload.next[0 .. desc.data]; 318 } 319 320 bool hasPointerABI() const { 321 switch (kind) with(TypeKind) { 322 case Class, Pointer : 323 return true; 324 325 case Alias : 326 return dalias.type.hasPointerABI(); 327 328 case Function : 329 return asFunctionType().contexts.length == 0; 330 331 default : 332 return false; 333 } 334 } 335 336 bool hasIndirection() { 337 auto t = getCanonicalAndPeelEnum(); 338 final switch(t.kind) with(TypeKind) { 339 case Builtin: 340 // Is this, really ? 341 return t.builtin == BuiltinType.Null; 342 343 case Alias, Enum, Pattern, Error: 344 assert(0); 345 346 case Pointer, Slice, Class, Interface, Context: 347 return true; 348 349 case Array: 350 return element.hasIndirection; 351 352 case Struct: 353 return t.dstruct.hasIndirection; 354 355 case Union: 356 return t.dunion.hasIndirection; 357 358 case Function: 359 import std.algorithm; 360 return asFunctionType() 361 .contexts 362 .any!(t => t.isRef || t.getType().hasIndirection); 363 364 case Sequence: 365 import std.algorithm; 366 return sequence.any!(t => t.hasIndirection); 367 } 368 } 369 370 string toString(const Context c, TypeQualifier q = TypeQualifier.Mutable) const { 371 auto s = toUnqualString(c); 372 if (q == qualifier) { 373 return s; 374 } 375 376 final switch(qualifier) with(TypeQualifier) { 377 case Mutable: 378 return s; 379 380 case Inout: 381 return "inout(" ~ s ~ ")"; 382 383 case Const: 384 return "const(" ~ s ~ ")"; 385 386 case Shared: 387 return "shared(" ~ s ~ ")"; 388 389 case ConstShared: 390 assert(0, "const shared isn't supported"); 391 392 case Immutable: 393 return "immutable(" ~ s ~ ")"; 394 } 395 } 396 397 string toUnqualString(const Context c) const { 398 final switch(kind) with(TypeKind) { 399 case Builtin: 400 import d.common.builtintype : toString; 401 return toString(builtin); 402 403 case Struct: 404 return dstruct.name.toString(c); 405 406 case Class: 407 return dclass.name.toString(c); 408 409 case Enum: 410 return denum.name.toString(c); 411 412 case Alias: 413 return dalias.name.toString(c); 414 415 case Interface: 416 return dinterface.name.toString(c); 417 418 case Union: 419 return dunion.name.toString(c); 420 421 case Context: 422 return "__ctx"; 423 424 case Pointer: 425 return element.toString(c, qualifier) ~ "*"; 426 427 case Slice: 428 return element.toString(c, qualifier) ~ "[]"; 429 430 case Array: 431 import std.conv; 432 return element.toString(c, qualifier) 433 ~ "[" ~ to!string(size) ~ "]"; 434 435 case Sequence: 436 import std.algorithm, std.range; 437 // XXX: need to use this because of identifier hijacking in the import. 438 return "(" ~ this.sequence.map!(e => e.toString(c, qualifier)).join(", ") ~ ")"; 439 440 case Function: 441 auto f = asFunctionType(); 442 443 auto linkage = ""; 444 if (f.linkage != Linkage.D) { 445 import std.conv; 446 linkage = "extern(" ~ f.linkage.to!string() ~ ") "; 447 } 448 449 auto ret = f.returnType.toString(c); 450 auto base = f.contexts.length ? " delegate(" : " function("; 451 import std.algorithm, std.range; 452 auto args = f.parameters.map!(p => p.toString(c)).join(", "); 453 return linkage ~ ret ~ base ~ args ~ (f.isVariadic ? ", ...)" : ")"); 454 455 case Pattern: 456 return pattern.toString(c); 457 458 case Error: 459 return "__error__(" ~ error.toString(c) ~ ")"; 460 } 461 } 462 463 static: 464 Type get(BuiltinType bt, TypeQualifier q = TypeQualifier.Mutable) { 465 Payload p; // Needed because of lolbug in inout 466 return Type(Desc(TypeKind.Builtin, q, bt), p); 467 } 468 469 Type get(Struct s, TypeQualifier q = TypeQualifier.Mutable) { 470 return Type(Desc(TypeKind.Struct, q), s); 471 } 472 473 Type get(Class c, TypeQualifier q = TypeQualifier.Mutable) { 474 return Type(Desc(TypeKind.Class, q), c); 475 } 476 477 Type get(Enum e, TypeQualifier q = TypeQualifier.Mutable) { 478 return Type(Desc(TypeKind.Enum, q), e); 479 } 480 481 Type get(TypeAlias a, TypeQualifier q = TypeQualifier.Mutable) { 482 return Type(Desc(TypeKind.Alias, q), a); 483 } 484 485 Type get(Interface i, TypeQualifier q = TypeQualifier.Mutable) { 486 return Type(Desc(TypeKind.Interface, q), i); 487 } 488 489 Type get(Union u, TypeQualifier q = TypeQualifier.Mutable) { 490 return Type(Desc(TypeKind.Union, q), u); 491 } 492 493 Type get(Type[] elements, TypeQualifier q = TypeQualifier.Mutable) { 494 return Type(Desc(TypeKind.Sequence, q, elements.length), elements.ptr); 495 } 496 497 Type get(TypeTemplateParameter p, TypeQualifier q = TypeQualifier.Mutable) { 498 return Pattern(p).getType(q); 499 } 500 501 Type getContextType(Function f, TypeQualifier q = TypeQualifier.Mutable) { 502 return Type(Desc(TypeKind.Context, q), f); 503 } 504 505 Type get(CompileError e, TypeQualifier q = TypeQualifier.Mutable) { 506 return Type(Desc(TypeKind.Error, q), e); 507 } 508 } 509 510 unittest { 511 auto i = Type.get(BuiltinType.Int); 512 auto pi = i.getPointer(); 513 assert(i == pi.element); 514 515 auto ci = i.qualify(TypeQualifier.Const); 516 auto cpi = pi.qualify(TypeQualifier.Const); 517 assert(ci == cpi.element); 518 assert(i != cpi.element); 519 } 520 521 unittest { 522 auto i = Type.get(BuiltinType.Int); 523 auto t = i; 524 foreach(_; 0 .. 64) { 525 t = t.getPointer().getSlice(); 526 } 527 528 foreach(_; 0 .. 64) { 529 assert(t.kind == TypeKind.Slice); 530 t = t.element; 531 assert(t.kind == TypeKind.Pointer); 532 t = t.element; 533 } 534 535 assert(t == i); 536 } 537 538 unittest { 539 auto i = Type.get(BuiltinType.Int); 540 auto ai = i.getArray(42); 541 assert(i == ai.element); 542 assert(ai.size == 42); 543 } 544 545 unittest { 546 auto i = Type.get(BuiltinType.Int); 547 auto ci = Type.get(BuiltinType.Int, TypeQualifier.Const); 548 auto cpi = i.getPointer(TypeQualifier.Const); 549 assert(ci == cpi.element); 550 551 auto csi = i.getSlice(TypeQualifier.Const); 552 assert(ci == csi.element); 553 554 auto cai = i.getArray(42, TypeQualifier.Const); 555 assert(ci == cai.element); 556 } 557 558 unittest { 559 import source.location, source.name, d.ir.symbol; 560 auto m = new Module(Location.init, BuiltinName!"", null); 561 auto c = new Class(Location.init, m, BuiltinName!"", []); 562 auto tc = Type.get(c); 563 assert(tc.isAggregate); 564 assert(tc.aggregate is c); 565 566 auto cc = Type.get(c, TypeQualifier.Const); 567 auto csc = tc.getSlice(TypeQualifier.Const); 568 assert(cc == csc.element); 569 } 570 571 unittest { 572 import source.location, source.name, d.ir.symbol; 573 auto i = Type.get(BuiltinType.Int); 574 auto a1 = new TypeAlias(Location.init, BuiltinName!"", i); 575 auto a1t = Type.get(a1); 576 assert(a1t.getCanonical() == i); 577 578 auto a2 = new TypeAlias(Location.init, BuiltinName!"", a1t); 579 auto a2t = Type.get(a2, TypeQualifier.Immutable); 580 assert(a2t.getCanonical() == i.qualify(TypeQualifier.Immutable)); 581 582 auto a3 = new TypeAlias(Location.init, BuiltinName!"", a2t); 583 auto a3t = Type.get(a3, TypeQualifier.Const); 584 assert(a3t.getCanonical() == i.qualify(TypeQualifier.Immutable)); 585 } 586 587 unittest { 588 import source.location, source.name, d.ir.symbol; 589 auto f = Type.get(BuiltinType.Float, TypeQualifier.Const); 590 auto a = new TypeAlias(Location.init, BuiltinName!"", f); 591 592 auto m = new Module(Location.init, BuiltinName!"", null); 593 auto e1 = new Enum(Location.init, m, BuiltinName!"", Type.get(a), []); 594 auto e1t = Type.get(e1); 595 assert(e1t.getCanonicalAndPeelEnum() == f); 596 597 auto e2 = new Enum(Location.init, m, BuiltinName!"", e1t, []); 598 auto e2t = Type.get(e2, TypeQualifier.Immutable); 599 assert(e2t.getCanonicalAndPeelEnum() == f.qualify(TypeQualifier.Immutable)); 600 601 auto e3 = new Enum(Location.init, m, BuiltinName!"", e2t, []); 602 auto e3t = Type.get(e3, TypeQualifier.Const); 603 assert(e3t.getCanonicalAndPeelEnum() == f.qualify(TypeQualifier.Immutable)); 604 } 605 606 alias ParamType = Type.ParamType; 607 608 string toString(const ParamType t, const Context c) { 609 string s; 610 final switch (t.paramKind) with(ParamKind) { 611 case Regular: 612 s = ""; 613 break; 614 615 case Final: 616 s = "final "; 617 break; 618 619 case Ref: 620 s = "ref "; 621 break; 622 } 623 624 return s ~ t.getType().toString(c); 625 } 626 627 inout(ParamType) getParamType(inout ParamType t, ParamKind kind) { 628 return t.getType().getParamType(kind); 629 } 630 631 @property isRef(const ParamType t) { 632 return t.paramKind == ParamKind.Ref; 633 } 634 635 @property isFinal(const ParamType t) { 636 return t.paramKind == ParamKind.Final; 637 } 638 639 unittest { 640 auto pi = Type.get(BuiltinType.Int).getPointer(TypeQualifier.Const); 641 auto p = pi.getParamType(ParamKind.Ref); 642 643 assert(p.paramKind == ParamKind.Ref); 644 assert(p.qualifier == TypeQualifier.Const); 645 646 auto pt = p.getType(); 647 assert(pt == pi); 648 } 649 650 alias FunctionType = Type.FunctionType; 651 652 unittest { 653 auto r = Type.get(BuiltinType.Void).getPointer() 654 .getParamType(ParamKind.Regular); 655 auto c = Type.get(BuiltinType.Null).getSlice() 656 .getParamType(ParamKind.Final); 657 auto p = Type.get(BuiltinType.Float).getSlice(TypeQualifier.Immutable) 658 .getParamType(ParamKind.Ref); 659 auto f = FunctionType(Linkage.Java, r, [c, p], true); 660 661 assert(f.linkage == Linkage.Java); 662 assert(f.isVariadic == true); 663 assert(f.isPure == false); 664 assert(f.returnType == r); 665 assert(f.parameters.length == 2); 666 assert(f.parameters[0] == c); 667 assert(f.parameters[1] == p); 668 669 auto ft = f.getType(); 670 assert(ft.asFunctionType() == f); 671 672 auto d = f.getDelegate(); 673 assert(d.linkage == Linkage.Java); 674 assert(d.isVariadic == true); 675 assert(d.isPure == false); 676 assert(d.returnType == r); 677 assert(d.contexts.length == 1); 678 assert(d.contexts[0] == c); 679 assert(d.parameters.length == 1); 680 assert(d.parameters[0] == p); 681 682 auto dt = d.getType(); 683 assert(dt.asFunctionType() == d); 684 assert(dt.asFunctionType() != f); 685 686 auto d2 = d.getDelegate(2); 687 assert(d2.contexts.length == 2); 688 assert(d2.parameters.length == 0); 689 assert(d2.getFunction() == f); 690 } 691 692 // Facility for IFTI pattern matching. 693 enum PatternKind : ubyte { 694 Parameter, 695 Instance, 696 TypeBracketValue, 697 TypeBracketType, 698 } 699 700 struct Pattern { 701 private: 702 alias Desc = Type.Desc; 703 704 import util.bitfields; 705 enum KindSize = EnumSize!PatternKind; 706 enum Pad = ulong.sizeof * 8 - Type.Desc.DataSize; 707 enum CountSize = ulong.sizeof * 8 - KindSize - Pad; 708 709 import std.bitmanip; 710 mixin(bitfields!( 711 PatternKind, "kind", KindSize, 712 ulong, "argCount", CountSize, 713 uint, "", Pad, // Pad for TypeKind and qualifier 714 )); 715 716 union Payload { 717 TypeTemplateParameter param; 718 TypeValuePair* typeValuePair; 719 TemplateArgument* args; 720 } 721 722 Payload payload; 723 724 static assert(Payload.sizeof == ulong.sizeof, "Payload must be the same size as ulong."); 725 726 this(Desc desc, inout Payload payload) inout { 727 // /!\ Black magic ahead. 728 auto raw_desc = cast(ulong*) &desc; 729 730 // Remove the TypeKind and qualifier 731 *raw_desc = (*raw_desc >> Pad); 732 733 // This should point to an area of memory that have 734 // the correct layout for the bitfield. 735 auto p = cast(Pattern*) raw_desc; 736 737 // unqual trick required for bitfield 738 auto unqual_this = cast(Pattern*) &this; 739 unqual_this.kind = p.kind; 740 unqual_this.argCount = p.argCount; 741 742 this.payload = payload; 743 } 744 745 this(PatternKind k, ulong c, Payload p) { 746 kind = k; 747 argCount = c; 748 payload = p; 749 } 750 751 struct TypeValuePair { 752 Type type; 753 ValueTemplateParameter value; 754 } 755 756 auto getTypeValuePair() inout in { 757 assert(kind == PatternKind.TypeBracketValue); 758 } do { 759 return payload.typeValuePair; 760 } 761 762 struct Instantiation { 763 Symbol instantiated; 764 TemplateArgument[] args; 765 } 766 767 auto getInstatiation() inout in { 768 assert(kind == PatternKind.Instance); 769 } do { 770 auto c = argCount; 771 return inout(Instantiation)( 772 payload.args[c].get!(TemplateArgument.Tag.Symbol), 773 payload.args[0 .. c], 774 ); 775 } 776 777 public: 778 import util.fastcast; 779 this(TypeTemplateParameter p) { 780 this(PatternKind.Parameter, 0, fastCast!Payload(p)); 781 } 782 783 this(Type t, ValueTemplateParameter v) { 784 auto p = new TypeValuePair(t, v); 785 this(PatternKind.TypeBracketValue, 0, fastCast!Payload(p)); 786 } 787 788 this(Symbol instantiated, TemplateArgument[] args) { 789 args ~= TemplateArgument(instantiated); 790 this( 791 PatternKind.Instance, 792 args.length - 1, 793 fastCast!Payload(args.ptr), 794 ); 795 } 796 797 @property parameter() inout in { 798 assert(kind == PatternKind.Parameter); 799 } do { 800 return payload.param; 801 } 802 803 Type getType(TypeQualifier q = TypeQualifier.Mutable) { 804 ulong d = *cast(ulong*) &this; 805 return Type(Desc(TypeKind.Pattern, q, d), payload); 806 } 807 808 auto accept(T)(ref T t) if(is(T == struct)) { 809 return acceptImpl(&t); 810 } 811 812 auto accept(T)(T t) if(is(T == class)) { 813 return acceptImpl(t); 814 } 815 816 string toString(const Context c) const { 817 final switch (kind) with(PatternKind) { 818 case Parameter: 819 return parameter.name.toString(c); 820 821 case Instance: 822 assert(0, "Not implemented"); 823 824 case TypeBracketValue: 825 auto p = getTypeValuePair(); 826 return p.type.toString(c) ~ '[' ~ p.value.name.toString(c) ~ ']'; 827 828 case TypeBracketType: 829 assert(0, "Not implemented"); 830 } 831 } 832 833 private: 834 auto acceptImpl(T)(T t) { 835 final switch(kind) with(PatternKind) { 836 case Parameter: 837 return t.visit(parameter); 838 839 case Instance: 840 auto i = getInstatiation(); 841 return t.visit(i.instantiated, i.args); 842 843 case TypeBracketValue: 844 auto p = getTypeValuePair(); 845 return t.visit(p.type, p.value); 846 847 case TypeBracketType: 848 assert(0, "Not implemented"); 849 } 850 } 851 } 852 853 private: 854 855 // XXX: we put it as a UFCS property to avoid forward reference. 856 @property 857 inout(ParamType)* params(inout Payload p) { 858 import util.fastcast; 859 return cast(inout ParamType*) p.next; 860 } 861 862 union Payload { 863 Type* next; 864 865 // Symbols 866 TypeAlias dalias; 867 Class dclass; 868 Interface dinterface; 869 Struct dstruct; 870 Union dunion; 871 Enum denum; 872 873 // Context 874 Function context; 875 876 // For function and delegates. 877 // ParamType* params; 878 879 // For template instanciation. 880 Pattern.Payload patternPayload; 881 882 // For speculative compilation. 883 CompileError error; 884 885 // For simple construction 886 Symbol sym; 887 Aggregate agg; 888 }