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.any!(t => t.isRef || t.getType().hasIndirection); 362 363 case Sequence: 364 import std.algorithm; 365 return sequence.any!(t => t.hasIndirection); 366 } 367 } 368 369 string toString(const Context c, 370 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) ~ "[" ~ to!string(size) 433 ~ "]"; 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)) 439 .join(", ") ~ ")"; 440 441 case Function: 442 auto f = asFunctionType(); 443 444 auto linkage = ""; 445 if (f.linkage != Linkage.D) { 446 import std.conv; 447 linkage = "extern(" ~ f.linkage.to!string() ~ ") "; 448 } 449 450 auto ret = f.returnType.toString(c); 451 auto base = f.contexts.length ? " delegate(" : " function("; 452 import std.algorithm, std.range; 453 auto args = f.parameters.map!(p => p.toString(c)).join(", "); 454 return linkage ~ ret ~ base ~ args 455 ~ (f.isVariadic ? ", ...)" : ")"); 456 457 case Pattern: 458 return pattern.toString(c); 459 460 case Error: 461 return "__error__(" ~ error.toString(c) ~ ")"; 462 } 463 } 464 465 static: 466 Type get(BuiltinType bt, TypeQualifier q = TypeQualifier.Mutable) { 467 Payload p; // Needed because of lolbug in inout 468 return Type(Desc(TypeKind.Builtin, q, bt), p); 469 } 470 471 Type get(Struct s, TypeQualifier q = TypeQualifier.Mutable) { 472 return Type(Desc(TypeKind.Struct, q), s); 473 } 474 475 Type get(Class c, TypeQualifier q = TypeQualifier.Mutable) { 476 return Type(Desc(TypeKind.Class, q), c); 477 } 478 479 Type get(Enum e, TypeQualifier q = TypeQualifier.Mutable) { 480 return Type(Desc(TypeKind.Enum, q), e); 481 } 482 483 Type get(TypeAlias a, TypeQualifier q = TypeQualifier.Mutable) { 484 return Type(Desc(TypeKind.Alias, q), a); 485 } 486 487 Type get(Interface i, TypeQualifier q = TypeQualifier.Mutable) { 488 return Type(Desc(TypeKind.Interface, q), i); 489 } 490 491 Type get(Union u, TypeQualifier q = TypeQualifier.Mutable) { 492 return Type(Desc(TypeKind.Union, q), u); 493 } 494 495 Type get(Type[] elements, TypeQualifier q = TypeQualifier.Mutable) { 496 return Type(Desc(TypeKind.Sequence, q, elements.length), elements.ptr); 497 } 498 499 Type get(TypeTemplateParameter p, TypeQualifier q = TypeQualifier.Mutable) { 500 return Pattern(p).getType(q); 501 } 502 503 Type getContextType(Function f, TypeQualifier q = TypeQualifier.Mutable) { 504 return Type(Desc(TypeKind.Context, q), f); 505 } 506 507 Type get(CompileError e, TypeQualifier q = TypeQualifier.Mutable) { 508 return Type(Desc(TypeKind.Error, q), e); 509 } 510 } 511 512 unittest { 513 auto i = Type.get(BuiltinType.Int); 514 auto pi = i.getPointer(); 515 assert(i == pi.element); 516 517 auto ci = i.qualify(TypeQualifier.Const); 518 auto cpi = pi.qualify(TypeQualifier.Const); 519 assert(ci == cpi.element); 520 assert(i != cpi.element); 521 } 522 523 unittest { 524 auto i = Type.get(BuiltinType.Int); 525 auto t = i; 526 foreach (_; 0 .. 64) { 527 t = t.getPointer().getSlice(); 528 } 529 530 foreach (_; 0 .. 64) { 531 assert(t.kind == TypeKind.Slice); 532 t = t.element; 533 assert(t.kind == TypeKind.Pointer); 534 t = t.element; 535 } 536 537 assert(t == i); 538 } 539 540 unittest { 541 auto i = Type.get(BuiltinType.Int); 542 auto ai = i.getArray(42); 543 assert(i == ai.element); 544 assert(ai.size == 42); 545 } 546 547 unittest { 548 auto i = Type.get(BuiltinType.Int); 549 auto ci = Type.get(BuiltinType.Int, TypeQualifier.Const); 550 auto cpi = i.getPointer(TypeQualifier.Const); 551 assert(ci == cpi.element); 552 553 auto csi = i.getSlice(TypeQualifier.Const); 554 assert(ci == csi.element); 555 556 auto cai = i.getArray(42, TypeQualifier.Const); 557 assert(ci == cai.element); 558 } 559 560 unittest { 561 import source.location, source.name, d.ir.symbol; 562 auto m = new Module(Location.init, BuiltinName!"", null); 563 auto c = new Class(Location.init, m, BuiltinName!"", []); 564 auto tc = Type.get(c); 565 assert(tc.isAggregate); 566 assert(tc.aggregate is c); 567 568 auto cc = Type.get(c, TypeQualifier.Const); 569 auto csc = tc.getSlice(TypeQualifier.Const); 570 assert(cc == csc.element); 571 } 572 573 unittest { 574 import source.location, source.name, d.ir.symbol; 575 auto i = Type.get(BuiltinType.Int); 576 auto a1 = new TypeAlias(Location.init, BuiltinName!"", i); 577 auto a1t = Type.get(a1); 578 assert(a1t.getCanonical() == i); 579 580 auto a2 = new TypeAlias(Location.init, BuiltinName!"", a1t); 581 auto a2t = Type.get(a2, TypeQualifier.Immutable); 582 assert(a2t.getCanonical() == i.qualify(TypeQualifier.Immutable)); 583 584 auto a3 = new TypeAlias(Location.init, BuiltinName!"", a2t); 585 auto a3t = Type.get(a3, TypeQualifier.Const); 586 assert(a3t.getCanonical() == i.qualify(TypeQualifier.Immutable)); 587 } 588 589 unittest { 590 import source.location, source.name, d.ir.symbol; 591 auto f = Type.get(BuiltinType.Float, TypeQualifier.Const); 592 auto a = new TypeAlias(Location.init, BuiltinName!"", f); 593 594 auto m = new Module(Location.init, BuiltinName!"", null); 595 auto e1 = new Enum(Location.init, m, BuiltinName!"", Type.get(a), []); 596 auto e1t = Type.get(e1); 597 assert(e1t.getCanonicalAndPeelEnum() == f); 598 599 auto e2 = new Enum(Location.init, m, BuiltinName!"", e1t, []); 600 auto e2t = Type.get(e2, TypeQualifier.Immutable); 601 assert(e2t.getCanonicalAndPeelEnum() == f.qualify(TypeQualifier.Immutable)); 602 603 auto e3 = new Enum(Location.init, m, BuiltinName!"", e2t, []); 604 auto e3t = Type.get(e3, TypeQualifier.Const); 605 assert(e3t.getCanonicalAndPeelEnum() == f.qualify(TypeQualifier.Immutable)); 606 } 607 608 alias ParamType = Type.ParamType; 609 610 string toString(const ParamType t, const Context c) { 611 string s; 612 final switch (t.paramKind) with (ParamKind) { 613 case Regular: 614 s = ""; 615 break; 616 617 case Final: 618 s = "final "; 619 break; 620 621 case Ref: 622 s = "ref "; 623 break; 624 } 625 626 return s ~ t.getType().toString(c); 627 } 628 629 inout(ParamType) getParamType(inout ParamType t, ParamKind kind) { 630 return t.getType().getParamType(kind); 631 } 632 633 @property 634 bool isRef(const ParamType t) { 635 return t.paramKind == ParamKind.Ref; 636 } 637 638 @property 639 bool isFinal(const ParamType t) { 640 return t.paramKind == ParamKind.Final; 641 } 642 643 unittest { 644 auto pi = Type.get(BuiltinType.Int).getPointer(TypeQualifier.Const); 645 auto p = pi.getParamType(ParamKind.Ref); 646 647 assert(p.paramKind == ParamKind.Ref); 648 assert(p.qualifier == TypeQualifier.Const); 649 650 auto pt = p.getType(); 651 assert(pt == pi); 652 } 653 654 alias FunctionType = Type.FunctionType; 655 656 unittest { 657 auto r = 658 Type.get(BuiltinType.Void).getPointer().getParamType(ParamKind.Regular); 659 auto c = 660 Type.get(BuiltinType.Null).getSlice().getParamType(ParamKind.Final); 661 auto p = Type.get(BuiltinType.Float).getSlice(TypeQualifier.Immutable) 662 .getParamType(ParamKind.Ref); 663 auto f = FunctionType(Linkage.Java, r, [c, p], true); 664 665 assert(f.linkage == Linkage.Java); 666 assert(f.isVariadic == true); 667 assert(f.isPure == false); 668 assert(f.returnType == r); 669 assert(f.parameters.length == 2); 670 assert(f.parameters[0] == c); 671 assert(f.parameters[1] == p); 672 673 auto ft = f.getType(); 674 assert(ft.asFunctionType() == f); 675 676 auto d = f.getDelegate(); 677 assert(d.linkage == Linkage.Java); 678 assert(d.isVariadic == true); 679 assert(d.isPure == false); 680 assert(d.returnType == r); 681 assert(d.contexts.length == 1); 682 assert(d.contexts[0] == c); 683 assert(d.parameters.length == 1); 684 assert(d.parameters[0] == p); 685 686 auto dt = d.getType(); 687 assert(dt.asFunctionType() == d); 688 assert(dt.asFunctionType() != f); 689 690 auto d2 = d.getDelegate(2); 691 assert(d2.contexts.length == 2); 692 assert(d2.parameters.length == 0); 693 assert(d2.getFunction() == f); 694 } 695 696 // Facility for IFTI pattern matching. 697 enum PatternKind : ubyte { 698 Parameter, 699 Instance, 700 TypeBracketValue, 701 TypeBracketType, 702 } 703 704 struct Pattern { 705 private: 706 alias Desc = Type.Desc; 707 708 import util.bitfields; 709 enum KindSize = EnumSize!PatternKind; 710 enum Pad = ulong.sizeof * 8 - Type.Desc.DataSize; 711 enum CountSize = ulong.sizeof * 8 - KindSize - Pad; 712 713 import std.bitmanip; 714 mixin(bitfields!( 715 // sdfmt off 716 PatternKind, "kind", KindSize, 717 ulong, "argCount", CountSize, 718 uint, "", Pad, // Pad for TypeKind and qualifier 719 // sdfmt on 720 )); 721 722 union Payload { 723 TypeTemplateParameter param; 724 TypeValuePair* typeValuePair; 725 TemplateArgument* args; 726 } 727 728 Payload payload; 729 730 static assert(Payload.sizeof == ulong.sizeof, 731 "Payload must be the same size as ulong."); 732 733 this(Desc desc, inout Payload payload) inout { 734 // /!\ Black magic ahead. 735 auto raw_desc = cast(ulong*) &desc; 736 737 // Remove the TypeKind and qualifier 738 *raw_desc = (*raw_desc >> Pad); 739 740 // This should point to an area of memory that have 741 // the correct layout for the bitfield. 742 auto p = cast(Pattern*) raw_desc; 743 744 // unqual trick required for bitfield 745 auto unqual_this = cast(Pattern*) &this; 746 unqual_this.kind = p.kind; 747 unqual_this.argCount = p.argCount; 748 749 this.payload = payload; 750 } 751 752 this(PatternKind k, ulong c, Payload p) { 753 kind = k; 754 argCount = c; 755 payload = p; 756 } 757 758 struct TypeValuePair { 759 Type type; 760 ValueTemplateParameter value; 761 } 762 763 auto getTypeValuePair() inout in { 764 assert(kind == PatternKind.TypeBracketValue); 765 } do { 766 return payload.typeValuePair; 767 } 768 769 struct Instantiation { 770 Symbol instantiated; 771 TemplateArgument[] args; 772 } 773 774 auto getInstatiation() inout in { 775 assert(kind == PatternKind.Instance); 776 } do { 777 auto c = argCount; 778 return inout(Instantiation)( 779 payload.args[c].get!(TemplateArgument.Tag.Symbol), 780 payload.args[0 .. c]); 781 } 782 783 public: 784 import util.fastcast; 785 this(TypeTemplateParameter p) { 786 this(PatternKind.Parameter, 0, fastCast!Payload(p)); 787 } 788 789 this(Type t, ValueTemplateParameter v) { 790 auto p = new TypeValuePair(t, v); 791 this(PatternKind.TypeBracketValue, 0, fastCast!Payload(p)); 792 } 793 794 this(Symbol instantiated, TemplateArgument[] args) { 795 args ~= TemplateArgument(instantiated); 796 this(PatternKind.Instance, args.length - 1, fastCast!Payload(args.ptr)); 797 } 798 799 @property 800 auto parameter() inout in { 801 assert(kind == PatternKind.Parameter); 802 } do { 803 return payload.param; 804 } 805 806 Type getType(TypeQualifier q = TypeQualifier.Mutable) { 807 ulong d = *cast(ulong*) &this; 808 return Type(Desc(TypeKind.Pattern, q, d), payload); 809 } 810 811 auto accept(T)(ref T t) if (is(T == struct)) { 812 return acceptImpl(&t); 813 } 814 815 auto accept(T)(T t) if (is(T == class)) { 816 return acceptImpl(t); 817 } 818 819 string toString(const Context c) const { 820 final switch (kind) with (PatternKind) { 821 case Parameter: 822 return parameter.name.toString(c); 823 824 case Instance: 825 assert(0, "Not implemented"); 826 827 case TypeBracketValue: 828 auto p = getTypeValuePair(); 829 return 830 p.type.toString(c) ~ '[' ~ p.value.name.toString(c) ~ ']'; 831 832 case TypeBracketType: 833 assert(0, "Not implemented"); 834 } 835 } 836 837 private: 838 auto acceptImpl(T)(T t) { 839 final switch (kind) with (PatternKind) { 840 case Parameter: 841 return t.visit(parameter); 842 843 case Instance: 844 auto i = getInstatiation(); 845 return t.visit(i.instantiated, i.args); 846 847 case TypeBracketValue: 848 auto p = getTypeValuePair(); 849 return t.visit(p.type, p.value); 850 851 case TypeBracketType: 852 assert(0, "Not implemented"); 853 } 854 } 855 } 856 857 private: 858 859 // XXX: we put it as a UFCS property to avoid forward reference. 860 @property 861 inout(ParamType)* params(inout Payload p) { 862 import util.fastcast; 863 return cast(inout ParamType*) p.next; 864 } 865 866 union Payload { 867 Type* next; 868 869 // Symbols 870 TypeAlias dalias; 871 Class dclass; 872 Interface dinterface; 873 Struct dstruct; 874 Union dunion; 875 Enum denum; 876 877 // Context 878 Function context; 879 880 // For function and delegates. 881 // ParamType* params; 882 883 // For template instanciation. 884 Pattern.Payload patternPayload; 885 886 // For speculative compilation. 887 CompileError error; 888 889 // For simple construction 890 Symbol sym; 891 Aggregate agg; 892 }