feat(lang): Generalize core types (WIP)
b5fc83f3c8d96e8d017850be318ee4b3a38083c97dcd5698f6401b3d851d1b7c
Use generic arrays, slices, and vectors throughout the compiler and RV64 backend. Keep slice values limited to pointer and length while vectors track initialized length and capacity. Add bounded overlap-safe relocation, canonical cross-package generic names, and tests for vector growth, array lengths, and relocation.
1 parent
3225bfc0
Makefile
+6 -1
| 90 | 90 | ||
| 91 | 91 | # A `.rad` executable test can have a same-basename `.ras` module. |
|
| 92 | 92 | $(patsubst %.ras,%.rv64,$(BIN_TEST_RAD_ASM_SRC)): %.rv64: %.ras |
|
| 93 | 93 | $(patsubst %.start.ras,%.rv64,$(BIN_TEST_RAD_START_SRC)): %.rv64: %.start.ras |
|
| 94 | 94 | ||
| 95 | + | # Cross-package generic tests compile with the standard library. |
|
| 96 | + | $(BIN_TEST_DIR)/vec.generic.rv64: $(BIN_TEST_DIR)/vec.generic.rad $(STD_LIB) $(RAD_BIN) |
|
| 97 | + | @echo "radiance $(BIN_TEST_DIR)/vec.generic.rad => $@" |
|
| 98 | + | @$(RADIANCE) $(STD) -pkg test -mod $< -entry test -o $@ |
|
| 99 | + | ||
| 95 | 100 | # Compile each executable test to a binary. |
|
| 96 | 101 | $(BIN_TEST_DIR)/%.rv64: $(BIN_TEST_DIR)/%.rad $(RAD_BIN) |
|
| 97 | 102 | @echo "radiance $< => $@" |
|
| 98 | 103 | @$(RADIANCE) -pkg test -mod $< $(patsubst %,-mod %,$(wildcard $(@:.rv64=)/*.rad)) $(patsubst %,-start %,$(wildcard $(@:.rv64=.start.ras))) $(patsubst %,-mod %,$(wildcard $(@:.rv64=.ras))) -o $@ |
|
| 99 | 104 |
| 104 | 109 | clean-bin-test: |
|
| 105 | 110 | @rm -f $(BIN_RUNNER) \ |
|
| 106 | 111 | $(BIN_RUNNER:.rv64=.rv64.debug) \ |
|
| 107 | 112 | $(BIN_RUNNER:.rv64=.rv64.s) \ |
|
| 108 | 113 | $(BIN_RUNNER:.rv64=.rv64.o) \ |
|
| 109 | - | $(BIN_TEST_EXE_BIN) \ |
|
| 114 | + | $(wildcard $(BIN_TEST_DIR)/*.rv64) \ |
|
| 110 | 115 | $(wildcard $(BIN_TEST_DIR)/*.rv64.debug) \ |
|
| 111 | 116 | $(wildcard $(BIN_TEST_DIR)/*.rv64.s) |
|
| 112 | 117 | ||
| 113 | 118 | seed: |
|
| 114 | 119 | seed/update |
compiler/radiance.rad
+62 -22
| 1 | 1 | //! Radiance compiler front-end. |
|
| 2 | 2 | use std::mem; |
|
| 3 | 3 | use std::fmt; |
|
| 4 | + | use std::vec; |
|
| 4 | 5 | use std::io; |
|
| 5 | 6 | use std::lang::alloc; |
|
| 6 | 7 | use std::lang::ast; |
|
| 7 | 8 | use std::lang::parser; |
|
| 8 | 9 | use std::lang::scanner; |
| 20 | 21 | use std::lang::gen::types; |
|
| 21 | 22 | use std::sys; |
|
| 22 | 23 | use std::sys::unix; |
|
| 23 | 24 | use std::collections::dict; |
|
| 24 | 25 | ||
| 26 | + | instantiate vec::append⟨*ast::Node⟩, |
|
| 27 | + | vec::viewMut⟨*ast::Node⟩, |
|
| 28 | + | vec::viewMut⟨resolver::Error⟩, |
|
| 29 | + | vec::view⟨il::Data⟩; |
|
| 30 | + | ||
| 25 | 31 | /// Maximum number of modules we can load per package. |
|
| 26 | 32 | constant MAX_LOADED_MODULES: u32 = 64; |
|
| 27 | 33 | /// Maximum number of packages we can compile. |
|
| 28 | 34 | constant MAX_PACKAGES: u32 = 4; |
|
| 29 | 35 | /// Total module entries across all packages. |
| 658 | 664 | } |
|
| 659 | 665 | set funcPath[desc.modPath.len - 1] = desc.fnName; |
|
| 660 | 666 | let funcArg = synthScopeAccess(arena, &funcPath[..desc.modPath.len]); |
|
| 661 | 667 | ||
| 662 | 668 | let a = alloc::arenaAllocator(&mut arena.arena); |
|
| 663 | - | let args = ast::nodeSlice(arena, 3) |
|
| 664 | - | .append(modArg, a) |
|
| 665 | - | .append(nameArg, a) |
|
| 666 | - | .append(funcArg, a); |
|
| 667 | - | ||
| 668 | - | return ast::synthNode(arena, ast::NodeValue::Call(ast::Call { callee, args })); |
|
| 669 | + | let mut args = ast::nodeVec(arena, 3); |
|
| 670 | + | vec::append⟨*ast::Node⟩(&mut args, modArg, a); |
|
| 671 | + | vec::append⟨*ast::Node⟩(&mut args, nameArg, a); |
|
| 672 | + | vec::append⟨*ast::Node⟩(&mut args, funcArg, a); |
|
| 673 | + | let argsView = vec::viewMut⟨*ast::Node⟩(&mut args); |
|
| 674 | + | ||
| 675 | + | return ast::synthNode(arena, ast::NodeValue::Call(ast::Call { |
|
| 676 | + | callee, |
|
| 677 | + | args: argsView, |
|
| 678 | + | })); |
|
| 669 | 679 | } |
|
| 670 | 680 | ||
| 671 | 681 | /// Inject a test runner into the entry package's root module. |
|
| 672 | 682 | /// |
|
| 673 | 683 | /// Scans all parsed modules for `@test fn` declarations, then appends |
| 714 | 724 | ||
| 715 | 725 | /// Synthesize the test entry point. |
|
| 716 | 726 | fn synthTestMainFn(arena: *mut ast::NodeArena, tests: *[TestDesc]) -> *ast::Node { |
|
| 717 | 727 | // Build array literal: `[testing::test(...), ...]`. |
|
| 718 | 728 | let a = alloc::arenaAllocator(&mut arena.arena); |
|
| 719 | - | let mut elements = ast::nodeSlice(arena, tests.len as u32); |
|
| 729 | + | let mut elements = ast::nodeVec(arena, tests.len as u32); |
|
| 720 | 730 | for i in 0..tests.len { |
|
| 721 | - | elements.append(synthTestCall(arena, &tests[i]), a); |
|
| 731 | + | vec::append⟨*ast::Node⟩(&mut elements, synthTestCall(arena, &tests[i]), a); |
|
| 722 | 732 | } |
|
| 723 | - | let arrayLit = ast::synthNode(arena, ast::NodeValue::ArrayLit(elements)); |
|
| 733 | + | let arrayLit = ast::synthNode( |
|
| 734 | + | arena, |
|
| 735 | + | ast::NodeValue::ArrayLit(vec::viewMut⟨*ast::Node⟩(&mut elements)) |
|
| 736 | + | ); |
|
| 724 | 737 | ||
| 725 | 738 | // Build: `&[...]`. |
|
| 726 | 739 | let testsRef = ast::synthNode(arena, ast::NodeValue::AddressOf(ast::AddressOf { |
|
| 727 | 740 | target: arrayLit, mutable: false, |
|
| 728 | 741 | })); |
|
| 729 | 742 | ||
| 730 | 743 | // Build: `testing::runAllTests(&[...])`. |
|
| 731 | 744 | let runFn = synthScopeAccess(arena, &["testing", "runAllTests"]); |
|
| 732 | - | let callArgs = ast::nodeSlice(arena, 1).append(testsRef, a); |
|
| 745 | + | let mut callArgs = ast::nodeVec(arena, 1); |
|
| 746 | + | vec::append⟨*ast::Node⟩(&mut callArgs, testsRef, a); |
|
| 733 | 747 | let callExpr = ast::synthNode(arena, ast::NodeValue::Call(ast::Call { |
|
| 734 | - | callee: runFn, args: callArgs, |
|
| 748 | + | callee: runFn, args: vec::viewMut⟨*ast::Node⟩(&mut callArgs), |
|
| 735 | 749 | })); |
|
| 736 | 750 | ||
| 737 | 751 | // Build: `return testing::runAllTests(&[...]);` |
|
| 738 | 752 | let retStmt = ast::synthNode(arena, ast::NodeValue::Return { value: callExpr }); |
|
| 739 | - | let bodyStmts = ast::nodeSlice(arena, 1).append(retStmt, a); |
|
| 740 | - | let fnBody = ast::synthNode(arena, ast::NodeValue::Block(ast::Block { statements: bodyStmts })); |
|
| 753 | + | let mut bodyStmts = ast::nodeVec(arena, 1); |
|
| 754 | + | vec::append⟨*ast::Node⟩(&mut bodyStmts, retStmt, a); |
|
| 755 | + | let fnBody = ast::synthNode(arena, ast::NodeValue::Block(ast::Block { |
|
| 756 | + | statements: vec::viewMut⟨*ast::Node⟩(&mut bodyStmts), |
|
| 757 | + | })); |
|
| 741 | 758 | ||
| 742 | 759 | // Build: `fn #testMain() -> i32` |
|
| 743 | 760 | let fnName = ast::synthNode(arena, ast::NodeValue::Ident(strings::intern(&mut STRING_POOL, "#testMain"))); |
|
| 744 | 761 | let returnType = ast::synthNode(arena, ast::NodeValue::TypeSig(ast::TypeSig::Integer { |
|
| 745 | 762 | width: 4, sign: ast::Signedness::Signed, |
|
| 746 | 763 | })); |
|
| 747 | 764 | let fnSig = ast::FnSig { |
|
| 748 | - | params: ast::nodeSlice(arena, 0), |
|
| 765 | + | params: &mut [], |
|
| 749 | 766 | returnType, |
|
| 750 | - | throwList: ast::nodeSlice(arena, 0), |
|
| 767 | + | throwList: &mut [], |
|
| 751 | 768 | }; |
|
| 752 | 769 | ||
| 753 | 770 | // `@default` attribute. |
|
| 754 | 771 | let attrNode = ast::synthNode(arena, ast::NodeValue::Attribute(ast::Attribute::Default)); |
|
| 755 | - | let attrList = ast::nodeSlice(arena, 1).append(attrNode, a); |
|
| 756 | - | let fnAttrs = ast::Attributes { list: attrList }; |
|
| 772 | + | let mut attrList = ast::nodeVec(arena, 1); |
|
| 773 | + | vec::append⟨*ast::Node⟩(&mut attrList, attrNode, a); |
|
| 774 | + | let fnAttrs = ast::Attributes { |
|
| 775 | + | list: vec::viewMut⟨*ast::Node⟩(&mut attrList), |
|
| 776 | + | }; |
|
| 757 | 777 | ||
| 758 | 778 | return ast::synthNode(arena, ast::NodeValue::FnDecl(ast::FnDecl { |
|
| 759 | - | name: fnName, params: ast::nodeSlice(arena, 0), sig: fnSig, body: fnBody, attrs: fnAttrs, |
|
| 779 | + | name: fnName, |
|
| 780 | + | params: &mut [], |
|
| 781 | + | sig: fnSig, |
|
| 782 | + | body: fnBody, |
|
| 783 | + | attrs: fnAttrs, |
|
| 760 | 784 | })); |
|
| 761 | 785 | } |
|
| 762 | 786 | ||
| 763 | 787 | /// Append a declaration to a block node's statement list. |
|
| 764 | 788 | fn injectIntoBlock( |
| 767 | 791 | decl: *ast::Node |
|
| 768 | 792 | ) { |
|
| 769 | 793 | let case ast::NodeValue::Block(block) = blockNode.value else { |
|
| 770 | 794 | panic "injectIntoBlock: expected Block node"; |
|
| 771 | 795 | }; |
|
| 772 | - | let stmts = block.statements.append(decl, alloc::arenaAllocator(&mut arena.arena)); |
|
| 773 | - | set blockNode.value = ast::NodeValue::Block(ast::Block { statements: stmts }); |
|
| 796 | + | let a = alloc::arenaAllocator(&mut arena.arena); |
|
| 797 | + | let mut stmts = ast::nodeVec(arena, block.statements.len as u32 + 1); |
|
| 798 | + | for stmt in block.statements { |
|
| 799 | + | vec::append⟨*ast::Node⟩(&mut stmts, stmt, a); |
|
| 800 | + | } |
|
| 801 | + | vec::append⟨*ast::Node⟩(&mut stmts, decl, a); |
|
| 802 | + | set blockNode.value = ast::NodeValue::Block(ast::Block { |
|
| 803 | + | statements: vec::viewMut⟨*ast::Node⟩(&mut stmts), |
|
| 804 | + | }); |
|
| 774 | 805 | } |
|
| 775 | 806 | ||
| 776 | 807 | /// Write a self-contained RV64 image containing text and data sections. |
|
| 777 | 808 | fn writeImage( |
|
| 778 | 809 | code: *[u32], |
| 871 | 902 | } |
|
| 872 | 903 | ||
| 873 | 904 | // Resolve all packages. |
|
| 874 | 905 | // TODO: Fix this error printing dance. |
|
| 875 | 906 | let diags = try resolver::resolve(&mut res, &ctx.graph, &resolverPkgs[..resolverPackageCount]) catch { |
|
| 876 | - | let diags = resolver::Diagnostics { errors: res.errors }; |
|
| 907 | + | let diags = resolver::Diagnostics { |
|
| 908 | + | errors: vec::viewMut⟨resolver::Error⟩(&mut res.errors), |
|
| 909 | + | }; |
|
| 877 | 910 | resolver::printer::printDiagnostics(&diags, &res); |
|
| 878 | 911 | throw Error::Other; |
|
| 879 | 912 | }; |
|
| 880 | 913 | if not resolver::success(&diags) { |
|
| 881 | 914 | resolver::printer::printDiagnostics(&diags, &res); |
| 1026 | 1059 | else => {} |
|
| 1027 | 1060 | } |
|
| 1028 | 1061 | if let path = codegenOptions.logPath { |
|
| 1029 | 1062 | pkgLog(entryPkg, &["generating code", "(", path, ")", ".."]); |
|
| 1030 | 1063 | } |
|
| 1031 | - | return rv64::finishProgram(&mut generator, &low.data[..], storage, asmData, &mut RO_DATA_BUF[..], &mut RW_DATA_BUF[..]); |
|
| 1064 | + | return rv64::finishProgram( |
|
| 1065 | + | &mut generator, |
|
| 1066 | + | vec::view⟨il::Data⟩(&low.data), |
|
| 1067 | + | storage, |
|
| 1068 | + | asmData, |
|
| 1069 | + | &mut RO_DATA_BUF[..], |
|
| 1070 | + | &mut RW_DATA_BUF[..], |
|
| 1071 | + | ); |
|
| 1032 | 1072 | } |
|
| 1033 | 1073 | ||
| 1034 | 1074 | /// Lower, optionally dump, and optionally generate binary output. |
|
| 1035 | 1075 | fn compile( |
|
| 1036 | 1076 | ctx: *mut CompileContext, |
lib/std.rad
+3 -2
| 1 | 1 | //! The Radiance Standard Library. |
|
| 2 | 2 | ||
| 3 | + | export mod lang; |
|
| 4 | + | export mod slice; |
|
| 5 | + | export mod vec; |
|
| 3 | 6 | export mod io; |
|
| 4 | 7 | export mod collections; |
|
| 5 | 8 | export mod char; |
|
| 6 | - | export mod lang; |
|
| 7 | 9 | export mod sys; |
|
| 8 | 10 | export mod arch; |
|
| 9 | 11 | export mod fmt; |
|
| 10 | 12 | export mod mem; |
|
| 11 | - | export mod vec; |
|
| 12 | 13 | export mod intrinsics; |
|
| 13 | 14 | ||
| 14 | 15 | // Test modules. |
|
| 15 | 16 | @test export mod testing; |
|
| 16 | 17 | @test export mod tests; |
lib/std/arch/rv64.rad
+1 -1
| 346 | 346 | let rwDataSize = data::emitSection( |
|
| 347 | 347 | globalData, &dataSymMap, &generator.e.labels, codeBase, rwDataBuf, false |
|
| 348 | 348 | ); |
|
| 349 | 349 | return Program { |
|
| 350 | 350 | code: emit::getCode(&generator.e), |
|
| 351 | - | funcs: generator.e.funcs, |
|
| 351 | + | funcs: emit::getFuncs(&generator.e), |
|
| 352 | 352 | roDataSize, |
|
| 353 | 353 | rwDataSize, |
|
| 354 | 354 | debugEntries: emit::getDebugEntries(&generator.e), |
|
| 355 | 355 | }; |
|
| 356 | 356 | } |
lib/std/arch/rv64/asm.rad
+37 -19
| 40 | 40 | use std::lang::strings; |
|
| 41 | 41 | use std::lang::gen; |
|
| 42 | 42 | use std::collections::dict; |
|
| 43 | 43 | use std::arch::rv64::encode; |
|
| 44 | 44 | use std::arch::rv64; |
|
| 45 | + | use std::vec; |
|
| 46 | + | ||
| 47 | + | instantiate vec::view⟨u32⟩; |
|
| 48 | + | ||
| 49 | + | instantiate vec::view⟨u8⟩; |
|
| 50 | + | ||
| 51 | + | instantiate vec::view⟨Symbol⟩; |
|
| 52 | + | ||
| 53 | + | instantiate vec::view⟨Fixup⟩; |
|
| 45 | 54 | ||
| 46 | 55 | /// Assembler scanner module. |
|
| 47 | 56 | export mod scanner; |
|
| 48 | 57 | /// Assembler parser module. |
|
| 49 | 58 | export mod parser; |
| 455 | 464 | export record Assembler { |
|
| 456 | 465 | /// Allocation arena for temporary assembler state. |
|
| 457 | 466 | arena: *mut alloc::Arena, |
|
| 458 | 467 | /// Assembler lexical scanner. |
|
| 459 | 468 | scan: scanner::Scanner, |
|
| 460 | - | /// Output text buffer. |
|
| 461 | - | text: *mut [u32], |
|
| 462 | - | /// Output data buffer. |
|
| 463 | - | data: *mut [u8], |
|
| 469 | + | /// Append-backed output text storage. |
|
| 470 | + | text: vec::Vec⟨u32⟩, |
|
| 471 | + | /// Append-backed output data storage. |
|
| 472 | + | data: vec::Vec⟨u8⟩, |
|
| 464 | 473 | /// Current output section. |
|
| 465 | 474 | section: Section, |
|
| 466 | - | /// Defined symbols. |
|
| 467 | - | symbols: *mut [Symbol], |
|
| 475 | + | /// Append-backed defined symbols. |
|
| 476 | + | symbols: vec::Vec⟨Symbol⟩, |
|
| 468 | 477 | /// Name-to-symbol index map. |
|
| 469 | 478 | symbolMap: dict::Dict, |
|
| 470 | 479 | /// Name-to-integer map. |
|
| 471 | 480 | constMap: dict::Dict, |
|
| 472 | 481 | /// Names marked by `.export`. |
|
| 473 | 482 | exportMap: dict::Dict, |
|
| 474 | - | /// Pending fixups. |
|
| 475 | - | fixups: *mut [Fixup], |
|
| 476 | - | /// Fixups that reference text outside this assembly fragment. |
|
| 477 | - | externalFixups: *mut [Fixup], |
|
| 483 | + | /// Append-backed pending fixups. |
|
| 484 | + | fixups: vec::Vec⟨Fixup⟩, |
|
| 485 | + | /// Append-backed fixups that reference text outside this assembly fragment. |
|
| 486 | + | externalFixups: vec::Vec⟨Fixup⟩, |
|
| 478 | 487 | /// Absolute runtime address of data-section offset zero. |
|
| 479 | 488 | dataBase: u32, |
|
| 480 | 489 | } |
|
| 481 | 490 | ||
| 482 | 491 | /// Assemble source using `dataBase` as the runtime address of the data-section. |
| 500 | 509 | let exportEntries = try! alloc::allocSlice(arena, @sizeOf(dict::Entry), @alignOf(dict::Entry), tableCap); |
|
| 501 | 510 | ||
| 502 | 511 | let mut a = Assembler { |
|
| 503 | 512 | arena, |
|
| 504 | 513 | scan: scanner::scanner(sourceKind, source, pool), |
|
| 505 | - | text: @sliceOf(textBuf.ptr, 0, textBuf.len), |
|
| 506 | - | data: @sliceOf(dataBuf.ptr, 0, dataBuf.len), |
|
| 514 | + | text: vec::Vec⟨u32⟩ { data: textBuf, len: 0 }, |
|
| 515 | + | data: vec::Vec⟨u8⟩ { data: dataBuf, len: 0 }, |
|
| 507 | 516 | section: Section::Text, |
|
| 508 | - | symbols: @sliceOf((symbols as *mut [Symbol]).ptr, 0, (symbols as *mut [Symbol]).len), |
|
| 517 | + | symbols: vec::Vec⟨Symbol⟩ { |
|
| 518 | + | data: symbols as *mut [Symbol], |
|
| 519 | + | len: 0, |
|
| 520 | + | }, |
|
| 509 | 521 | symbolMap: dict::init(entries as *mut [dict::Entry]), |
|
| 510 | 522 | constMap: dict::init(constEntries as *mut [dict::Entry]), |
|
| 511 | 523 | exportMap: dict::init(exportEntries as *mut [dict::Entry]), |
|
| 512 | - | fixups: @sliceOf((fixups as *mut [Fixup]).ptr, 0, (fixups as *mut [Fixup]).len), |
|
| 513 | - | externalFixups: @sliceOf((externalFixups as *mut [Fixup]).ptr, 0, (externalFixups as *mut [Fixup]).len), |
|
| 524 | + | fixups: vec::Vec⟨Fixup⟩ { |
|
| 525 | + | data: fixups as *mut [Fixup], |
|
| 526 | + | len: 0, |
|
| 527 | + | }, |
|
| 528 | + | externalFixups: vec::Vec⟨Fixup⟩ { |
|
| 529 | + | data: externalFixups as *mut [Fixup], |
|
| 530 | + | len: 0, |
|
| 531 | + | }, |
|
| 514 | 532 | dataBase, |
|
| 515 | 533 | }; |
|
| 516 | 534 | // Parse assembly source and emit instructions. |
|
| 517 | 535 | try parser::parseProgram(&mut a); |
|
| 518 | 536 | // Resolve fixups and finalize program. |
|
| 519 | 537 | try emit::finishProgram(&mut a); |
|
| 520 | 538 | ||
| 521 | 539 | return Program { |
|
| 522 | - | text: a.text, |
|
| 523 | - | data: a.data, |
|
| 524 | - | symbols: a.symbols, |
|
| 525 | - | externalFixups: a.externalFixups, |
|
| 540 | + | text: vec::view⟨u32⟩(&a.text), |
|
| 541 | + | data: vec::view⟨u8⟩(&a.data), |
|
| 542 | + | symbols: vec::view⟨Symbol⟩(&a.symbols), |
|
| 543 | + | externalFixups: vec::view⟨Fixup⟩(&a.externalFixups), |
|
| 526 | 544 | }; |
|
| 527 | 545 | } |
|
| 528 | 546 | ||
| 529 | 547 | /// Return the next power of two at least as large as `value`. |
|
| 530 | 548 | fn nextPowerOfTwo(value: u32) -> u32 { |
lib/std/arch/rv64/asm/emit.rad
+28 -13
| 5 | 5 | use std::fmt; |
|
| 6 | 6 | ||
| 7 | 7 | use std::collections::dict; |
|
| 8 | 8 | use std::lang::alloc; |
|
| 9 | 9 | use std::lang::gen; |
|
| 10 | + | use std::vec; |
|
| 11 | + | ||
| 12 | + | instantiate vec::append⟨super::Symbol⟩, |
|
| 13 | + | vec::view⟨super::Symbol⟩; |
|
| 14 | + | ||
| 15 | + | instantiate vec::append⟨u32⟩, |
|
| 16 | + | vec::viewMut⟨u32⟩; |
|
| 17 | + | ||
| 18 | + | instantiate vec::append⟨u8⟩, |
|
| 19 | + | vec::viewMut⟨u8⟩; |
|
| 20 | + | ||
| 21 | + | instantiate vec::append⟨super::Fixup⟩, |
|
| 22 | + | vec::view⟨super::Fixup⟩; |
|
| 10 | 23 | ||
| 11 | 24 | /// Define a symbol at the current text or data offset. |
|
| 12 | 25 | export fn defineSymbol(a: *mut super::Assembler, name: *[u8]) { |
|
| 13 | 26 | let idx = a.symbols.len; |
|
| 14 | 27 | let offset: i32 = a.data.len as i32 |
|
| 15 | 28 | if a.section == super::Section::Data |
|
| 16 | 29 | else a.text.len as i32 * rv64::INSTR_SIZE; |
|
| 17 | 30 | ||
| 18 | - | a.symbols.append(super::Symbol { |
|
| 31 | + | vec::append⟨super::Symbol⟩(&mut a.symbols, super::Symbol { |
|
| 19 | 32 | name, |
|
| 20 | 33 | section: a.section, |
|
| 21 | 34 | offset, |
|
| 22 | 35 | isExported: dict::get(&a.exportMap, name) <> nil, |
|
| 23 | 36 | }, alloc::arenaAllocator(a.arena)); |
|
| 24 | 37 | dict::insert(&mut a.symbolMap, name, idx as i32); |
|
| 25 | 38 | } |
|
| 26 | 39 | ||
| 27 | 40 | /// Append one encoded instruction word to the text section. |
|
| 28 | 41 | export fn emitText(a: *mut super::Assembler, word: u32) throws (super::Error) { |
|
| 29 | - | a.text.append(word, alloc::arenaAllocator(a.arena)); |
|
| 42 | + | vec::append⟨u32⟩(&mut a.text, word, alloc::arenaAllocator(a.arena)); |
|
| 30 | 43 | } |
|
| 31 | 44 | ||
| 32 | 45 | /// Append `words` no-op instructions to the text section. |
|
| 33 | 46 | export fn emitTextPadding(a: *mut super::Assembler, words: u32) throws (super::Error) { |
|
| 34 | 47 | for _ in 0..words { |
| 36 | 49 | } |
|
| 37 | 50 | } |
|
| 38 | 51 | ||
| 39 | 52 | /// Append one byte to the data section. |
|
| 40 | 53 | export fn emitByte(a: *mut super::Assembler, byte: u8) throws (super::Error) { |
|
| 41 | - | a.data.append(byte, alloc::arenaAllocator(a.arena)); |
|
| 54 | + | vec::append⟨u8⟩(&mut a.data, byte, alloc::arenaAllocator(a.arena)); |
|
| 42 | 55 | } |
|
| 43 | 56 | ||
| 44 | 57 | /// Emit a little-endian integer with `bytes` bytes. |
|
| 45 | 58 | fn emitDataInt(a: *mut super::Assembler, bits: u64, bytes: u32) throws (super::Error) { |
|
| 46 | 59 | for i in 0..bytes { |
| 48 | 61 | } |
|
| 49 | 62 | } |
|
| 50 | 63 | ||
| 51 | 64 | /// Patch a little-endian integer with `bytes` bytes. |
|
| 52 | 65 | fn patchDataInt(a: *mut super::Assembler, offset: u32, bits: u64, bytes: u32) { |
|
| 66 | + | let data = vec::viewMut⟨u8⟩(&mut a.data); |
|
| 53 | 67 | for i in 0..bytes { |
|
| 54 | - | set a.data[offset + i] = ((bits >> ((i as u64) * super::BITS_PER_BYTE)) & super::BYTE_MASK) as u8; |
|
| 68 | + | set data[offset + i] = ((bits >> ((i as u64) * super::BITS_PER_BYTE)) & super::BYTE_MASK) as u8; |
|
| 55 | 69 | } |
|
| 56 | 70 | } |
|
| 57 | 71 | ||
| 58 | 72 | /// Emit an integer data directive value. |
|
| 59 | 73 | export fn emitDataValue(a: *mut super::Assembler, value: i64, width: super::DataWidth) throws (super::Error) { |
| 78 | 92 | } |
|
| 79 | 93 | } |
|
| 80 | 94 | ||
| 81 | 95 | /// Record a pending symbol fixup. |
|
| 82 | 96 | fn recordFixup(a: *mut super::Assembler, symbol: *[u8], info: super::FixupInfo) { |
|
| 83 | - | a.fixups.append(super::Fixup { symbol, info }, alloc::arenaAllocator(a.arena)); |
|
| 97 | + | vec::append⟨super::Fixup⟩(&mut a.fixups, super::Fixup { symbol, info }, alloc::arenaAllocator(a.arena)); |
|
| 84 | 98 | } |
|
| 85 | 99 | ||
| 86 | 100 | /// Record a text fixup that must be resolved after all program text is known. |
|
| 87 | 101 | fn recordExternalFixup(a: *mut super::Assembler, fixup: super::Fixup) { |
|
| 88 | - | a.externalFixups.append(fixup, alloc::arenaAllocator(a.arena)); |
|
| 102 | + | vec::append⟨super::Fixup⟩(&mut a.externalFixups, fixup, alloc::arenaAllocator(a.arena)); |
|
| 89 | 103 | } |
|
| 90 | 104 | ||
| 91 | 105 | /// Record a text-section symbol fixup and reserve its instruction words. |
|
| 92 | 106 | export fn recordTextFixup(a: *mut super::Assembler, symbol: *[u8], info: super::FixupInfo, words: u32) throws (super::Error) { |
|
| 93 | 107 | recordFixup(a, symbol, info); |
| 96 | 110 | ||
| 97 | 111 | /// Find a previously defined symbol by name. |
|
| 98 | 112 | fn findSymbol(a: *super::Assembler, name: *[u8]) -> ?super::Symbol { |
|
| 99 | 113 | let idx = dict::get(&a.symbolMap, name) |
|
| 100 | 114 | else return nil; |
|
| 101 | - | return a.symbols[idx as u32]; |
|
| 115 | + | return vec::view⟨super::Symbol⟩(&a.symbols)[idx as u32]; |
|
| 102 | 116 | } |
|
| 103 | 117 | ||
| 104 | 118 | /// Return the final address for a data symbol. |
|
| 105 | 119 | fn dataSymbolAddr(a: *super::Assembler, symbol: super::Symbol) -> i32 throws (super::Error) { |
|
| 106 | 120 | if symbol.section <> super::Section::Data { |
| 109 | 123 | return symbol.offset + (a.dataBase as i32); |
|
| 110 | 124 | } |
|
| 111 | 125 | ||
| 112 | 126 | /// Resolve final symbol references and patch all delayed output. |
|
| 113 | 127 | export fn finishProgram(a: *mut super::Assembler) throws (super::Error) { |
|
| 114 | - | for i in 0..a.fixups.len { |
|
| 115 | - | let fixup = a.fixups[i]; |
|
| 128 | + | let fixups = vec::view⟨super::Fixup⟩(&a.fixups); |
|
| 129 | + | let text = vec::viewMut⟨u32⟩(&mut a.text); |
|
| 130 | + | for fixup in fixups { |
|
| 116 | 131 | let symbol = findSymbol(a, fixup.symbol) else { |
|
| 117 | 132 | match fixup.info { |
|
| 118 | 133 | case super::FixupInfo::Jal { .. }, super::FixupInfo::Addr { .. } => { |
|
| 119 | 134 | recordExternalFixup(a, fixup); |
|
| 120 | 135 | continue; |
| 133 | 148 | if not encode::isBranchImm(rel) { |
|
| 134 | 149 | throw super::Error::Invalid { offset: 0, message: "branch target out of range" }; |
|
| 135 | 150 | } |
|
| 136 | 151 | let word = encodeBranch(op, rs1, rs2, rel); |
|
| 137 | 152 | ||
| 138 | - | set a.text[index] = word; |
|
| 153 | + | set text[index] = word; |
|
| 139 | 154 | } |
|
| 140 | 155 | case super::FixupInfo::Jal { rd, index } => { |
|
| 141 | 156 | if symbol.section <> super::Section::Text { |
|
| 142 | 157 | throw super::Error::Invalid { offset: 0, message: "jump target must be in text section" }; |
|
| 143 | 158 | } |
| 145 | 160 | let rel = symbol.offset - srcOffset; |
|
| 146 | 161 | ||
| 147 | 162 | if not encode::isJumpImm(rel) { |
|
| 148 | 163 | throw super::Error::Invalid { offset: 0, message: "jump target out of range" }; |
|
| 149 | 164 | } |
|
| 150 | - | set a.text[index] = encode::jal(rd, rel); |
|
| 165 | + | set text[index] = encode::jal(rd, rel); |
|
| 151 | 166 | } |
|
| 152 | 167 | case super::FixupInfo::Addr { rd, index } => { |
|
| 153 | 168 | let mut addr = symbol.offset - (index as i32 * rv64::INSTR_SIZE); |
|
| 154 | 169 | if symbol.section == super::Section::Data { |
|
| 155 | 170 | set addr = symbol.offset + (a.dataBase as i32); |
|
| 156 | 171 | } |
|
| 157 | 172 | let split = emit::splitImm(addr); |
|
| 158 | - | set a.text[index] = encode::lui(rd, split.hi) |
|
| 173 | + | set text[index] = encode::lui(rd, split.hi) |
|
| 159 | 174 | if symbol.section == super::Section::Data |
|
| 160 | 175 | else encode::auipc(rd, split.hi); |
|
| 161 | - | set a.text[index + 1] = encode::addi(rd, rd, split.lo); |
|
| 176 | + | set text[index + 1] = encode::addi(rd, rd, split.lo); |
|
| 162 | 177 | } |
|
| 163 | 178 | case super::FixupInfo::Word { offset } => { |
|
| 164 | 179 | let addr = try dataSymbolAddr(a, symbol); |
|
| 165 | 180 | patchDataInt(a, offset, addr as u64, rv64::WORD_SIZE as u32); |
|
| 166 | 181 | } |
lib/std/arch/rv64/asm/parser.rad
+5 -1
| 6 | 6 | use std::lang::parser; |
|
| 7 | 7 | use std::lang::gen; |
|
| 8 | 8 | use std::collections::dict; |
|
| 9 | 9 | use std::arch::rv64::encode; |
|
| 10 | 10 | use std::arch::rv64; |
|
| 11 | + | use std::vec; |
|
| 11 | 12 | ||
| 12 | 13 | use super::emit; |
|
| 13 | 14 | use super::scanner; |
|
| 14 | 15 | ||
| 16 | + | instantiate vec::viewMut⟨super::Symbol⟩; |
|
| 17 | + | ||
| 15 | 18 | /// Parsed memory operand with base register and signed byte offset. |
|
| 16 | 19 | record MemOperand { |
|
| 17 | 20 | /// Base register inside the memory operand parentheses. |
|
| 18 | 21 | base: gen::Reg, |
|
| 19 | 22 | /// Signed byte offset preceding the base register. |
| 556 | 559 | /// Parse a `.export` directive. |
|
| 557 | 560 | fn parseExportDirective(a: *mut super::Assembler) throws (super::Error) { |
|
| 558 | 561 | let name = try parseLabelName(a); |
|
| 559 | 562 | dict::insert(&mut a.exportMap, name, 1); |
|
| 560 | 563 | if let idx = dict::get(&a.symbolMap, name) { |
|
| 561 | - | set a.symbols[idx as u32].isExported = true; |
|
| 564 | + | let symbols = vec::viewMut⟨super::Symbol⟩(&mut a.symbols); |
|
| 565 | + | set symbols[idx as u32].isExported = true; |
|
| 562 | 566 | } |
|
| 563 | 567 | } |
|
| 564 | 568 | ||
| 565 | 569 | /// Parse a `.space` directive. |
|
| 566 | 570 | fn parseSpaceDirective(a: *mut super::Assembler) throws (super::Error) { |
lib/std/arch/rv64/emit.rad
+61 -25
| 8 | 8 | use std::lang::gen::data; |
|
| 9 | 9 | use std::lang::gen::labels; |
|
| 10 | 10 | use std::lang::gen::types; |
|
| 11 | 11 | use std::collections::dict; |
|
| 12 | 12 | use std::mem; |
|
| 13 | + | use std::vec; |
|
| 13 | 14 | ||
| 14 | 15 | use super::encode; |
|
| 15 | 16 | ||
| 17 | + | instantiate vec::append⟨PendingBranch⟩, |
|
| 18 | + | vec::view⟨PendingBranch⟩; |
|
| 19 | + | ||
| 20 | + | instantiate vec::append⟨PendingCall⟩, |
|
| 21 | + | vec::view⟨PendingCall⟩; |
|
| 22 | + | ||
| 23 | + | instantiate vec::append⟨PendingJump⟩, |
|
| 24 | + | vec::view⟨PendingJump⟩; |
|
| 25 | + | ||
| 26 | + | instantiate vec::append⟨PendingAddrLoad⟩, |
|
| 27 | + | vec::view⟨PendingAddrLoad⟩; |
|
| 28 | + | ||
| 29 | + | instantiate vec::append⟨types::FuncAddr⟩, |
|
| 30 | + | vec::view⟨types::FuncAddr⟩; |
|
| 31 | + | ||
| 16 | 32 | /// Maximum number of instructions in code buffer. |
|
| 17 | 33 | constant MAX_INSTRS: u32 = 2097152; |
|
| 18 | 34 | /// Maximum code length before byte offset overflows signed 32-bits. |
|
| 19 | 35 | constant MAX_CODE_LEN: u32 = 0x7FFFFFFF / super::INSTR_SIZE as u32; |
|
| 20 | 36 | /// Maximum positive value encodable by a signed 32-bit address calculation. |
| 103 | 119 | /// Emitted instructions storage. |
|
| 104 | 120 | code: *mut [u32], |
|
| 105 | 121 | /// Current number of emitted instructions. |
|
| 106 | 122 | codeLen: u32, |
|
| 107 | 123 | /// Local branches needing offset patching. |
|
| 108 | - | pendingBranches: *mut [PendingBranch], |
|
| 124 | + | pendingBranches: vec::Vec⟨PendingBranch⟩, |
|
| 109 | 125 | /// Function calls needing offset patching. |
|
| 110 | - | pendingCalls: *mut [PendingCall], |
|
| 126 | + | pendingCalls: vec::Vec⟨PendingCall⟩, |
|
| 111 | 127 | /// Assembly jumps needing offset patching. |
|
| 112 | - | pendingJumps: *mut [PendingJump], |
|
| 128 | + | pendingJumps: vec::Vec⟨PendingJump⟩, |
|
| 113 | 129 | /// Function address loads needing offset patching. |
|
| 114 | - | pendingAddrLoads: *mut [PendingAddrLoad], |
|
| 130 | + | pendingAddrLoads: vec::Vec⟨PendingAddrLoad⟩, |
|
| 115 | 131 | /// Block label tracking. |
|
| 116 | 132 | labels: labels::Labels, |
|
| 117 | 133 | /// Function start positions for printing. |
|
| 118 | - | funcs: *mut [types::FuncAddr], |
|
| 134 | + | funcs: vec::Vec⟨types::FuncAddr⟩, |
|
| 119 | 135 | /// Debug entries mapping PCs to source locations. |
|
| 120 | 136 | debugEntries: *mut [types::DebugEntry], |
|
| 121 | 137 | /// Number of debug entries recorded. |
|
| 122 | 138 | debugEntriesLen: u32, |
|
| 123 | 139 | } |
| 200 | 216 | } |
|
| 201 | 217 | return Emitter { |
|
| 202 | 218 | allocator: alloc::arenaAllocator(arena), |
|
| 203 | 219 | code: code as *mut [u32], |
|
| 204 | 220 | codeLen: 0, |
|
| 205 | - | pendingBranches: @sliceOf((pendingBranches as *mut [PendingBranch]).ptr, 0, MAX_PENDING), |
|
| 206 | - | pendingCalls: @sliceOf((pendingCalls as *mut [PendingCall]).ptr, 0, MAX_PENDING), |
|
| 207 | - | pendingJumps: @sliceOf((pendingJumps as *mut [PendingJump]).ptr, 0, MAX_PENDING), |
|
| 208 | - | pendingAddrLoads: @sliceOf((pendingAddrLoads as *mut [PendingAddrLoad]).ptr, 0, MAX_PENDING), |
|
| 221 | + | pendingBranches: vec::Vec⟨PendingBranch⟩ { |
|
| 222 | + | data: pendingBranches as *mut [PendingBranch], |
|
| 223 | + | len: 0, |
|
| 224 | + | }, |
|
| 225 | + | pendingCalls: vec::Vec⟨PendingCall⟩ { |
|
| 226 | + | data: pendingCalls as *mut [PendingCall], |
|
| 227 | + | len: 0, |
|
| 228 | + | }, |
|
| 229 | + | pendingJumps: vec::Vec⟨PendingJump⟩ { |
|
| 230 | + | data: pendingJumps as *mut [PendingJump], |
|
| 231 | + | len: 0, |
|
| 232 | + | }, |
|
| 233 | + | pendingAddrLoads: vec::Vec⟨PendingAddrLoad⟩ { |
|
| 234 | + | data: pendingAddrLoads as *mut [PendingAddrLoad], |
|
| 235 | + | len: 0, |
|
| 236 | + | }, |
|
| 209 | 237 | labels: labels::init(blockOffsets as *mut [i32], funcEntries as *mut [dict::Entry]), |
|
| 210 | - | funcs: @sliceOf((funcs as *mut [types::FuncAddr]).ptr, 0, MAX_FUNCS), |
|
| 238 | + | funcs: vec::Vec⟨types::FuncAddr⟩ { |
|
| 239 | + | data: funcs as *mut [types::FuncAddr], |
|
| 240 | + | len: 0, |
|
| 241 | + | }, |
|
| 211 | 242 | debugEntries, |
|
| 212 | 243 | debugEntriesLen: 0, |
|
| 213 | 244 | }; |
|
| 214 | 245 | } |
|
| 215 | 246 |
| 256 | 287 | recordFuncAt(e, name, e.codeLen); |
|
| 257 | 288 | } |
|
| 258 | 289 | ||
| 259 | 290 | /// Record a function's start position at `index` for printing. |
|
| 260 | 291 | export fn recordFuncAt(e: *mut Emitter, name: *[u8], index: u32) { |
|
| 261 | - | e.funcs.append(types::FuncAddr { name, index }, e.allocator); |
|
| 292 | + | vec::append⟨types::FuncAddr⟩(&mut e.funcs, types::FuncAddr { name, index }, e.allocator); |
|
| 262 | 293 | } |
|
| 263 | 294 | ||
| 264 | 295 | /// Record a local branch needing later patching. |
|
| 265 | 296 | /// Unconditional jumps use a single slot (J-type, +-1MB range). |
|
| 266 | 297 | /// Conditional branches use two slots (B-type has only +-4KB range, |
|
| 267 | 298 | /// so large functions may need the inverted-branch + JAL fallback). |
|
| 268 | 299 | export fn recordBranch(e: *mut Emitter, targetBlock: u32, kind: BranchKind) { |
|
| 269 | - | e.pendingBranches.append(PendingBranch { |
|
| 300 | + | vec::append⟨PendingBranch⟩(&mut e.pendingBranches, PendingBranch { |
|
| 270 | 301 | index: e.codeLen, |
|
| 271 | 302 | target: targetBlock, |
|
| 272 | 303 | kind: kind, |
|
| 273 | 304 | }, e.allocator); |
|
| 274 | 305 |
| 282 | 313 | ||
| 283 | 314 | /// Record a function call needing later patching. |
|
| 284 | 315 | /// Emits placeholder instructions that will be patched later. |
|
| 285 | 316 | /// Uses two slots to support long-distance calls. |
|
| 286 | 317 | export fn recordCall(e: *mut Emitter, target: *[u8]) { |
|
| 287 | - | e.pendingCalls.append(PendingCall { |
|
| 318 | + | vec::append⟨PendingCall⟩(&mut e.pendingCalls, PendingCall { |
|
| 288 | 319 | index: e.codeLen, |
|
| 289 | 320 | target, |
|
| 290 | 321 | }, e.allocator); |
|
| 291 | 322 | ||
| 292 | 323 | emit(e, encode::nop()); // Placeholder for AUIPC. |
|
| 293 | 324 | emit(e, encode::nop()); // Placeholder for JALR. |
|
| 294 | 325 | } |
|
| 295 | 326 | ||
| 296 | 327 | /// Record a jump emitted by assembly that needs whole-program patching. |
|
| 297 | 328 | export fn recordJumpAt(e: *mut Emitter, target: *[u8], rd: gen::Reg, index: u32) { |
|
| 298 | - | e.pendingJumps.append(PendingJump { |
|
| 329 | + | vec::append⟨PendingJump⟩(&mut e.pendingJumps, PendingJump { |
|
| 299 | 330 | index, |
|
| 300 | 331 | target, |
|
| 301 | 332 | rd, |
|
| 302 | 333 | }, e.allocator); |
|
| 303 | 334 | } |
| 312 | 343 | emit(e, encode::nop()); // Placeholder for ADDI. |
|
| 313 | 344 | } |
|
| 314 | 345 | ||
| 315 | 346 | /// Record a function address load already reserved by assembly. |
|
| 316 | 347 | export fn recordAddrLoadAt(e: *mut Emitter, target: *[u8], rd: gen::Reg, index: u32) { |
|
| 317 | - | e.pendingAddrLoads.append(PendingAddrLoad { |
|
| 348 | + | vec::append⟨PendingAddrLoad⟩(&mut e.pendingAddrLoads, PendingAddrLoad { |
|
| 318 | 349 | index, |
|
| 319 | 350 | target, |
|
| 320 | 351 | rd: rd, |
|
| 321 | 352 | isData: false, |
|
| 322 | 353 | }, e.allocator); |
|
| 323 | 354 | } |
|
| 324 | 355 | ||
| 325 | 356 | /// Record a data address load needing later patching. |
|
| 326 | 357 | /// Uses an absolute 32-bit load sequence matching the current data memory map. |
|
| 327 | 358 | export fn recordDataAddrLoad(e: *mut Emitter, target: *[u8], rd: gen::Reg) { |
|
| 328 | - | e.pendingAddrLoads.append(PendingAddrLoad { |
|
| 359 | + | vec::append⟨PendingAddrLoad⟩(&mut e.pendingAddrLoads, PendingAddrLoad { |
|
| 329 | 360 | index: e.codeLen, |
|
| 330 | 361 | target, |
|
| 331 | 362 | rd: rd, |
|
| 332 | 363 | isData: true, |
|
| 333 | 364 | }, e.allocator); |
| 341 | 372 | /// Called after each function. |
|
| 342 | 373 | /// |
|
| 343 | 374 | /// Uses two-instruction sequences: short branches use `branch` and `nop`, |
|
| 344 | 375 | /// long branches use inverted branch and `jal` or `auipc` and `jalr`. |
|
| 345 | 376 | export fn patchLocalBranches(e: *mut Emitter) { |
|
| 346 | - | for i in 0..e.pendingBranches.len { |
|
| 347 | - | let p = e.pendingBranches[i]; |
|
| 377 | + | let pendingBranches = vec::view⟨PendingBranch⟩(&e.pendingBranches); |
|
| 378 | + | for p in pendingBranches { |
|
| 348 | 379 | let offset = labels::branchToBlock(&e.labels, p.index, p.target, super::INSTR_SIZE); |
|
| 349 | 380 | match p.kind { |
|
| 350 | 381 | case BranchKind::Cond { op, rs1, rs2 } => { |
|
| 351 | 382 | if encode::isBranchImm(offset) { |
|
| 352 | 383 | patch(e, p.index, encodeCondBranch(op, rs1, rs2, offset)); |
| 372 | 403 | assert encode::isJumpImm(offset), "patchLocalBranches: jump offset too large"; |
|
| 373 | 404 | patch(e, p.index, encode::jal(super::ZERO, offset)); |
|
| 374 | 405 | }, |
|
| 375 | 406 | } |
|
| 376 | 407 | } |
|
| 377 | - | set e.pendingBranches = @sliceOf(e.pendingBranches.ptr, 0, e.pendingBranches.cap); |
|
| 408 | + | set e.pendingBranches.len = 0; |
|
| 378 | 409 | } |
|
| 379 | 410 | ||
| 380 | 411 | /// Encode a conditional branch instruction. |
|
| 381 | 412 | fn encodeCondBranch(op: il::CmpOp, rs1: gen::Reg, rs2: gen::Reg, offset: i32) -> u32 { |
|
| 382 | 413 | match op { |
| 398 | 429 | } |
|
| 399 | 430 | ||
| 400 | 431 | /// Patch all pending function calls. |
|
| 401 | 432 | /// Called after all functions have been generated. |
|
| 402 | 433 | export fn patchCalls(e: *mut Emitter) { |
|
| 403 | - | for i in 0..e.pendingCalls.len { |
|
| 404 | - | let p = e.pendingCalls[i]; |
|
| 434 | + | let pendingCalls = vec::view⟨PendingCall⟩(&e.pendingCalls); |
|
| 435 | + | for p in pendingCalls { |
|
| 405 | 436 | let offset = branchOffsetToFunc(e, p.index, p.target); |
|
| 406 | 437 | let s = splitImm(offset); |
|
| 407 | 438 | ||
| 408 | 439 | // `AUIPC scratch, hi(offset)`. |
|
| 409 | 440 | patch(e, p.index, encode::auipc(super::SCRATCH1, s.hi)); |
| 412 | 443 | } |
|
| 413 | 444 | } |
|
| 414 | 445 | ||
| 415 | 446 | /// Patch all pending assembly jumps. |
|
| 416 | 447 | export fn patchJumps(e: *mut Emitter) { |
|
| 417 | - | for i in 0..e.pendingJumps.len { |
|
| 418 | - | let p = e.pendingJumps[i]; |
|
| 448 | + | let pendingJumps = vec::view⟨PendingJump⟩(&e.pendingJumps); |
|
| 449 | + | for p in pendingJumps { |
|
| 419 | 450 | let offset = branchOffsetToFunc(e, p.index, p.target); |
|
| 420 | 451 | ||
| 421 | 452 | assert encode::isJumpImm(offset), "patchJumps: jump offset too large"; |
|
| 422 | 453 | patch(e, p.index, encode::jal(p.rd, offset)); |
|
| 423 | 454 | } |
|
| 424 | 455 | } |
|
| 425 | 456 | ||
| 426 | 457 | /// Patch all pending function and data address loads. |
|
| 427 | 458 | /// Called after all functions have been generated and data layout is known. |
|
| 428 | 459 | export fn patchAddrLoads(e: *mut Emitter, dataSymMap: *data::DataSymMap) { |
|
| 429 | - | for i in 0..e.pendingAddrLoads.len { |
|
| 430 | - | let p = e.pendingAddrLoads[i]; |
|
| 460 | + | let pendingAddrLoads = vec::view⟨PendingAddrLoad⟩(&e.pendingAddrLoads); |
|
| 461 | + | for p in pendingAddrLoads { |
|
| 431 | 462 | if p.isData { |
|
| 432 | 463 | let addr = data::lookupAddr(dataSymMap, p.target) else { |
|
| 433 | 464 | panic "patchAddrLoads: data symbol not found"; |
|
| 434 | 465 | }; |
|
| 435 | 466 | assert addr <= MAX_I32_ADDR, "patchAddrLoads: data address too large"; |
| 703 | 734 | ||
| 704 | 735 | ////////////////// |
|
| 705 | 736 | // Code Access // |
|
| 706 | 737 | ////////////////// |
|
| 707 | 738 | ||
| 739 | + | /// Get function start positions as an initialized slice. |
|
| 740 | + | export fn getFuncs(e: *Emitter) -> *[types::FuncAddr] { |
|
| 741 | + | return vec::view⟨types::FuncAddr⟩(&e.funcs); |
|
| 742 | + | } |
|
| 743 | + | ||
| 708 | 744 | /// Get emitted code as a slice. |
|
| 709 | 745 | export fn getCode(e: *Emitter) -> *[u32] { |
|
| 710 | 746 | return &e.code[..e.codeLen]; |
|
| 711 | 747 | } |
|
| 712 | 748 |
lib/std/arch/rv64/tests.rad
+1 -1
| 21 | 21 | @test fn testAddAssemblyExportsOnlyGlobalTextSymbols() throws (testing::TestError) { |
|
| 22 | 22 | let mut arena = alloc::new(&mut ASSEMBLY_ARENA_STORAGE[..]); |
|
| 23 | 23 | let symbols = try alloc::allocSlice(&mut arena, @sizeOf(asm::Symbol), @alignOf(asm::Symbol), 2) catch { |
|
| 24 | 24 | throw testing::TestError::Failed; |
|
| 25 | 25 | }; |
|
| 26 | - | let mut symbolSlice = @sliceOf((symbols as *mut [asm::Symbol]).ptr, 2, 2); |
|
| 26 | + | let mut symbolSlice = @sliceOf((symbols as *mut [asm::Symbol]).ptr, 2); |
|
| 27 | 27 | set symbolSlice[0] = asm::Symbol { |
|
| 28 | 28 | name: "local", |
|
| 29 | 29 | section: asm::Section::Text, |
|
| 30 | 30 | offset: 0, |
|
| 31 | 31 | isExported: false, |
lib/std/lang.rad
+2 -0
| 1 | 1 | //! Radiance language implementation. |
|
| 2 | 2 | export mod alloc; |
|
| 3 | + | export mod slice; |
|
| 4 | + | export mod vec; |
|
| 3 | 5 | export mod sexpr; |
|
| 4 | 6 | export mod types; |
|
| 5 | 7 | export mod strings; |
|
| 6 | 8 | export mod scanner; |
|
| 7 | 9 | export mod ast; |
lib/std/lang/ast.rad
+15 -8
| 1 | 1 | //! Radiance AST modules. |
|
| 2 | 2 | export mod printer; |
|
| 3 | 3 | ||
| 4 | 4 | use std::io; |
|
| 5 | 5 | use std::fmt; |
|
| 6 | + | use std::lang::vec; |
|
| 7 | + | use std::lang::slice; |
|
| 6 | 8 | use std::lang::alloc; |
|
| 7 | 9 | use std::lang::types; |
|
| 8 | 10 | ||
| 9 | 11 | /// Maximum number of trait methods. |
|
| 10 | 12 | export constant MAX_TRAIT_METHODS: u32 = 8; |
| 51 | 53 | arena: alloc::new(data), |
|
| 52 | 54 | nextId: 0, |
|
| 53 | 55 | }; |
|
| 54 | 56 | } |
|
| 55 | 57 | ||
| 56 | - | /// Create an empty `*mut [*Node]` slice with the given capacity. |
|
| 57 | - | export fn nodeSlice(arena: *mut NodeArena, capacity: u32) -> *mut [*Node] { |
|
| 58 | + | /// Create an empty node vector with arena-backed storage of the given capacity. |
|
| 59 | + | export fn nodeVec(arena: *mut NodeArena, capacity: u32) -> vec::Vec⟨*Node⟩ { |
|
| 58 | 60 | if capacity == 0 { |
|
| 59 | - | return &mut []; |
|
| 61 | + | return vec::Vec⟨*Node⟩ { data: &mut [], len: 0 }; |
|
| 60 | 62 | } |
|
| 61 | 63 | let ptr = try! alloc::allocSlice(&mut arena.arena, @sizeOf(*Node), @alignOf(*Node), capacity); |
|
| 64 | + | let data = slice::fromRawPartsMut⟨*Node⟩(ptr.ptr as *mut *Node, capacity); |
|
| 62 | 65 | ||
| 63 | - | return @sliceOf(ptr.ptr as *mut *Node, 0, capacity); |
|
| 66 | + | return vec::Vec⟨*Node⟩ { data, len: 0 }; |
|
| 64 | 67 | } |
|
| 65 | 68 | ||
| 66 | 69 | /// Attribute bit set applied to declarations or fields. |
|
| 67 | 70 | export union Attribute { |
|
| 68 | 71 | /// Public visibility attribute. |
| 165 | 168 | export union Builtin { |
|
| 166 | 169 | /// Size of type in bytes (`@sizeOf`). |
|
| 167 | 170 | SizeOf, |
|
| 168 | 171 | /// Alignment requirement of type (`@alignOf`). |
|
| 169 | 172 | AlignOf, |
|
| 170 | - | /// Construct a slice from pointer, length, and optional capacity (`@sliceOf`). |
|
| 173 | + | /// Construct a slice from a pointer and initialized length (`@sliceOf`). |
|
| 171 | 174 | SliceOf, |
|
| 175 | + | /// Move typed values between mutable pointers (`@relocate`). |
|
| 176 | + | Relocate, |
|
| 172 | 177 | } |
|
| 173 | 178 | ||
| 174 | 179 | /// Source extent for a node measured in bytes. |
|
| 175 | 180 | export record Span { |
|
| 176 | 181 | /// Byte offset from the start of the source file. |
| 893 | 898 | let fnSig = FnSig { params, returnType: nil, throwList }; |
|
| 894 | 899 | let fnBody = synthNode(arena, NodeValue::Block(Block { statements: bodyStmts })); |
|
| 895 | 900 | let fnDecl = synthNode(arena, NodeValue::FnDecl(FnDecl { |
|
| 896 | 901 | name: fnName, params: &mut [], sig: fnSig, body: fnBody, attrs: nil, |
|
| 897 | 902 | })); |
|
| 898 | - | let mut rootStmts: *mut [*Node] = &mut []; |
|
| 899 | - | rootStmts.append(fnDecl, a); |
|
| 900 | - | let modBody = synthNode(arena, NodeValue::Block(Block { statements: rootStmts })); |
|
| 903 | + | let mut rootStmts = nodeVec(arena, 1); |
|
| 904 | + | vec::append⟨*Node⟩(&mut rootStmts, fnDecl, a); |
|
| 905 | + | let statements = vec::viewMut⟨*Node⟩(&mut rootStmts); |
|
| 906 | + | let modBody = synthNode(arena, NodeValue::Block(Block { statements })); |
|
| 901 | 907 | ||
| 902 | 908 | return SynthFnMod { modBody, fnBody }; |
|
| 903 | 909 | } |
|
| 910 | + |
lib/std/lang/ast/printer.rad
+1 -0
| 43 | 43 | fn builtinName(kind: super::Builtin) -> *[u8] { |
|
| 44 | 44 | match kind { |
|
| 45 | 45 | case super::Builtin::SizeOf => return "@sizeOf", |
|
| 46 | 46 | case super::Builtin::AlignOf => return "@alignOf", |
|
| 47 | 47 | case super::Builtin::SliceOf => return "@sliceOf", |
|
| 48 | + | case super::Builtin::Relocate => return "@relocate", |
|
| 48 | 49 | } |
|
| 49 | 50 | } |
|
| 50 | 51 | ||
| 51 | 52 | /// Return the name for an integer type. |
|
| 52 | 53 | fn intTypeName(width: u8, sign: super::Signedness) -> *[u8] { |
lib/std/lang/lower.rad
+337 -329
| 97 | 97 | use std::mem; |
|
| 98 | 98 | use std::lang::ast; |
|
| 99 | 99 | use std::lang::il; |
|
| 100 | 100 | use std::lang::module; |
|
| 101 | 101 | use std::lang::resolver; |
|
| 102 | + | use std::lang::vec; |
|
| 103 | + | ||
| 104 | + | instantiate vec::append⟨ErrTagEntry⟩, |
|
| 105 | + | vec::append⟨*il::Fn⟩, |
|
| 106 | + | vec::append⟨il::DataValue⟩, |
|
| 107 | + | vec::append⟨u8⟩, |
|
| 108 | + | vec::append⟨FnSymEntry⟩, |
|
| 109 | + | vec::append⟨DataSymEntry⟩, |
|
| 110 | + | vec::append⟨il::Data⟩, |
|
| 111 | + | vec::append⟨BlockData⟩, |
|
| 112 | + | vec::append⟨il::Param⟩, |
|
| 113 | + | vec::append⟨il::SrcLoc⟩, |
|
| 114 | + | vec::append⟨il::Instr⟩, |
|
| 115 | + | vec::append⟨u32⟩, |
|
| 116 | + | vec::append⟨VarData⟩, |
|
| 117 | + | vec::append⟨FnParamBinding⟩, |
|
| 118 | + | vec::append⟨il::SwitchCase⟩, |
|
| 119 | + | vec::view⟨ErrTagEntry⟩, |
|
| 120 | + | vec::view⟨il::DataValue⟩, |
|
| 121 | + | vec::view⟨*il::Fn⟩, |
|
| 122 | + | vec::view⟨il::Data⟩, |
|
| 123 | + | vec::view⟨u8⟩, |
|
| 124 | + | vec::view⟨FnSymEntry⟩, |
|
| 125 | + | vec::view⟨resolver::TraitMethod⟩, |
|
| 126 | + | vec::view⟨u32⟩, |
|
| 127 | + | vec::view⟨il::Param⟩, |
|
| 128 | + | vec::view⟨il::SrcLoc⟩, |
|
| 129 | + | vec::view⟨FnParamBinding⟩, |
|
| 130 | + | vec::viewMut⟨il::Instr⟩, |
|
| 131 | + | vec::viewMut⟨il::SwitchCase⟩; |
|
| 102 | 132 | ||
| 103 | 133 | // TODO: Search for all `_ as i32` to ensure that casts from u32 to i32 don't |
|
| 104 | 134 | // happen, since they are potentially truncating values. |
|
| 105 | 135 | ||
| 106 | 136 | // TODO: Support constant union lowering. |
| 169 | 199 | } |
|
| 170 | 200 | ||
| 171 | 201 | /// Incrementally build deterministic internal symbol names. |
|
| 172 | 202 | record NameBuilder { |
|
| 173 | 203 | /// Accumulated name bytes. |
|
| 174 | - | bytes: *mut [u8], |
|
| 204 | + | bytes: vec::Vec⟨u8⟩, |
|
| 175 | 205 | /// Allocator used to grow the name. |
|
| 176 | 206 | allocator: alloc::Allocator, |
|
| 177 | 207 | } |
|
| 178 | 208 | ||
| 179 | 209 | /// Print a LowerError for debugging. |
| 217 | 247 | /// Maximum number of `catch` clauses per `try`. |
|
| 218 | 248 | constant MAX_CATCH_CLAUSES: u32 = 32; |
|
| 219 | 249 | ||
| 220 | 250 | // Slice Layout |
|
| 221 | 251 | // |
|
| 222 | - | // A slice is a fat pointer consisting of a data pointer, a length and a capacity. |
|
| 223 | - | // `{ ptr: u32, len: u32, cap: u32 }`. |
|
| 252 | + | // A slice is a 16-byte fat pointer consisting of a data pointer, a length and |
|
| 253 | + | // four bytes of padding. `{ ptr: u64, len: u32, padding: u32 }`. |
|
| 224 | 254 | ||
| 225 | 255 | /// Slice data pointer offset. |
|
| 226 | 256 | constant SLICE_PTR_OFFSET: i32 = 0; |
|
| 227 | 257 | /// Offset of slice length in slice data structure. |
|
| 228 | 258 | constant SLICE_LEN_OFFSET: i32 = resolver::PTR_SIZE as i32; |
|
| 229 | - | /// Offset of slice capacity in slice data structure. |
|
| 230 | - | constant SLICE_CAP_OFFSET: i32 = resolver::PTR_SIZE as i32 + 4; |
|
| 231 | 259 | ||
| 232 | 260 | // Trait Object Layout |
|
| 233 | 261 | // |
|
| 234 | 262 | // A trait object is a fat pointer consisting of a data pointer and a |
|
| 235 | 263 | // v-table pointer. `{ data: *T, vtable: *VTable }`. |
| 283 | 311 | emitFn: fn(*mut opaque, *il::Fn, FnRole), |
|
| 284 | 312 | } |
|
| 285 | 313 | ||
| 286 | 314 | /// Destination for functions produced by the lowerer. |
|
| 287 | 315 | export union FnOutput { |
|
| 288 | - | /// Store lowered functions in the provided slice. |
|
| 289 | - | Accumulate(*mut [*il::Fn]), |
|
| 316 | + | /// Accumulate lowered functions in arena-backed vector storage. |
|
| 317 | + | Accumulate(vec::Vec⟨*il::Fn⟩), |
|
| 290 | 318 | /// Send lowered functions to an external consumer immediately. |
|
| 291 | 319 | Stream(FnSink), |
|
| 292 | 320 | } |
|
| 293 | 321 | ||
| 294 | 322 | /// Module-level lowering context shared across all function lowerings. |
| 304 | 332 | allocator: alloc::Allocator, |
|
| 305 | 333 | /// Fully resolved semantic metadata queried without mutation. |
|
| 306 | 334 | resolver: *resolver::Resolver, |
|
| 307 | 335 | /// Module graph for cross-module symbol resolution. |
|
| 308 | 336 | moduleGraph: ?*module::ModuleGraph, |
|
| 309 | - | /// Package name for qualified symbol names. |
|
| 337 | + | /// Fallback package name for declarations without a module path. |
|
| 310 | 338 | pkgName: *[u8], |
|
| 311 | 339 | /// Current module being lowered. |
|
| 312 | 340 | currentMod: ?u16, |
|
| 313 | 341 | /// Rigid-to-concrete mapping for the function currently being lowered. |
|
| 314 | 342 | specialization: ?*resolver::Substitution, |
|
| 315 | 343 | /// Concrete generic function whose body is currently being lowered. |
|
| 316 | 344 | genericSpecialization: ?*resolver::GenericFnSpecialization, |
|
| 317 | 345 | /// Global data items (string literals, constants, static arrays). |
|
| 318 | 346 | /// These become the data sections in the final binary. |
|
| 319 | - | data: *mut [il::Data], |
|
| 347 | + | data: vec::Vec⟨il::Data⟩, |
|
| 320 | 348 | /// Destination for lowered functions. |
|
| 321 | 349 | output: FnOutput, |
|
| 322 | 350 | /// Map of function symbols to qualified names. |
|
| 323 | - | fnSyms: *mut [FnSymEntry], |
|
| 351 | + | fnSyms: vec::Vec⟨FnSymEntry⟩, |
|
| 324 | 352 | /// Global error tag table keyed by persistent concrete types. |
|
| 325 | - | errTags: *mut [ErrTagEntry], |
|
| 353 | + | errTags: vec::Vec⟨ErrTagEntry⟩, |
|
| 326 | 354 | /// Next error tag to assign (starts at 1; 0 = success). |
|
| 327 | 355 | errTagCounter: u32, |
|
| 328 | 356 | /// Lowering options. |
|
| 329 | 357 | options: LowerOptions, |
|
| 330 | 358 | } |
| 367 | 395 | fn getOrAssignErrorTag( |
|
| 368 | 396 | self: *mut Lowerer, |
|
| 369 | 397 | errType: resolver::Type, |
|
| 370 | 398 | ) -> u32 { |
|
| 371 | 399 | assert not resolver::containsGenericParameter(errType); |
|
| 372 | - | for entry in self.errTags { |
|
| 400 | + | for entry in vec::view⟨ErrTagEntry⟩(&self.errTags) { |
|
| 373 | 401 | if resolver::typesEqual(entry.ty, errType) { |
|
| 374 | 402 | return entry.tag; |
|
| 375 | 403 | } |
|
| 376 | 404 | } |
|
| 377 | 405 | let tag = self.errTagCounter; |
|
| 378 | 406 | set self.errTagCounter += 1; |
|
| 379 | - | self.errTags.append(ErrTagEntry { |
|
| 407 | + | vec::append⟨ErrTagEntry⟩(&mut self.errTags, ErrTagEntry { |
|
| 380 | 408 | ty: resolver::copyStructuralTypeToArena(errType, self.arena), |
|
| 381 | 409 | tag, |
|
| 382 | 410 | }, self.allocator); |
|
| 383 | 411 | return tag; |
|
| 384 | 412 | } |
| 386 | 414 | /// Emit one function to the active output. |
|
| 387 | 415 | fn emitFunction(self: *mut Lowerer, func: *il::Fn, role: FnRole) { |
|
| 388 | 416 | match self.output { |
|
| 389 | 417 | case FnOutput::Accumulate(accumulated) => { |
|
| 390 | 418 | let mut fns = accumulated; |
|
| 391 | - | fns.append(func, self.allocator); |
|
| 419 | + | vec::append⟨*il::Fn⟩(&mut fns, func, self.allocator); |
|
| 392 | 420 | set self.output = FnOutput::Accumulate(fns); |
|
| 393 | 421 | } |
|
| 394 | 422 | case FnOutput::Stream(sink) => { |
|
| 395 | 423 | sink.emitFn(sink.ctx, func, role); |
|
| 396 | 424 | } |
| 405 | 433 | return FnRole::Normal; |
|
| 406 | 434 | } |
|
| 407 | 435 | ||
| 408 | 436 | /// Builder for accumulating data values during constant lowering. |
|
| 409 | 437 | record DataValueBuilder { |
|
| 438 | + | /// Allocator used to grow the value storage. |
|
| 410 | 439 | allocator: alloc::Allocator, |
|
| 411 | - | values: *mut [il::DataValue], |
|
| 440 | + | /// Values accumulated in initialization order. |
|
| 441 | + | values: vec::Vec⟨il::DataValue⟩, |
|
| 412 | 442 | /// Whether all pushed values can be represented by zero-filled memory. |
|
| 413 | 443 | zeroInit: bool, |
|
| 414 | 444 | } |
|
| 415 | 445 | ||
| 416 | 446 | /// Result of lowering constant data. |
| 419 | 449 | zeroInit: bool, |
|
| 420 | 450 | } |
|
| 421 | 451 | ||
| 422 | 452 | /// Create a new builder. |
|
| 423 | 453 | fn dataBuilder(allocator: alloc::Allocator) -> DataValueBuilder { |
|
| 424 | - | return DataValueBuilder { allocator, values: &mut [], zeroInit: true }; |
|
| 454 | + | return DataValueBuilder { |
|
| 455 | + | allocator, |
|
| 456 | + | values: vec::Vec⟨il::DataValue⟩ { data: &mut [], len: 0 }, |
|
| 457 | + | zeroInit: true, |
|
| 458 | + | }; |
|
| 425 | 459 | } |
|
| 426 | 460 | ||
| 427 | 461 | /// Return whether a data item can be omitted from a zero-filled image. |
|
| 428 | 462 | fn dataIsZero(item: il::DataItem) -> bool { |
|
| 429 | 463 | match item { |
| 443 | 477 | return true; |
|
| 444 | 478 | } |
|
| 445 | 479 | ||
| 446 | 480 | /// Append a data value to the builder. |
|
| 447 | 481 | fn dataBuilderPush(b: *mut DataValueBuilder, value: il::DataValue) { |
|
| 448 | - | b.values.append(value, b.allocator); |
|
| 482 | + | vec::append⟨il::DataValue⟩(&mut b.values, value, b.allocator); |
|
| 449 | 483 | ||
| 450 | 484 | if value.count > 0 and not dataIsZero(value.item) { |
|
| 451 | 485 | set b.zeroInit = false; |
|
| 452 | 486 | } |
|
| 453 | 487 | } |
|
| 454 | 488 | ||
| 455 | 489 | /// Return the accumulated values. |
|
| 456 | 490 | fn dataBuilderFinish(b: *DataValueBuilder) -> ConstDataResult { |
|
| 457 | 491 | return ConstDataResult { |
|
| 458 | - | values: &b.values[..], |
|
| 492 | + | values: vec::view⟨il::DataValue⟩(&b.values), |
|
| 459 | 493 | zeroInit: b.zeroInit, |
|
| 460 | 494 | }; |
|
| 461 | 495 | } |
|
| 462 | 496 | ||
| 463 | 497 | /////////////////////////// |
| 532 | 566 | record BlockData { |
|
| 533 | 567 | /// Block label for debugging and IL printing. |
|
| 534 | 568 | label: *[u8], |
|
| 535 | 569 | /// Block parameters for merging values at control flow joins. These |
|
| 536 | 570 | /// receive values from predecessor edges when control flow merges. |
|
| 537 | - | params: *mut [il::Param], |
|
| 571 | + | params: vec::Vec⟨il::Param⟩, |
|
| 538 | 572 | /// Variable ids corresponding to each parameter. Used to map block params |
|
| 539 | 573 | /// back to source variables when building argument lists for jumps. |
|
| 540 | - | paramVars: *mut [u32], |
|
| 574 | + | paramVars: vec::Vec⟨u32⟩, |
|
| 541 | 575 | /// Instructions accumulated so far. The last instruction should eventually |
|
| 542 | 576 | /// be a terminator. |
|
| 543 | - | instrs: *mut [il::Instr], |
|
| 577 | + | instrs: vec::Vec⟨il::Instr⟩, |
|
| 544 | 578 | /// Debug source locations, one per instruction. Only populated when |
|
| 545 | 579 | /// debug info is enabled. |
|
| 546 | - | locs: *mut [il::SrcLoc], |
|
| 580 | + | locs: vec::Vec⟨il::SrcLoc⟩, |
|
| 547 | 581 | /// Predecessor block ids. Used for SSA construction to propagate values |
|
| 548 | 582 | /// from predecessors when a variable is used before being defined locally. |
|
| 549 | - | preds: *mut [u32], |
|
| 583 | + | preds: vec::Vec⟨u32⟩, |
|
| 550 | 584 | /// The current SSA value of each variable in this block. Indexed by variable |
|
| 551 | 585 | /// id. A `nil` means the variable wasn't assigned in this block. Updated by |
|
| 552 | 586 | /// [`defVar`], queried by [`useVarInBlock`]. |
|
| 553 | 587 | vars: *mut [?il::Val], |
|
| 554 | 588 | /// Sealing state. Once sealed, all predecessors are known and we can resolve |
| 564 | 598 | /// During this time, variables used before being defined locally are tracked. |
|
| 565 | 599 | /// Once all predecessors are known, the block is sealed and those variables |
|
| 566 | 600 | /// are resolved via [`resolveBlockArgs`]. |
|
| 567 | 601 | union Sealed { |
|
| 568 | 602 | /// Block is unsealed; predecessors may still be added. |
|
| 569 | - | No { incompleteVars: *mut [u32] }, |
|
| 603 | + | No { |
|
| 604 | + | /// Variables whose block parameters must be resolved when sealed. |
|
| 605 | + | incompleteVars: vec::Vec⟨u32⟩, |
|
| 606 | + | }, |
|
| 570 | 607 | /// Block is sealed; all predecessors are known. |
|
| 571 | 608 | Yes, |
|
| 572 | 609 | } |
|
| 573 | 610 | ||
| 574 | 611 | /////////////////////////////////// |
| 707 | 744 | /// Type signature of the function being lowered. |
|
| 708 | 745 | fnType: *resolver::FnType, |
|
| 709 | 746 | /// Function name, used as prefix for generated data symbols. |
|
| 710 | 747 | fnName: *[u8], |
|
| 711 | 748 | /// Names assigned to data declarations in this function. |
|
| 712 | - | dataSyms: *mut [DataSymEntry], |
|
| 749 | + | dataSyms: vec::Vec⟨DataSymEntry⟩, |
|
| 713 | 750 | ||
| 714 | 751 | // ~ SSA variable tracking ~ // |
|
| 715 | 752 | ||
| 716 | 753 | /// Metadata (name, type, mutability) for each variable. Indexed by variable |
|
| 717 | 754 | /// id. Doesn't change after declaration. For the SSA value of a variable in |
|
| 718 | 755 | /// a specific block, see [`BlockData::vars`]. |
|
| 719 | - | vars: *mut [VarData], |
|
| 756 | + | vars: vec::Vec⟨VarData⟩, |
|
| 720 | 757 | /// Parameter-to-variable bindings, initialized in the entry block. |
|
| 721 | - | params: *mut [FnParamBinding], |
|
| 758 | + | params: vec::Vec⟨FnParamBinding⟩, |
|
| 722 | 759 | ||
| 723 | 760 | // ~ Basic block management ~ // |
|
| 724 | 761 | ||
| 725 | 762 | /// Block storage array, indexed by block id. |
|
| 726 | - | blockData: *mut [BlockData], |
|
| 763 | + | blockData: vec::Vec⟨BlockData⟩, |
|
| 727 | 764 | /// The entry block for this function. |
|
| 728 | 765 | entryBlock: ?BlockId, |
|
| 729 | 766 | /// The block currently receiving new instructions. |
|
| 730 | 767 | currentBlock: ?BlockId, |
|
| 731 | 768 |
| 781 | 818 | moduleGraph: nil, |
|
| 782 | 819 | pkgName, |
|
| 783 | 820 | currentMod: nil, |
|
| 784 | 821 | specialization: nil, |
|
| 785 | 822 | genericSpecialization: nil, |
|
| 786 | - | data: &mut [], |
|
| 787 | - | output: FnOutput::Accumulate(&mut []), |
|
| 788 | - | fnSyms: &mut [], |
|
| 789 | - | errTags: &mut [], |
|
| 823 | + | data: vec::Vec⟨il::Data⟩ { data: &mut [], len: 0 }, |
|
| 824 | + | output: FnOutput::Accumulate(vec::Vec⟨*il::Fn⟩ { data: &mut [], len: 0 }), |
|
| 825 | + | fnSyms: vec::Vec⟨FnSymEntry⟩ { data: &mut [], len: 0 }, |
|
| 826 | + | errTags: vec::Vec⟨ErrTagEntry⟩ { data: &mut [], len: 0 }, |
|
| 790 | 827 | errTagCounter: 1, |
|
| 791 | 828 | options: LowerOptions { debug: false, buildTest: false }, |
|
| 792 | 829 | }; |
|
| 793 | 830 | try lowerDecls(&mut low, root, true); |
|
| 794 | 831 |
| 816 | 853 | moduleGraph: graph, |
|
| 817 | 854 | pkgName, |
|
| 818 | 855 | currentMod: nil, |
|
| 819 | 856 | specialization: nil, |
|
| 820 | 857 | genericSpecialization: nil, |
|
| 821 | - | data: &mut [], |
|
| 822 | - | output: FnOutput::Accumulate(&mut []), |
|
| 823 | - | fnSyms: &mut [], |
|
| 824 | - | errTags: &mut [], |
|
| 858 | + | data: vec::Vec⟨il::Data⟩ { data: &mut [], len: 0 }, |
|
| 859 | + | output: FnOutput::Accumulate(vec::Vec⟨*il::Fn⟩ { data: &mut [], len: 0 }), |
|
| 860 | + | fnSyms: vec::Vec⟨FnSymEntry⟩ { data: &mut [], len: 0 }, |
|
| 861 | + | errTags: vec::Vec⟨ErrTagEntry⟩ { data: &mut [], len: 0 }, |
|
| 825 | 862 | errTagCounter: 1, |
|
| 826 | 863 | options, |
|
| 827 | 864 | }; |
|
| 828 | 865 | } |
|
| 829 | 866 |
| 926 | 963 | } |
|
| 927 | 964 | } |
|
| 928 | 965 | ||
| 929 | 966 | /// Finalize lowering and return the unified IL program. |
|
| 930 | 967 | export fn finalize(low: *Lowerer) -> il::Program { |
|
| 931 | - | let mut fns: *mut [*il::Fn] = undefined; |
|
| 968 | + | let mut fns: *[*il::Fn] = &[]; |
|
| 932 | 969 | match low.output { |
|
| 933 | - | case FnOutput::Accumulate(accumulated) => { |
|
| 934 | - | set fns = accumulated; |
|
| 935 | - | } |
|
| 936 | - | case FnOutput::Stream(_) => { |
|
| 937 | - | panic "finalize: cannot finalize streaming lowerer"; |
|
| 938 | - | } |
|
| 970 | + | case FnOutput::Accumulate(accumulated) => |
|
| 971 | + | set fns = vec::view⟨*il::Fn⟩(&accumulated), |
|
| 972 | + | case FnOutput::Stream(_) => |
|
| 973 | + | panic "finalize: cannot finalize streaming lowerer", |
|
| 939 | 974 | } |
|
| 940 | 975 | return il::Program { |
|
| 941 | - | data: &low.data[..], |
|
| 942 | - | fns: &fns[..], |
|
| 976 | + | data: vec::view⟨il::Data⟩(&low.data), |
|
| 977 | + | fns, |
|
| 943 | 978 | }; |
|
| 944 | 979 | } |
|
| 945 | 980 | ||
| 946 | 981 | ///////////////////////////////// |
|
| 947 | 982 | // Qualified Name Construction // |
| 977 | 1012 | } |
|
| 978 | 1013 | ||
| 979 | 1014 | /// Append bytes to a symbol name. |
|
| 980 | 1015 | fn namePush(builder: *mut NameBuilder, text: *[u8]) { |
|
| 981 | 1016 | for byte in text { |
|
| 982 | - | builder.bytes.append(byte, builder.allocator); |
|
| 1017 | + | vec::append⟨u8⟩(&mut builder.bytes, byte, builder.allocator); |
|
| 983 | 1018 | } |
|
| 984 | 1019 | } |
|
| 985 | 1020 | ||
| 986 | 1021 | /// Append a decimal `u32` to a symbol name. |
|
| 987 | 1022 | fn namePushU32(builder: *mut NameBuilder, value: u32) { |
| 993 | 1028 | fn namePushU64(builder: *mut NameBuilder, value: u64) { |
|
| 994 | 1029 | let mut digits: [u8; 20] = undefined; |
|
| 995 | 1030 | namePush(builder, fmt::formatU64(value, &mut digits[..])); |
|
| 996 | 1031 | } |
|
| 997 | 1032 | ||
| 998 | - | /// Append the stable, source-qualified name of a module-level declaration. |
|
| 1033 | + | /// Append the canonical source-qualified name of a module-level declaration. |
|
| 1034 | + | /// Non-empty module paths already begin with the defining package. |
|
| 999 | 1035 | fn namePushQualified( |
|
| 1000 | 1036 | self: *mut Lowerer, |
|
| 1001 | 1037 | builder: *mut NameBuilder, |
|
| 1002 | 1038 | modId: ?u16, |
|
| 1003 | 1039 | name: *[u8], |
|
| 1004 | 1040 | ) { |
|
| 1005 | 1041 | let path = getModulePath(self, modId); |
|
| 1006 | - | if path.len == 0 or path[0] <> self.pkgName { |
|
| 1042 | + | if path.len == 0 { |
|
| 1007 | 1043 | namePush(builder, self.pkgName); |
|
| 1008 | 1044 | namePush(builder, "::"); |
|
| 1009 | 1045 | } |
|
| 1010 | 1046 | for segment in path { |
|
| 1011 | 1047 | namePush(builder, segment); |
| 1064 | 1100 | } |
|
| 1065 | 1101 | case resolver::Type::Array(array) => { |
|
| 1066 | 1102 | namePush(builder, "["); |
|
| 1067 | 1103 | namePushType(self, builder, *array.item); |
|
| 1068 | 1104 | namePush(builder, "; "); |
|
| 1069 | - | namePushU32(builder, array.length); |
|
| 1105 | + | namePushType(self, builder, *array.length); |
|
| 1070 | 1106 | namePush(builder, "]"); |
|
| 1071 | 1107 | } |
|
| 1072 | 1108 | case resolver::Type::ConstArgument { value, .. } => { |
|
| 1073 | 1109 | if value.negative { namePush(builder, "-"); } |
|
| 1074 | 1110 | namePushU64(builder, value.magnitude); |
| 1150 | 1186 | fn specializationName( |
|
| 1151 | 1187 | self: *mut Lowerer, |
|
| 1152 | 1188 | specialization: *resolver::GenericFnSpecialization, |
|
| 1153 | 1189 | ) -> *[u8] { |
|
| 1154 | 1190 | let template = specialization.template; |
|
| 1155 | - | let mut builder = NameBuilder { bytes: &mut [], allocator: self.allocator }; |
|
| 1191 | + | let mut builder = NameBuilder { |
|
| 1192 | + | bytes: vec::Vec⟨u8⟩ { data: &mut [], len: 0 }, |
|
| 1193 | + | allocator: self.allocator, |
|
| 1194 | + | }; |
|
| 1156 | 1195 | namePushQualified(self, &mut builder, template.moduleId, template.name); |
|
| 1157 | 1196 | namePush(&mut builder, "⟨"); |
|
| 1158 | 1197 | for arg, i in specialization.args { |
|
| 1159 | 1198 | if i > 0 { namePush(&mut builder, ", "); } |
|
| 1160 | 1199 | namePushType(self, &mut builder, *arg); |
|
| 1161 | 1200 | } |
|
| 1162 | 1201 | namePush(&mut builder, "⟩"); |
|
| 1163 | - | return &builder.bytes[..]; |
|
| 1202 | + | return vec::view⟨u8⟩(&builder.bytes); |
|
| 1164 | 1203 | } |
|
| 1165 | 1204 | ||
| 1166 | 1205 | /// Register a function symbol with its qualified name. |
|
| 1167 | 1206 | /// Called when lowering function declarations, so cross-package calls can find |
|
| 1168 | 1207 | /// the function by name. |
|
| 1169 | 1208 | fn registerFnSym(self: *mut Lowerer, sym: *resolver::Symbol, qualName: *[u8]) { |
|
| 1170 | - | self.fnSyms.append(FnSymEntry { sym, qualName }, self.allocator); |
|
| 1209 | + | vec::append⟨FnSymEntry⟩( |
|
| 1210 | + | &mut self.fnSyms, |
|
| 1211 | + | FnSymEntry { sym, qualName }, |
|
| 1212 | + | self.allocator, |
|
| 1213 | + | ); |
|
| 1171 | 1214 | } |
|
| 1172 | 1215 | ||
| 1173 | 1216 | /// Look up a function's qualified name by its symbol. |
|
| 1174 | 1217 | /// Returns `nil` if the symbol wasn't registered (e.g. callee's module is not yet lowered). |
|
| 1175 | 1218 | // TODO: This is kind of dubious as an optimization, if it depends on the order |
|
| 1176 | 1219 | // in which modules are lowered. |
|
| 1177 | 1220 | // TODO: Use a hash table here? |
|
| 1178 | 1221 | fn lookupFnSym(self: *Lowerer, sym: *resolver::Symbol) -> ?*[u8] { |
|
| 1179 | - | for entry in self.fnSyms { |
|
| 1222 | + | for entry in vec::view⟨FnSymEntry⟩(&self.fnSyms) { |
|
| 1180 | 1223 | if entry.sym == sym { |
|
| 1181 | 1224 | return entry.qualName; |
|
| 1182 | 1225 | } |
|
| 1183 | 1226 | } |
|
| 1184 | 1227 | return nil; |
| 1188 | 1231 | fn registerDataSym( |
|
| 1189 | 1232 | self: *mut FnLowerer, |
|
| 1190 | 1233 | sym: *resolver::Symbol, |
|
| 1191 | 1234 | qualName: *[u8], |
|
| 1192 | 1235 | ) { |
|
| 1193 | - | self.dataSyms.append(DataSymEntry { sym, qualName }, self.allocator); |
|
| 1236 | + | vec::append⟨DataSymEntry⟩( |
|
| 1237 | + | &mut self.dataSyms, |
|
| 1238 | + | DataSymEntry { sym, qualName }, |
|
| 1239 | + | self.allocator, |
|
| 1240 | + | ); |
|
| 1194 | 1241 | } |
|
| 1195 | 1242 | ||
| 1196 | 1243 | /// Look up the current function's most recently registered local data name. |
|
| 1197 | 1244 | fn lookupDataSym(self: *FnLowerer, sym: *resolver::Symbol) -> ?*[u8] { |
|
| 1198 | 1245 | let mut i = self.dataSyms.len; |
|
| 1199 | 1246 | while i > 0 { |
|
| 1200 | 1247 | set i -= 1; |
|
| 1201 | - | let entry = &self.dataSyms[i]; |
|
| 1248 | + | let entry = &self.dataSyms.data[i]; |
|
| 1202 | 1249 | if entry.sym == sym { |
|
| 1203 | 1250 | return entry.qualName; |
|
| 1204 | 1251 | } |
|
| 1205 | 1252 | } |
|
| 1206 | 1253 | return nil; |
| 1226 | 1273 | let mut fnLow = FnLowerer { |
|
| 1227 | 1274 | low: self, |
|
| 1228 | 1275 | allocator: alloc::arenaAllocator(self.fnArena), |
|
| 1229 | 1276 | fnType: fnType, |
|
| 1230 | 1277 | fnName: qualName, |
|
| 1231 | - | dataSyms: &mut [], |
|
| 1232 | - | vars: &mut [], |
|
| 1233 | - | params: &mut [], |
|
| 1234 | - | blockData: &mut [], |
|
| 1278 | + | dataSyms: vec::Vec⟨DataSymEntry⟩ { data: &mut [], len: 0 }, |
|
| 1279 | + | vars: vec::Vec⟨VarData⟩ { data: &mut [], len: 0 }, |
|
| 1280 | + | params: vec::Vec⟨FnParamBinding⟩ { data: &mut [], len: 0 }, |
|
| 1281 | + | blockData: vec::Vec⟨BlockData⟩ { data: &mut [], len: 0 }, |
|
| 1235 | 1282 | entryBlock: nil, |
|
| 1236 | 1283 | currentBlock: nil, |
|
| 1237 | 1284 | loopStack, |
|
| 1238 | 1285 | loopDepth: 0, |
|
| 1239 | 1286 | labelCounter: 0, |
| 1331 | 1378 | self: *mut Lowerer, |
|
| 1332 | 1379 | concreteType: resolver::Type, |
|
| 1333 | 1380 | traitInfo: ?*resolver::TraitType, |
|
| 1334 | 1381 | methodName: *[u8], |
|
| 1335 | 1382 | ) -> *[u8] { |
|
| 1336 | - | let mut builder = NameBuilder { bytes: &mut [], allocator: self.allocator }; |
|
| 1383 | + | let mut builder = NameBuilder { |
|
| 1384 | + | bytes: vec::Vec⟨u8⟩ { data: &mut [], len: 0 }, |
|
| 1385 | + | allocator: self.allocator, |
|
| 1386 | + | }; |
|
| 1337 | 1387 | namePushType(self, &mut builder, concreteType); |
|
| 1338 | 1388 | if let traitValue = traitInfo { |
|
| 1339 | 1389 | namePush(&mut builder, " "); |
|
| 1340 | 1390 | namePushTrait(self, &mut builder, traitValue); |
|
| 1341 | 1391 | } |
|
| 1342 | 1392 | namePush(&mut builder, "::"); |
|
| 1343 | 1393 | namePush(&mut builder, methodName); |
|
| 1344 | - | return &builder.bytes[..]; |
|
| 1394 | + | return vec::view⟨u8⟩(&builder.bytes); |
|
| 1345 | 1395 | } |
|
| 1346 | 1396 | ||
| 1347 | 1397 | /// Build a readable v-table name from its concrete type and trait. |
|
| 1348 | 1398 | fn vtableName( |
|
| 1349 | 1399 | self: *mut Lowerer, |
|
| 1350 | 1400 | concreteType: resolver::Type, |
|
| 1351 | 1401 | traitInfo: *resolver::TraitType, |
|
| 1352 | 1402 | ) -> *[u8] { |
|
| 1353 | - | let mut builder = NameBuilder { bytes: &mut [], allocator: self.allocator }; |
|
| 1403 | + | let mut builder = NameBuilder { |
|
| 1404 | + | bytes: vec::Vec⟨u8⟩ { data: &mut [], len: 0 }, |
|
| 1405 | + | allocator: self.allocator, |
|
| 1406 | + | }; |
|
| 1354 | 1407 | namePush(&mut builder, "vtable::"); |
|
| 1355 | 1408 | namePushType(self, &mut builder, concreteType); |
|
| 1356 | 1409 | namePush(&mut builder, " "); |
|
| 1357 | 1410 | namePushTrait(self, &mut builder, traitInfo); |
|
| 1358 | - | return &builder.bytes[..]; |
|
| 1411 | + | return vec::view⟨u8⟩(&builder.bytes); |
|
| 1359 | 1412 | } |
|
| 1360 | 1413 | ||
| 1361 | 1414 | /// Lower an instance declaration (`instance Trait for Type { ... }`). |
|
| 1362 | 1415 | /// |
|
| 1363 | 1416 | /// Each method in the instance block is lowered as a standalone function |
| 1410 | 1463 | set methodNameSet[method.index] = true; |
|
| 1411 | 1464 | } |
|
| 1412 | 1465 | ||
| 1413 | 1466 | // Fill inherited method slots from their declaring supertraits. Their |
|
| 1414 | 1467 | // declaring-trait identity selects the already lowered implementation. |
|
| 1415 | - | for method, i in traitInfo.methods { |
|
| 1468 | + | for method, i in vec::view⟨resolver::TraitMethod⟩(&traitInfo.methods) { |
|
| 1416 | 1469 | if not methodNameSet[i] { |
|
| 1417 | 1470 | let inheritedInst = resolver::findInstance( |
|
| 1418 | 1471 | self.resolver, method.owner, instEntry.concreteType |
|
| 1419 | 1472 | ) else throw LowerError::MissingMetadata; |
|
| 1420 | 1473 | set methodNames[i] = instanceMethodName( |
| 1436 | 1489 | set values[i] = il::DataValue { |
|
| 1437 | 1490 | item: il::DataItem::Fn(methodNames[i]), |
|
| 1438 | 1491 | count: 1, |
|
| 1439 | 1492 | }; |
|
| 1440 | 1493 | } |
|
| 1441 | - | self.data.append(il::Data { |
|
| 1494 | + | vec::append⟨il::Data⟩(&mut self.data, il::Data { |
|
| 1442 | 1495 | name: vName, |
|
| 1443 | 1496 | size: traitInfo.methods.len as u32 * resolver::PTR_SIZE, |
|
| 1444 | 1497 | alignment: resolver::PTR_SIZE, |
|
| 1445 | 1498 | readOnly: true, |
|
| 1446 | 1499 | isZeroInit: false, |
| 1652 | 1705 | } |
|
| 1653 | 1706 | let mut b = dataBuilder(self.allocator); |
|
| 1654 | 1707 | try lowerConstDataInto(self, value, data.ty, layout.size, qualName, &mut b); |
|
| 1655 | 1708 | let result = dataBuilderFinish(&b); |
|
| 1656 | 1709 | ||
| 1657 | - | self.data.append(il::Data { |
|
| 1710 | + | vec::append⟨il::Data⟩(&mut self.data, il::Data { |
|
| 1658 | 1711 | name: qualName, |
|
| 1659 | 1712 | size: layout.size, |
|
| 1660 | 1713 | alignment: layout.alignment, |
|
| 1661 | 1714 | readOnly, |
|
| 1662 | 1715 | isZeroInit: not readOnly and result.zeroInit, |
|
| 1663 | 1716 | values: result.values, |
|
| 1664 | 1717 | }, self.allocator); |
|
| 1665 | 1718 | } |
|
| 1666 | 1719 | ||
| 1667 | - | /// Emit the in-memory representation of a slice header: `{ ptr, len, cap }`. |
|
| 1720 | + | /// Emit a 16-byte slice header containing a pointer, length, and padding. |
|
| 1668 | 1721 | fn dataSliceHeader(b: *mut DataValueBuilder, dataSym: *[u8], len: u32) { |
|
| 1669 | 1722 | dataBuilderPush(b, il::DataValue { |
|
| 1670 | 1723 | item: il::DataItem::Sym(dataSym), |
|
| 1671 | 1724 | count: 1 |
|
| 1672 | 1725 | }); |
| 1676 | 1729 | val: len as i64 |
|
| 1677 | 1730 | }, |
|
| 1678 | 1731 | count: 1 |
|
| 1679 | 1732 | }); |
|
| 1680 | 1733 | dataBuilderPush(b, il::DataValue { |
|
| 1681 | - | item: il::DataItem::Val { |
|
| 1682 | - | typ: il::Type::W32, |
|
| 1683 | - | val: len as i64 |
|
| 1684 | - | }, |
|
| 1685 | - | count: 1 |
|
| 1734 | + | item: il::DataItem::Undef, |
|
| 1735 | + | count: 4, |
|
| 1686 | 1736 | }); |
|
| 1687 | 1737 | } |
|
| 1688 | 1738 | ||
| 1689 | 1739 | /// Lower a compile-time `&[...]` expression to a concrete slice header. |
|
| 1690 | 1740 | fn lowerConstAddressSliceInto( |
| 1715 | 1765 | set dataName = try pushDeclData(self, layout.size, layout.alignment, readOnly, backing.values, dataPrefix); |
|
| 1716 | 1766 | } |
|
| 1717 | 1767 | } else { |
|
| 1718 | 1768 | set dataName = try pushDeclData(self, layout.size, layout.alignment, readOnly, backing.values, dataPrefix); |
|
| 1719 | 1769 | } |
|
| 1720 | - | dataSliceHeader(b, dataName, arrInfo.length); |
|
| 1770 | + | let length = resolver::concreteArrayLength(arrInfo.length) |
|
| 1771 | + | else throw LowerError::MissingMetadata; |
|
| 1772 | + | dataSliceHeader(b, dataName, length); |
|
| 1721 | 1773 | } |
|
| 1722 | 1774 | ||
| 1723 | 1775 | /// Lower a constant expression payload into a builder without slot padding. |
|
| 1724 | 1776 | fn lowerConstDataPayloadInto( |
|
| 1725 | 1777 | self: *mut Lowerer, |
| 1848 | 1900 | dataPrefix: *[u8], |
|
| 1849 | 1901 | b: *mut DataValueBuilder |
|
| 1850 | 1902 | ) throws (LowerError) { |
|
| 1851 | 1903 | let case resolver::Type::Array(arrInfo) = ty |
|
| 1852 | 1904 | else throw LowerError::ExpectedArray; |
|
| 1853 | - | let length = arrInfo.length; |
|
| 1905 | + | let length = resolver::concreteArrayLength(arrInfo.length) |
|
| 1906 | + | else throw LowerError::MissingMetadata; |
|
| 1854 | 1907 | let elemTy = *arrInfo.item; |
|
| 1855 | 1908 | let elemLayout = resolver::getTypeLayout(elemTy); |
|
| 1856 | 1909 | ||
| 1857 | 1910 | if let case ast::NodeValue::Undef = repeat.item.value { |
|
| 1858 | 1911 | dataBuilderPush(b, il::DataValue { |
| 1992 | 2045 | } |
|
| 1993 | 2046 | ||
| 1994 | 2047 | /// Find an existing string data entry with matching content. |
|
| 1995 | 2048 | // TODO: Optimize with hash table or remove? |
|
| 1996 | 2049 | fn findStringData(self: *Lowerer, s: *[u8]) -> ?*[u8] { |
|
| 1997 | - | for d in self.data { |
|
| 2050 | + | for d in vec::view⟨il::Data⟩(&self.data) { |
|
| 1998 | 2051 | if d.values.len == 1 { |
|
| 1999 | 2052 | if let case il::DataItem::Str(existing) = d.values[0].item { |
|
| 2000 | 2053 | if mem::eq(existing, s) { |
|
| 2001 | 2054 | return d.name; |
|
| 2002 | 2055 | } |
| 2058 | 2111 | readOnly: bool, |
|
| 2059 | 2112 | values: *[il::DataValue], |
|
| 2060 | 2113 | dataPrefix: *[u8] |
|
| 2061 | 2114 | ) -> *[u8] throws (LowerError) { |
|
| 2062 | 2115 | let name = try nextDeclDataName(self, dataPrefix, self.data.len, "literal"); |
|
| 2063 | - | self.data.append(il::Data { |
|
| 2116 | + | vec::append⟨il::Data⟩(&mut self.data, il::Data { |
|
| 2064 | 2117 | name, |
|
| 2065 | 2118 | size, |
|
| 2066 | 2119 | alignment, |
|
| 2067 | 2120 | readOnly, |
|
| 2068 | 2121 | isZeroInit: not readOnly and dataValuesAreZeroInit(values), |
| 2146 | 2199 | } |
|
| 2147 | 2200 | ||
| 2148 | 2201 | /// Find an existing read-only slice data entry with matching values. |
|
| 2149 | 2202 | // TODO: Optimize with hash table or remove? |
|
| 2150 | 2203 | fn findSliceData(self: *Lowerer, values: *[il::DataValue], alignment: u32) -> ?*[u8] { |
|
| 2151 | - | for d in self.data { |
|
| 2204 | + | for d in vec::view⟨il::Data⟩(&self.data) { |
|
| 2152 | 2205 | if d.alignment == alignment and d.readOnly and dataValuesEq(d.values, values) { |
|
| 2153 | 2206 | return d.name; |
|
| 2154 | 2207 | } |
|
| 2155 | 2208 | } |
|
| 2156 | 2209 | return nil; |
| 2186 | 2239 | if readOnly { |
|
| 2187 | 2240 | if let found = findConstData(self.low, values, alignment) { |
|
| 2188 | 2241 | set dataName = found; |
|
| 2189 | 2242 | } else { |
|
| 2190 | 2243 | set dataName = try nextDataName(self); |
|
| 2191 | - | self.low.data.append(il::Data { |
|
| 2244 | + | vec::append⟨il::Data⟩(&mut self.low.data, il::Data { |
|
| 2192 | 2245 | name: dataName, |
|
| 2193 | 2246 | size, |
|
| 2194 | 2247 | alignment, |
|
| 2195 | 2248 | readOnly, |
|
| 2196 | 2249 | isZeroInit: false, |
|
| 2197 | 2250 | values, |
|
| 2198 | 2251 | }, self.low.allocator); |
|
| 2199 | 2252 | } |
|
| 2200 | 2253 | } else { |
|
| 2201 | 2254 | set dataName = try nextDataName(self); |
|
| 2202 | - | self.low.data.append(il::Data { |
|
| 2255 | + | vec::append⟨il::Data⟩(&mut self.low.data, il::Data { |
|
| 2203 | 2256 | name: dataName, |
|
| 2204 | 2257 | size, |
|
| 2205 | 2258 | alignment, |
|
| 2206 | 2259 | readOnly, |
|
| 2207 | 2260 | isZeroInit: dataValuesAreZeroInit(values), |
| 2212 | 2265 | // Get data address. |
|
| 2213 | 2266 | let ptrReg = nextReg(self); |
|
| 2214 | 2267 | emit(self, il::Instr::Copy { dst: ptrReg, val: il::Val::DataSym(dataName) }); |
|
| 2215 | 2268 | ||
| 2216 | 2269 | return try buildSliceValue( |
|
| 2217 | - | self, elemTy, mutable, il::Val::Reg(ptrReg), il::Val::Imm(length as i64), il::Val::Imm(length as i64) |
|
| 2270 | + | self, elemTy, mutable, il::Val::Reg(ptrReg), il::Val::Imm(length as i64) |
|
| 2218 | 2271 | ); |
|
| 2219 | 2272 | } |
|
| 2220 | 2273 | ||
| 2221 | 2274 | /// Generate a unique data name for inline literals, eg. `fnName$literal$N`. |
|
| 2222 | 2275 | fn nextDataName(self: *mut FnLowerer) -> *[u8] throws (LowerError) { |
| 2284 | 2337 | /// Remove the last block parameter and its associated variable. |
|
| 2285 | 2338 | /// Used when detecting a trivial phi that can be eliminated. |
|
| 2286 | 2339 | fn removeLastBlockParam(self: *mut FnLowerer, block: BlockId) { |
|
| 2287 | 2340 | let blk = getBlockMut(self, block); |
|
| 2288 | 2341 | if blk.params.len > 0 { |
|
| 2289 | - | // TODO: Use `pop`? |
|
| 2290 | - | set blk.params = @sliceOf(blk.params.ptr, blk.params.len - 1, blk.params.cap); |
|
| 2342 | + | set blk.params.len -= 1; |
|
| 2291 | 2343 | } |
|
| 2292 | 2344 | if blk.paramVars.len > 0 { |
|
| 2293 | - | // TODO: Use `pop`? |
|
| 2294 | - | set blk.paramVars = @sliceOf(blk.paramVars.ptr, blk.paramVars.len - 1, blk.paramVars.cap); |
|
| 2345 | + | set blk.paramVars.len -= 1; |
|
| 2295 | 2346 | } |
|
| 2296 | 2347 | } |
|
| 2297 | 2348 | ||
| 2298 | 2349 | /// Rewrite cached SSA values for a variable across all blocks, and also |
|
| 2299 | 2350 | /// rewrite any terminator arguments that reference the provisional register. |
| 2306 | 2357 | if blk.vars[*v] == from { |
|
| 2307 | 2358 | set blk.vars[*v] = to; |
|
| 2308 | 2359 | } |
|
| 2309 | 2360 | if blk.instrs.len > 0 { |
|
| 2310 | 2361 | let ix = blk.instrs.len - 1; |
|
| 2311 | - | match &mut blk.instrs[ix] { |
|
| 2362 | + | match &mut blk.instrs.data[ix] { |
|
| 2312 | 2363 | case il::Instr::Jmp { args, .. } => |
|
| 2313 | 2364 | rewriteValInSlice(*args, from, to), |
|
| 2314 | 2365 | case il::Instr::Br { thenArgs, elseArgs, .. } => { |
|
| 2315 | 2366 | rewriteValInSlice(*thenArgs, from, to); |
|
| 2316 | 2367 | rewriteValInSlice(*elseArgs, from, to); |
| 2364 | 2415 | let vars = try! alloc::allocSlice(self.low.fnArena, @sizeOf(?il::Val), @alignOf(?il::Val), varCount) as *mut [?il::Val]; |
|
| 2365 | 2416 | ||
| 2366 | 2417 | for i in 0..varCount { |
|
| 2367 | 2418 | set vars[i] = nil; |
|
| 2368 | 2419 | } |
|
| 2369 | - | self.blockData.append(BlockData { |
|
| 2420 | + | vec::append⟨BlockData⟩(&mut self.blockData, BlockData { |
|
| 2370 | 2421 | label, |
|
| 2371 | - | params: &mut [], |
|
| 2372 | - | paramVars: &mut [], |
|
| 2373 | - | instrs: &mut [], |
|
| 2374 | - | locs: &mut [], |
|
| 2375 | - | preds: &mut [], |
|
| 2422 | + | params: vec::Vec⟨il::Param⟩ { data: &mut [], len: 0 }, |
|
| 2423 | + | paramVars: vec::Vec⟨u32⟩ { data: &mut [], len: 0 }, |
|
| 2424 | + | instrs: vec::Vec⟨il::Instr⟩ { data: &mut [], len: 0 }, |
|
| 2425 | + | locs: vec::Vec⟨il::SrcLoc⟩ { data: &mut [], len: 0 }, |
|
| 2426 | + | preds: vec::Vec⟨u32⟩ { data: &mut [], len: 0 }, |
|
| 2376 | 2427 | vars, |
|
| 2377 | - | sealState: Sealed::No { incompleteVars: &mut [] }, |
|
| 2428 | + | sealState: Sealed::No { |
|
| 2429 | + | incompleteVars: vec::Vec⟨u32⟩ { data: &mut [], len: 0 }, |
|
| 2430 | + | }, |
|
| 2378 | 2431 | loopDepth: self.loopDepth, |
|
| 2379 | 2432 | }, self.allocator); |
|
| 2380 | 2433 | ||
| 2381 | 2434 | return id; |
|
| 2382 | 2435 | } |
| 2387 | 2440 | labelBase: *[u8], |
|
| 2388 | 2441 | param: il::Param |
|
| 2389 | 2442 | ) -> BlockId throws (LowerError) { |
|
| 2390 | 2443 | let block = try createBlock(self, labelBase); |
|
| 2391 | 2444 | let blk = getBlockMut(self, block); |
|
| 2392 | - | blk.params.append(param, self.allocator); |
|
| 2445 | + | vec::append⟨il::Param⟩(&mut blk.params, param, self.allocator); |
|
| 2393 | 2446 | ||
| 2394 | 2447 | return block; |
|
| 2395 | 2448 | } |
|
| 2396 | 2449 | ||
| 2397 | 2450 | /// Switch to building a different block. |
| 2411 | 2464 | return; // Already sealed. |
|
| 2412 | 2465 | }; |
|
| 2413 | 2466 | set blk.sealState = Sealed::Yes; |
|
| 2414 | 2467 | ||
| 2415 | 2468 | // Complete all incomplete block parameters. |
|
| 2416 | - | for varId in incompleteVars { |
|
| 2469 | + | for varId in vec::view⟨u32⟩(&incompleteVars) { |
|
| 2417 | 2470 | try resolveBlockArgs(self, block, Var(varId)); |
|
| 2418 | 2471 | } |
|
| 2419 | 2472 | } |
|
| 2420 | 2473 | ||
| 2421 | 2474 | /// Seal a block and switch to it. |
| 2424 | 2477 | switchToBlock(self, block); |
|
| 2425 | 2478 | } |
|
| 2426 | 2479 | ||
| 2427 | 2480 | /// Get block data by block id. |
|
| 2428 | 2481 | fn getBlock(self: *FnLowerer, block: BlockId) -> *BlockData { |
|
| 2429 | - | return &self.blockData[*block]; |
|
| 2482 | + | return &self.blockData.data[*block]; |
|
| 2430 | 2483 | } |
|
| 2431 | 2484 | ||
| 2432 | 2485 | /// Get mutable block data by block id. |
|
| 2433 | 2486 | fn getBlockMut(self: *mut FnLowerer, block: BlockId) -> *mut BlockData { |
|
| 2434 | - | return &mut self.blockData[*block]; |
|
| 2487 | + | return &mut self.blockData.data[*block]; |
|
| 2435 | 2488 | } |
|
| 2436 | 2489 | ||
| 2437 | 2490 | /// Get the current block being built. |
|
| 2438 | 2491 | fn currentBlock(self: *FnLowerer) -> BlockId { |
|
| 2439 | 2492 | let block = self.currentBlock else { |
| 2459 | 2512 | else => {}, |
|
| 2460 | 2513 | } |
|
| 2461 | 2514 | } |
|
| 2462 | 2515 | // Record source location alongside instruction when enabled. |
|
| 2463 | 2516 | if self.low.options.debug { |
|
| 2464 | - | block.locs.append(self.srcLoc, self.allocator); |
|
| 2517 | + | vec::append⟨il::SrcLoc⟩(&mut block.locs, self.srcLoc, self.allocator); |
|
| 2465 | 2518 | } |
|
| 2466 | - | block.instrs.append(instr, self.allocator); |
|
| 2519 | + | vec::append⟨il::Instr⟩(&mut block.instrs, instr, self.allocator); |
|
| 2467 | 2520 | } |
|
| 2468 | 2521 | ||
| 2469 | 2522 | /// Emit an unconditional jump to `target`. |
|
| 2470 | 2523 | fn emitJmp(self: *mut FnLowerer, target: BlockId) throws (LowerError) { |
|
| 2471 | 2524 | emit(self, il::Instr::Jmp { target: *target, args: &mut [] }); |
| 2621 | 2674 | let condReg = emitValToReg(self, condVal); |
|
| 2622 | 2675 | ||
| 2623 | 2676 | try emitBr(self, condReg, thenBlock, elseBlock); |
|
| 2624 | 2677 | } |
|
| 2625 | 2678 | ||
| 2626 | - | /// Emit a 32-bit store instruction at the given offset. |
|
| 2627 | - | fn emitStoreW32At(self: *mut FnLowerer, src: il::Val, dst: il::Reg, offset: i32) { |
|
| 2628 | - | emit(self, il::Instr::Store { typ: il::Type::W32, src, dst, offset }); |
|
| 2629 | - | } |
|
| 2630 | - | ||
| 2631 | 2679 | /// Emit a 32-bit load instruction at the given offset. |
|
| 2632 | 2680 | fn emitLoadW32At(self: *mut FnLowerer, dst: il::Reg, src: il::Reg, offset: i32) { |
|
| 2633 | 2681 | emit(self, il::Instr::Load { typ: il::Type::W32, dst, src, offset }); |
|
| 2634 | 2682 | } |
|
| 2635 | 2683 |
| 2672 | 2720 | let lenReg = nextReg(self); |
|
| 2673 | 2721 | emitLoadW32At(self, lenReg, sliceReg, SLICE_LEN_OFFSET); |
|
| 2674 | 2722 | return il::Val::Reg(lenReg); |
|
| 2675 | 2723 | } |
|
| 2676 | 2724 | ||
| 2677 | - | /// Load the capacity from a slice value. |
|
| 2678 | - | fn loadSliceCap(self: *mut FnLowerer, sliceReg: il::Reg) -> il::Val { |
|
| 2679 | - | let capReg = nextReg(self); |
|
| 2680 | - | emitLoadW32At(self, capReg, sliceReg, SLICE_CAP_OFFSET); |
|
| 2681 | - | return il::Val::Reg(capReg); |
|
| 2682 | - | } |
|
| 2683 | - | ||
| 2684 | 2725 | /// Emit a load instruction for a scalar value at `src` plus `offset`. |
|
| 2685 | 2726 | /// For reading values that may be aggregates, use `emitRead` instead. |
|
| 2686 | 2727 | fn emitLoad(self: *mut FnLowerer, src: il::Reg, offset: i32, typ: resolver::Type) -> il::Val { |
|
| 2687 | 2728 | let dst = nextReg(self); |
|
| 2688 | 2729 | let ilTyp = ilType(self.low, typ); |
| 2884 | 2925 | fn blockHasTerminator(self: *FnLowerer) -> bool { |
|
| 2885 | 2926 | let blk = getBlock(self, currentBlock(self)); |
|
| 2886 | 2927 | if blk.instrs.len == 0 { |
|
| 2887 | 2928 | return false; |
|
| 2888 | 2929 | } |
|
| 2889 | - | match blk.instrs[blk.instrs.len - 1] { |
|
| 2930 | + | match blk.instrs.data[blk.instrs.len - 1] { |
|
| 2890 | 2931 | case il::Instr::Ret { .. }, |
|
| 2891 | 2932 | il::Instr::Jmp { .. }, |
|
| 2892 | 2933 | il::Instr::Br { .. }, |
|
| 2893 | 2934 | il::Instr::Switch { .. }, |
|
| 2894 | 2935 | il::Instr::Unreachable => |
| 2930 | 2971 | /// Add a predecessor edge from `pred` to `target`. |
|
| 2931 | 2972 | /// Must be called before the target block is sealed. Duplicates are ignored. |
|
| 2932 | 2973 | fn addPredecessor(self: *mut FnLowerer, target: BlockId, pred: BlockId) { |
|
| 2933 | 2974 | let blk = getBlockMut(self, target); |
|
| 2934 | 2975 | assert blk.sealState <> Sealed::Yes, "addPredecessor: adding predecessor to sealed block"; |
|
| 2935 | - | let preds = &mut blk.preds; |
|
| 2936 | - | for i in 0..preds.len { |
|
| 2937 | - | if preds[i] == *pred { // Avoid duplicate predecessor entries. |
|
| 2976 | + | for i in 0..blk.preds.len { |
|
| 2977 | + | if blk.preds.data[i] == *pred { // Avoid duplicate predecessor entries. |
|
| 2938 | 2978 | return; |
|
| 2939 | 2979 | } |
|
| 2940 | 2980 | } |
|
| 2941 | - | preds.append(*pred, self.allocator); |
|
| 2981 | + | vec::append⟨u32⟩(&mut blk.preds, *pred, self.allocator); |
|
| 2942 | 2982 | } |
|
| 2943 | 2983 | ||
| 2944 | 2984 | /// Finalize all blocks and return the block array. |
|
| 2945 | 2985 | fn finalizeBlocks(self: *mut FnLowerer) -> *[il::Block] throws (LowerError) { |
|
| 2946 | 2986 | let blocks = try! alloc::allocSlice( |
|
| 2947 | 2987 | self.low.fnArena, @sizeOf(il::Block), @alignOf(il::Block), self.blockData.len |
|
| 2948 | 2988 | ) as *mut [il::Block]; |
|
| 2949 | 2989 | ||
| 2950 | 2990 | for i in 0..self.blockData.len { |
|
| 2951 | - | let data = &self.blockData[i]; |
|
| 2991 | + | let data = &mut self.blockData.data[i]; |
|
| 2952 | 2992 | ||
| 2953 | 2993 | set blocks[i] = il::Block { |
|
| 2954 | 2994 | label: data.label, |
|
| 2955 | - | params: &data.params[..], |
|
| 2956 | - | instrs: data.instrs, |
|
| 2957 | - | locs: &data.locs[..], |
|
| 2958 | - | preds: &data.preds[..], |
|
| 2995 | + | params: vec::view⟨il::Param⟩(&data.params), |
|
| 2996 | + | instrs: vec::viewMut⟨il::Instr⟩(&mut data.instrs), |
|
| 2997 | + | locs: vec::view⟨il::SrcLoc⟩(&data.locs), |
|
| 2998 | + | preds: vec::view⟨u32⟩(&data.preds), |
|
| 2959 | 2999 | loopDepth: data.loopDepth, |
|
| 2960 | 3000 | }; |
|
| 2961 | 3001 | } |
|
| 2962 | 3002 | return &blocks[..self.blockData.len]; |
|
| 2963 | 3003 | } |
| 3112 | 3152 | type: il::Type, |
|
| 3113 | 3153 | mutable: bool, |
|
| 3114 | 3154 | val: il::Val |
|
| 3115 | 3155 | ) -> Var { |
|
| 3116 | 3156 | let id = self.vars.len; |
|
| 3117 | - | self.vars.append(VarData { name, type, mutable, addressTaken: false }, self.allocator); |
|
| 3157 | + | vec::append⟨VarData⟩( |
|
| 3158 | + | &mut self.vars, |
|
| 3159 | + | VarData { name, type, mutable, addressTaken: false }, |
|
| 3160 | + | self.allocator, |
|
| 3161 | + | ); |
|
| 3118 | 3162 | ||
| 3119 | 3163 | let v = Var(id); |
|
| 3120 | 3164 | if self.currentBlock <> nil { |
|
| 3121 | 3165 | defVar(self, v, val); |
|
| 3122 | 3166 | } |
| 3162 | 3206 | throw LowerError::InvalidUse; |
|
| 3163 | 3207 | } |
|
| 3164 | 3208 | // Single predecessor means no merge needed, variable is implicitly |
|
| 3165 | 3209 | // available without a block parameter. |
|
| 3166 | 3210 | if blk.preds.len == 1 { |
|
| 3167 | - | let pred = BlockId(blk.preds[0]); |
|
| 3211 | + | let pred = BlockId(blk.preds.data[0]); |
|
| 3168 | 3212 | if *pred <> *block { |
|
| 3169 | 3213 | let val = try useVarInBlock(self, pred, v); |
|
| 3170 | 3214 | set blk.vars[*v] = val; // Cache. |
|
| 3171 | 3215 | return val; |
|
| 3172 | 3216 | } |
| 3181 | 3225 | /// Searches from most recently declared to first, enabling shadowing. |
|
| 3182 | 3226 | fn lookupVarByName(self: *FnLowerer, name: *[u8]) -> ?Var { |
|
| 3183 | 3227 | let mut id = self.vars.len; |
|
| 3184 | 3228 | while id > 0 { |
|
| 3185 | 3229 | set id -= 1; |
|
| 3186 | - | if let varName = self.vars[id].name { |
|
| 3230 | + | if let varName = self.vars.data[id].name { |
|
| 3187 | 3231 | // Names are interned strings, so pointer comparison suffices. |
|
| 3188 | 3232 | if varName == name { |
|
| 3189 | 3233 | return Var(id); |
|
| 3190 | 3234 | } |
|
| 3191 | 3235 | } |
| 3206 | 3250 | return self.vars.len; |
|
| 3207 | 3251 | } |
|
| 3208 | 3252 | ||
| 3209 | 3253 | /// Restore lexical variable scope depth. |
|
| 3210 | 3254 | fn exitVarScope(self: *mut FnLowerer, savedVarsLen: u32) { |
|
| 3211 | - | set self.vars = @sliceOf(self.vars.ptr, savedVarsLen, self.vars.cap); |
|
| 3255 | + | set self.vars.len = savedVarsLen; |
|
| 3212 | 3256 | } |
|
| 3213 | 3257 | ||
| 3214 | 3258 | /// Get the metadata for a variable. |
|
| 3215 | 3259 | fn getVar(self: *FnLowerer, v: Var) -> *VarData { |
|
| 3216 | 3260 | assert *v < self.vars.len; |
|
| 3217 | - | return &self.vars[*v]; |
|
| 3261 | + | return &self.vars.data[*v]; |
|
| 3218 | 3262 | } |
|
| 3219 | 3263 | ||
| 3220 | 3264 | /// Create a block parameter to merge a variable's value from multiple |
|
| 3221 | 3265 | /// control flow paths. |
|
| 3222 | 3266 | /// |
| 3241 | 3285 | let type = getVar(self, v).type; |
|
| 3242 | 3286 | ||
| 3243 | 3287 | // Create block parameter and add it to the block. |
|
| 3244 | 3288 | let param = il::Param { value: reg, type }; |
|
| 3245 | 3289 | let blk = getBlockMut(self, block); |
|
| 3246 | - | blk.params.append(param, self.allocator); |
|
| 3247 | - | blk.paramVars.append(*v, self.allocator); // Associate variable with parameter. |
|
| 3290 | + | vec::append⟨il::Param⟩(&mut blk.params, param, self.allocator); |
|
| 3291 | + | vec::append⟨u32⟩(&mut blk.paramVars, *v, self.allocator); // Associate variable with parameter. |
|
| 3248 | 3292 | ||
| 3249 | 3293 | // Record that this variable's value in this block is now the parameter register. |
|
| 3250 | 3294 | // This must happen before the predecessor loop to handle self-referential loops. |
|
| 3251 | 3295 | set blk.vars[*v] = il::Val::Reg(reg); |
|
| 3252 | 3296 | ||
| 3253 | 3297 | match &mut blk.sealState { |
|
| 3254 | 3298 | case Sealed::No { incompleteVars } => { |
|
| 3255 | 3299 | // Block unsealed: defer until sealing. |
|
| 3256 | - | incompleteVars.append(*v, self.allocator); |
|
| 3300 | + | vec::append⟨u32⟩(incompleteVars, *v, self.allocator); |
|
| 3257 | 3301 | }, |
|
| 3258 | 3302 | case Sealed::Yes => { |
|
| 3259 | 3303 | // Block sealed: check for trivial phi before committing. If all |
|
| 3260 | 3304 | // predecessors provide the same value, we can remove the param we |
|
| 3261 | 3305 | // just created and use that value directly. |
| 3289 | 3333 | ||
| 3290 | 3334 | // Find the parameter index corresponding to this variable. |
|
| 3291 | 3335 | // Each variable that needs merging gets its own block parameter slot. |
|
| 3292 | 3336 | let mut paramIdx: u32 = 0; |
|
| 3293 | 3337 | for i in 0..blk.paramVars.len { |
|
| 3294 | - | if blk.paramVars[i] == *v { |
|
| 3338 | + | if blk.paramVars.data[i] == *v { |
|
| 3295 | 3339 | set paramIdx = i; |
|
| 3296 | 3340 | break; |
|
| 3297 | 3341 | } |
|
| 3298 | 3342 | } |
|
| 3299 | 3343 | ||
| 3300 | 3344 | // For each predecessor, recursively look up the variable's reaching definition |
|
| 3301 | 3345 | // in that block, then patch the predecessor's terminator to pass that value |
|
| 3302 | 3346 | // as an argument to this block's parameter. |
|
| 3303 | - | for predId in blk.preds { |
|
| 3347 | + | for predId in vec::view⟨u32⟩(&blk.preds) { |
|
| 3304 | 3348 | let pred = BlockId(predId); |
|
| 3305 | 3349 | // This may recursively trigger more block arg resolution if the |
|
| 3306 | 3350 | // predecessor also needs to look up the variable from its predecessors. |
|
| 3307 | 3351 | let val = try useVarInBlock(self, pred, v); |
|
| 3308 | 3352 | assert val <> il::Val::Undef, "createBlockParam: predecessor provides undef value for block parameter"; |
| 3317 | 3361 | // Get the block parameter register. |
|
| 3318 | 3362 | let paramReg = blk.vars[*v]; |
|
| 3319 | 3363 | // Check if all predecessors provide the same value. |
|
| 3320 | 3364 | let mut sameVal: ?il::Val = nil; |
|
| 3321 | 3365 | ||
| 3322 | - | for predId in blk.preds { |
|
| 3366 | + | for predId in vec::view⟨u32⟩(&blk.preds) { |
|
| 3323 | 3367 | let pred = BlockId(predId); |
|
| 3324 | 3368 | let val = try useVarInBlock(self, pred, v); |
|
| 3325 | 3369 | ||
| 3326 | 3370 | // Check if this is a self-reference. |
|
| 3327 | 3371 | // This happens in cycles where the loop back-edge passes the phi to |
| 3356 | 3400 | let data = getBlockMut(self, from); |
|
| 3357 | 3401 | let ix = data.instrs.len - 1; // The terminator is always the last instruction. |
|
| 3358 | 3402 | ||
| 3359 | 3403 | // TODO: We shouldn't need to use a mutable subscript here, given that the |
|
| 3360 | 3404 | // fields are already mutable. |
|
| 3361 | - | match &mut data.instrs[ix] { |
|
| 3405 | + | match &mut data.instrs.data[ix] { |
|
| 3362 | 3406 | case il::Instr::Jmp { args, .. } => { |
|
| 3363 | 3407 | set *args = growArgs(self, *args, paramIdx + 1); |
|
| 3364 | 3408 | set args[paramIdx] = val; |
|
| 3365 | 3409 | } |
|
| 3366 | 3410 | case il::Instr::Br { thenTarget, thenArgs, elseTarget, elseArgs, .. } => { |
| 3466 | 3510 | } else { |
|
| 3467 | 3511 | set name = try paramName(&astParams[i].value); |
|
| 3468 | 3512 | } |
|
| 3469 | 3513 | let v = newVar(self, name, type, false, il::Val::Undef); |
|
| 3470 | 3514 | ||
| 3471 | - | self.params.append(FnParamBinding { var: v, reg }, self.allocator); |
|
| 3515 | + | vec::append⟨FnParamBinding⟩( |
|
| 3516 | + | &mut self.params, |
|
| 3517 | + | FnParamBinding { var: v, reg }, |
|
| 3518 | + | self.allocator, |
|
| 3519 | + | ); |
|
| 3472 | 3520 | } |
|
| 3473 | 3521 | return params; |
|
| 3474 | 3522 | } |
|
| 3475 | 3523 | ||
| 3476 | 3524 | /// Resolve match subject. |
| 3875 | 3923 | let entry = try createBlock(self, "entry"); |
|
| 3876 | 3924 | set self.entryBlock = entry; |
|
| 3877 | 3925 | switchToBlock(self, entry); |
|
| 3878 | 3926 | ||
| 3879 | 3927 | /// Bind parameter registers to variables in the entry block. |
|
| 3880 | - | for def in self.params { |
|
| 3928 | + | for def in vec::view⟨FnParamBinding⟩(&self.params) { |
|
| 3881 | 3929 | defVar(self, def.var, il::Val::Reg(def.reg)); |
|
| 3882 | 3930 | } |
|
| 3883 | 3931 | /// Lower function body. |
|
| 3884 | 3932 | try lowerBlock(self, body); |
|
| 3885 | 3933 |
| 3903 | 3951 | } |
|
| 3904 | 3952 | ||
| 3905 | 3953 | /// Lower a scalar match as a switch instruction. |
|
| 3906 | 3954 | fn lowerMatchSwitch(self: *mut FnLowerer, prongs: *mut [*ast::Node], subject: *MatchSubject, mergeBlock: *mut ?BlockId) throws (LowerError) { |
|
| 3907 | 3955 | let mut blocks: [BlockId; 32] = undefined; |
|
| 3908 | - | let mut cases: *mut [il::SwitchCase] = &mut []; |
|
| 3956 | + | let mut cases = vec::Vec⟨il::SwitchCase⟩ { data: &mut [], len: 0 }; |
|
| 3909 | 3957 | let mut defaultIdx: u32 = 0; |
|
| 3910 | 3958 | let entry = currentBlock(self); |
|
| 3911 | 3959 | ||
| 3912 | 3960 | for p, i in prongs { |
|
| 3913 | 3961 | let case ast::NodeValue::MatchProng(prong) = p.value |
| 3922 | 3970 | set blocks[i] = try createBlock(self, "case"); |
|
| 3923 | 3971 | for pat in pats { |
|
| 3924 | 3972 | let cv = resolver::constValueEntry(self.low.resolver, pat) |
|
| 3925 | 3973 | else throw LowerError::MissingConst(pat); |
|
| 3926 | 3974 | ||
| 3927 | - | cases.append(il::SwitchCase { |
|
| 3975 | + | vec::append⟨il::SwitchCase⟩(&mut cases, il::SwitchCase { |
|
| 3928 | 3976 | value: constToScalar(cv), |
|
| 3929 | 3977 | target: *blocks[i], |
|
| 3930 | 3978 | args: &mut [] |
|
| 3931 | 3979 | }, self.allocator); |
|
| 3932 | 3980 | } |
| 3936 | 3984 | } |
|
| 3937 | 3985 | emit(self, il::Instr::Switch { |
|
| 3938 | 3986 | val: subject.val, |
|
| 3939 | 3987 | defaultTarget: *blocks[defaultIdx], |
|
| 3940 | 3988 | defaultArgs: &mut [], |
|
| 3941 | - | cases: &mut cases[..] |
|
| 3989 | + | cases: vec::viewMut⟨il::SwitchCase⟩(&mut cases), |
|
| 3942 | 3990 | }); |
|
| 3943 | 3991 | ||
| 3944 | 3992 | for p, i in prongs { |
|
| 3945 | 3993 | let case ast::NodeValue::MatchProng(prong) = p.value |
|
| 3946 | 3994 | else throw LowerError::UnexpectedNodeValue(p); |
| 4590 | 4638 | if let case resolver::Type::Pointer(_) = *inner { |
|
| 4591 | 4639 | return il::Val::Imm(0); |
|
| 4592 | 4640 | } |
|
| 4593 | 4641 | if let case resolver::Type::Slice(slice) = *inner { |
|
| 4594 | 4642 | return try buildSliceValue( |
|
| 4595 | - | self, slice.item, slice.mutable, il::Val::Imm(0), il::Val::Imm(0), il::Val::Imm(0) |
|
| 4643 | + | self, slice.item, slice.mutable, il::Val::Imm(0), il::Val::Imm(0) |
|
| 4596 | 4644 | ); |
|
| 4597 | 4645 | } |
|
| 4598 | 4646 | let valOffset = resolver::getOptionalValOffset(*inner) as i32; |
|
| 4599 | 4647 | return try buildTagged(self, resolver::getTypeLayout(optType), 0, nil, *inner, 1, valOffset); |
|
| 4600 | 4648 | } |
| 4611 | 4659 | successType, self.fnType.throwList |
|
| 4612 | 4660 | ); |
|
| 4613 | 4661 | return try buildTagged(self, layout, tag, payload, payloadType, resolver::PTR_SIZE as i32, RESULT_VAL_OFFSET); |
|
| 4614 | 4662 | } |
|
| 4615 | 4663 | ||
| 4616 | - | /// Build a slice aggregate from a data pointer, length and capacity. |
|
| 4664 | + | /// Build a 16-byte slice aggregate from a data pointer and length. |
|
| 4617 | 4665 | fn buildSliceValue( |
|
| 4618 | 4666 | self: *mut FnLowerer, |
|
| 4619 | 4667 | elemTy: *resolver::Type, |
|
| 4620 | 4668 | mutable: bool, |
|
| 4621 | 4669 | ptrVal: il::Val, |
|
| 4622 | - | lenVal: il::Val, |
|
| 4623 | - | capVal: il::Val |
|
| 4670 | + | lenVal: il::Val |
|
| 4624 | 4671 | ) -> il::Val throws (LowerError) { |
|
| 4625 | 4672 | let sliceType = resolver::Type::Slice(resolver::SliceType { |
|
| 4626 | 4673 | class: types::PointerClass::Unsafe, |
|
| 4627 | 4674 | item: elemTy, |
|
| 4628 | 4675 | mutable, |
| 4634 | 4681 | mutable, |
|
| 4635 | 4682 | }); |
|
| 4636 | 4683 | ||
| 4637 | 4684 | try emitStore(self, dst, SLICE_PTR_OFFSET, ptrTy, ptrVal); |
|
| 4638 | 4685 | try emitStore(self, dst, SLICE_LEN_OFFSET, resolver::Type::U32, lenVal); |
|
| 4639 | - | try emitStore(self, dst, SLICE_CAP_OFFSET, resolver::Type::U32, capVal); |
|
| 4640 | 4686 | ||
| 4641 | 4687 | return il::Val::Reg(dst); |
|
| 4642 | 4688 | } |
|
| 4643 | 4689 | ||
| 4644 | 4690 | /// Build a trait object fat pointer from a data pointer and a v-table. |
| 5051 | 5097 | offset: i32 |
|
| 5052 | 5098 | ) -> il::Val throws (LowerError) { |
|
| 5053 | 5099 | let elemLayout = resolver::getTypeLayout(*arr.item); |
|
| 5054 | 5100 | let stride = elemLayout.size as i32; |
|
| 5055 | 5101 | let mut result: ?il::Val = nil; |
|
| 5102 | + | let length = resolver::concreteArrayLength(arr.length) |
|
| 5103 | + | else throw LowerError::MissingMetadata; |
|
| 5056 | 5104 | ||
| 5057 | - | for i in 0..arr.length { |
|
| 5105 | + | for i in 0..length { |
|
| 5058 | 5106 | let elemOffset = offset + (i as i32) * stride; |
|
| 5059 | 5107 | let cmp = try emitEqAtOffset(self, a, b, elemOffset, *arr.item); |
|
| 5060 | 5108 | set result = emitLogicalAnd(self, result, cmp); |
|
| 5061 | 5109 | } |
|
| 5062 | 5110 | if let r = result { |
| 5216 | 5264 | let typ = try typeOf(self, node); |
|
| 5217 | 5265 | let case resolver::Type::Array(arrInfo) = typ else { |
|
| 5218 | 5266 | throw LowerError::ExpectedArray; |
|
| 5219 | 5267 | }; |
|
| 5220 | 5268 | let elemTy = *arrInfo.item; |
|
| 5221 | - | let length = arrInfo.length; |
|
| 5269 | + | let length = resolver::concreteArrayLength(arrInfo.length) |
|
| 5270 | + | else throw LowerError::MissingMetadata; |
|
| 5222 | 5271 | let elemLayout = resolver::getTypeLayout(elemTy); |
|
| 5223 | 5272 | let dst = try emitReserve(self, typ); |
|
| 5224 | 5273 | ||
| 5225 | 5274 | // Evaluate the repeated item once. |
|
| 5226 | 5275 | let repeatVal = try lowerExpr(self, repeat.item); |
| 5295 | 5344 | let itemType = try specializeType(self, *info.itemType); |
|
| 5296 | 5345 | ||
| 5297 | 5346 | // Extract data pointer and container length. |
|
| 5298 | 5347 | let mut dataReg = baseReg; |
|
| 5299 | 5348 | let mut containerLen: il::Val = undefined; |
|
| 5300 | - | if let cap = info.capacity { // Slice from array. |
|
| 5301 | - | set containerLen = il::Val::Imm(cap as i64); |
|
| 5349 | + | if let descriptor = info.capacity { // Slice from array. |
|
| 5350 | + | let specialized = try specializeType(self, *descriptor); |
|
| 5351 | + | let capacity = resolver::concreteArrayLength(&specialized) |
|
| 5352 | + | else throw LowerError::MissingMetadata; |
|
| 5353 | + | set containerLen = il::Val::Imm(capacity as i64); |
|
| 5302 | 5354 | } else { // Slice from slice. |
|
| 5303 | 5355 | set dataReg = loadSlicePtr(self, baseReg); |
|
| 5304 | 5356 | set containerLen = loadSliceLen(self, baseReg); |
|
| 5305 | 5357 | } |
|
| 5306 | 5358 |
| 5361 | 5413 | throw LowerError::MissingMetadata; |
|
| 5362 | 5414 | }; |
|
| 5363 | 5415 | let r = try resolveSliceRangePtr(self, container, range, info); |
|
| 5364 | 5416 | let itemType = try specializeType(self, *info.itemType); |
|
| 5365 | 5417 | return try buildSliceValue( |
|
| 5366 | - | self, &itemType, info.mutable, il::Val::Reg(r.dataReg), r.count, r.count |
|
| 5418 | + | self, &itemType, info.mutable, il::Val::Reg(r.dataReg), r.count |
|
| 5367 | 5419 | ); |
|
| 5368 | 5420 | } |
|
| 5369 | 5421 | ||
| 5370 | 5422 | /// Lower an address-of (`&x`) expression. |
|
| 5371 | 5423 | fn lowerAddressOf(self: *mut FnLowerer, node: *ast::Node, addr: ast::AddressOf) -> il::Val throws (LowerError) { |
| 5394 | 5446 | if isAggregateType(typ) { |
|
| 5395 | 5447 | return val; |
|
| 5396 | 5448 | } |
|
| 5397 | 5449 | // For scalars, if we've already materialized a stack slot for this |
|
| 5398 | 5450 | // variable, the SSA value is that slot pointer. |
|
| 5399 | - | if self.vars[*v].addressTaken { |
|
| 5451 | + | if self.vars.data[*v].addressTaken { |
|
| 5400 | 5452 | // Already address-taken; return existing stack pointer. |
|
| 5401 | 5453 | return val; |
|
| 5402 | 5454 | } |
|
| 5403 | 5455 | // Materialize a stack slot using the declaration's resolved |
|
| 5404 | 5456 | // layout so `align(N)` on locals is honored. |
|
| 5405 | 5457 | let layout = resolver::getLayout(self.low.resolver, addr.target, typ); |
|
| 5406 | 5458 | let slot = emitReserveLayout(self, layout); |
|
| 5407 | 5459 | try emitStore(self, slot, 0, typ, val); |
|
| 5408 | 5460 | let stackVal = il::Val::Reg(slot); |
|
| 5409 | 5461 | ||
| 5410 | - | set self.vars[*v].addressTaken = true; |
|
| 5462 | + | set self.vars.data[*v].addressTaken = true; |
|
| 5411 | 5463 | defVar(self, v, stackVal); |
|
| 5412 | 5464 | ||
| 5413 | 5465 | return stackVal; |
|
| 5414 | 5466 | } |
|
| 5415 | 5467 | // Fall back to symbol lookup for constants/statics. |
| 5447 | 5499 | }; |
|
| 5448 | 5500 | let arrayTy = try typeOf(self, arrayNode); |
|
| 5449 | 5501 | let case resolver::Type::Array(arrayInfo) = arrayTy else { |
|
| 5450 | 5502 | throw LowerError::ExpectedArray; |
|
| 5451 | 5503 | }; |
|
| 5452 | - | let length = arrayInfo.length; |
|
| 5504 | + | let length = resolver::concreteArrayLength(arrayInfo.length) |
|
| 5505 | + | else throw LowerError::MissingMetadata; |
|
| 5453 | 5506 | if length == 0 { |
|
| 5454 | 5507 | return try buildSliceValue( |
|
| 5455 | - | self, slice.item, slice.mutable, il::Val::Imm(0), il::Val::Imm(0), il::Val::Imm(0) |
|
| 5508 | + | self, slice.item, slice.mutable, il::Val::Imm(0), il::Val::Imm(0) |
|
| 5456 | 5509 | ); |
|
| 5457 | 5510 | } |
|
| 5458 | 5511 | if resolver::isConstExpr(self.low.resolver, arrayNode) { |
|
| 5459 | 5512 | let mut b = dataBuilder(self.low.allocator); |
|
| 5460 | 5513 | match arrayNode.value { |
| 5471 | 5524 | slice.item, slice.mutable, length |
|
| 5472 | 5525 | ); |
|
| 5473 | 5526 | } |
|
| 5474 | 5527 | let data = try lowerExpr(self, arrayNode); |
|
| 5475 | 5528 | let count = il::Val::Imm(length as i64); |
|
| 5476 | - | return try buildSliceValue(self, slice.item, slice.mutable, data, count, count); |
|
| 5529 | + | return try buildSliceValue(self, slice.item, slice.mutable, data, count); |
|
| 5477 | 5530 | } |
|
| 5478 | 5531 | ||
| 5479 | 5532 | /// Lower the common element pointer computation for subscript operations. |
|
| 5480 | 5533 | /// Handles both arrays and slices by resolving the container type, extracting |
|
| 5481 | 5534 | /// the data pointer (for slices), and emitting an [`il::Instr::Elem`] to compute |
| 5505 | 5558 | set elemType = *arrInfo.item; |
|
| 5506 | 5559 | // Runtime safety check: index must be strictly less than array length. |
|
| 5507 | 5560 | // Skip when the index is a compile-time constant, since we check |
|
| 5508 | 5561 | // that in the resolver. |
|
| 5509 | 5562 | if not resolver::isConstExpr(self.low.resolver, index) { |
|
| 5510 | - | let arrLen = il::Val::Imm(arrInfo.length as i64); |
|
| 5563 | + | let length = resolver::concreteArrayLength(arrInfo.length) |
|
| 5564 | + | else throw LowerError::MissingMetadata; |
|
| 5565 | + | let arrLen = il::Val::Imm(length as i64); |
|
| 5511 | 5566 | try emitTrapUnlessCmp(self, il::CmpOp::Ult, il::Type::W32, indexVal, arrLen); |
|
| 5512 | 5567 | } |
|
| 5513 | 5568 | } |
|
| 5514 | 5569 | else => throw LowerError::ExpectedSliceOrArray, |
|
| 5515 | 5570 | } |
| 5582 | 5637 | let layout = resolver::getLayout(self.low.resolver, node, typ); |
|
| 5583 | 5638 | let slot = emitReserveLayout(self, layout); |
|
| 5584 | 5639 | try emitStore(self, slot, 0, typ, varVal); |
|
| 5585 | 5640 | ||
| 5586 | 5641 | let v = newVar(self, name, ilType, l.mutable, il::Val::Reg(slot)); |
|
| 5587 | - | set self.vars[*v].addressTaken = true; |
|
| 5642 | + | set self.vars.data[*v].addressTaken = true; |
|
| 5588 | 5643 | ||
| 5589 | 5644 | return; |
|
| 5590 | 5645 | } |
|
| 5591 | 5646 | } |
|
| 5592 | 5647 | } |
| 6036 | 6091 | let containerVal = try lowerExpr(self, f.iterable); |
|
| 6037 | 6092 | let containerReg = emitValToReg(self, containerVal); |
|
| 6038 | 6093 | ||
| 6039 | 6094 | let mut dataReg = containerReg; |
|
| 6040 | 6095 | let mut lengthVal: il::Val = undefined; |
|
| 6041 | - | if let len = length { |
|
| 6096 | + | if let descriptor = length { |
|
| 6097 | + | let specialized = try specializeType(self, *descriptor); |
|
| 6098 | + | let len = resolver::concreteArrayLength(&specialized) |
|
| 6099 | + | else throw LowerError::MissingMetadata; |
|
| 6042 | 6100 | set lengthVal = il::Val::Imm(len as i64); |
|
| 6043 | 6101 | } else { |
|
| 6044 | 6102 | set lengthVal = loadSliceLen(self, containerReg); |
|
| 6045 | 6103 | set dataReg = loadSlicePtr(self, containerReg); |
|
| 6046 | 6104 | } |
| 6555 | 6613 | ||
| 6556 | 6614 | /// Lower a builtin call expression. |
|
| 6557 | 6615 | fn lowerBuiltinCall(self: *mut FnLowerer, node: *ast::Node, kind: ast::Builtin, args: *mut [*ast::Node]) -> il::Val throws (LowerError) { |
|
| 6558 | 6616 | match kind { |
|
| 6559 | 6617 | case ast::Builtin::SliceOf => return try lowerSliceOf(self, node, args), |
|
| 6618 | + | case ast::Builtin::Relocate => return try lowerRelocate(self, args), |
|
| 6560 | 6619 | case ast::Builtin::SizeOf, ast::Builtin::AlignOf => { |
|
| 6561 | - | let constVal = resolver::constValueEntry(self.low.resolver, node) else { |
|
| 6562 | - | throw LowerError::MissingConst(node); |
|
| 6563 | - | }; |
|
| 6564 | - | return try constValueToVal(self, constVal, node); |
|
| 6620 | + | if let constVal = resolver::constValueEntry(self.low.resolver, node) { |
|
| 6621 | + | return try constValueToVal(self, constVal, node); |
|
| 6622 | + | } |
|
| 6623 | + | if args.len <> 1 { |
|
| 6624 | + | throw LowerError::InvalidArgCount; |
|
| 6625 | + | } |
|
| 6626 | + | let ty = try typeOf(self, args[0]); |
|
| 6627 | + | let layout = resolver::getTypeLayout(ty); |
|
| 6628 | + | let mut value = layout.size; |
|
| 6629 | + | if kind == ast::Builtin::AlignOf { |
|
| 6630 | + | set value = layout.alignment; |
|
| 6631 | + | } |
|
| 6632 | + | return il::Val::Imm(value as i64); |
|
| 6565 | 6633 | } |
|
| 6566 | 6634 | } |
|
| 6567 | 6635 | } |
|
| 6568 | 6636 | ||
| 6569 | - | /// Lower a `@sliceOf(ptr, len)` or `@sliceOf(ptr, len, cap)` builtin call. |
|
| 6637 | + | /// Lower a two-argument `@sliceOf(ptr, len)` builtin call. |
|
| 6570 | 6638 | fn lowerSliceOf(self: *mut FnLowerer, node: *ast::Node, args: *mut [*ast::Node]) -> il::Val throws (LowerError) { |
|
| 6571 | - | if args.len <> 2 and args.len <> 3 { |
|
| 6639 | + | if args.len <> 2 { |
|
| 6572 | 6640 | throw LowerError::InvalidArgCount; |
|
| 6573 | 6641 | } |
|
| 6574 | 6642 | let sliceTy = try typeOf(self, node); |
|
| 6575 | 6643 | let case resolver::Type::Slice(slice) = sliceTy |
|
| 6576 | 6644 | else throw LowerError::ExpectedSliceOrArray; |
|
| 6577 | 6645 | let ptrVal = try lowerExpr(self, args[0]); |
|
| 6578 | 6646 | let lenVal = try lowerExpr(self, args[1]); |
|
| 6579 | - | let mut capVal = lenVal; |
|
| 6580 | - | if args.len == 3 { |
|
| 6581 | - | set capVal = try lowerExpr(self, args[2]); |
|
| 6582 | - | } |
|
| 6583 | - | if not isLtEq(lenVal, capVal) { |
|
| 6584 | - | try emitTrapIfLt(self, il::Type::W32, capVal, lenVal); |
|
| 6647 | + | return try buildSliceValue(self, slice.item, slice.mutable, ptrVal, lenVal); |
|
| 6648 | + | } |
|
| 6649 | + | ||
| 6650 | + | /// Lower `@relocate(destination, source)` as an overlap-safe byte move. |
|
| 6651 | + | fn lowerRelocate( |
|
| 6652 | + | self: *mut FnLowerer, |
|
| 6653 | + | args: *mut [*ast::Node], |
|
| 6654 | + | ) -> il::Val throws (LowerError) { |
|
| 6655 | + | if args.len <> 2 { |
|
| 6656 | + | throw LowerError::InvalidArgCount; |
|
| 6585 | 6657 | } |
|
| 6586 | - | return try buildSliceValue(self, slice.item, slice.mutable, ptrVal, lenVal, capVal); |
|
| 6658 | + | ||
| 6659 | + | let destinationSlice = emitValToReg(self, try lowerExpr(self, args[0])); |
|
| 6660 | + | let destination = loadSlicePtr(self, destinationSlice); |
|
| 6661 | + | let destinationLen = loadSliceLen(self, destinationSlice); |
|
| 6662 | + | let sourceSlice = emitValToReg(self, try lowerExpr(self, args[1])); |
|
| 6663 | + | let source = loadSlicePtr(self, sourceSlice); |
|
| 6664 | + | let sourceLen = loadSliceLen(self, sourceSlice); |
|
| 6665 | + | ||
| 6666 | + | // The destination must hold every source byte. |
|
| 6667 | + | try emitTrapIfLt(self, il::Type::W32, destinationLen, sourceLen); |
|
| 6668 | + | ||
| 6669 | + | let forwardBlock = try createBlock(self, "relocate.forward"); |
|
| 6670 | + | let backwardBlock = try createBlock(self, "relocate.backward"); |
|
| 6671 | + | let doneBlock = try createBlock(self, "relocate.done"); |
|
| 6672 | + | try emitBrCmp( |
|
| 6673 | + | self, |
|
| 6674 | + | il::CmpOp::Ult, |
|
| 6675 | + | il::Type::W64, |
|
| 6676 | + | il::Val::Reg(destination), |
|
| 6677 | + | il::Val::Reg(source), |
|
| 6678 | + | forwardBlock, |
|
| 6679 | + | backwardBlock, |
|
| 6680 | + | ); |
|
| 6681 | + | ||
| 6682 | + | // Moving toward a lower address cannot overwrite unread source bytes. |
|
| 6683 | + | try switchToAndSeal(self, forwardBlock); |
|
| 6684 | + | try emitByteCopyLoop( |
|
| 6685 | + | self, |
|
| 6686 | + | destination, |
|
| 6687 | + | source, |
|
| 6688 | + | sourceLen, |
|
| 6689 | + | "relocate.forward", |
|
| 6690 | + | ); |
|
| 6691 | + | try emitJmp(self, doneBlock); |
|
| 6692 | + | ||
| 6693 | + | // Moving toward a higher address must copy from the end for overlap safety. |
|
| 6694 | + | try switchToAndSeal(self, backwardBlock); |
|
| 6695 | + | let remainingReg = nextReg(self); |
|
| 6696 | + | let backwardHeader = try createBlockWithParam( |
|
| 6697 | + | self, |
|
| 6698 | + | "relocate.backward", |
|
| 6699 | + | il::Param { value: remainingReg, type: il::Type::W32 }, |
|
| 6700 | + | ); |
|
| 6701 | + | let backwardBody = try createBlock(self, "relocate.backward"); |
|
| 6702 | + | let backwardDone = try createBlock(self, "relocate.backward"); |
|
| 6703 | + | try emitJmpWithArg(self, backwardHeader, sourceLen); |
|
| 6704 | + | ||
| 6705 | + | switchToBlock(self, backwardHeader); |
|
| 6706 | + | try emitBrCmp( |
|
| 6707 | + | self, |
|
| 6708 | + | il::CmpOp::Ult, |
|
| 6709 | + | il::Type::W32, |
|
| 6710 | + | il::Val::Imm(0), |
|
| 6711 | + | il::Val::Reg(remainingReg), |
|
| 6712 | + | backwardBody, |
|
| 6713 | + | backwardDone, |
|
| 6714 | + | ); |
|
| 6715 | + | ||
| 6716 | + | try switchToAndSeal(self, backwardBody); |
|
| 6717 | + | let byteIndex = emitTypedBinOp( |
|
| 6718 | + | self, |
|
| 6719 | + | il::BinOp::Sub, |
|
| 6720 | + | il::Type::W32, |
|
| 6721 | + | il::Val::Reg(remainingReg), |
|
| 6722 | + | il::Val::Imm(1), |
|
| 6723 | + | ); |
|
| 6724 | + | let sourceByte = emitElem(self, 1, source, byteIndex); |
|
| 6725 | + | let byteReg = nextReg(self); |
|
| 6726 | + | emit(self, il::Instr::Load { |
|
| 6727 | + | typ: il::Type::W8, |
|
| 6728 | + | dst: byteReg, |
|
| 6729 | + | src: sourceByte, |
|
| 6730 | + | offset: 0, |
|
| 6731 | + | }); |
|
| 6732 | + | let destinationByte = emitElem(self, 1, destination, byteIndex); |
|
| 6733 | + | emit(self, il::Instr::Store { |
|
| 6734 | + | typ: il::Type::W8, |
|
| 6735 | + | src: il::Val::Reg(byteReg), |
|
| 6736 | + | dst: destinationByte, |
|
| 6737 | + | offset: 0, |
|
| 6738 | + | }); |
|
| 6739 | + | try emitJmpWithArg(self, backwardHeader, byteIndex); |
|
| 6740 | + | ||
| 6741 | + | try sealBlock(self, backwardHeader); |
|
| 6742 | + | try switchToAndSeal(self, backwardDone); |
|
| 6743 | + | try emitJmp(self, doneBlock); |
|
| 6744 | + | ||
| 6745 | + | try switchToAndSeal(self, doneBlock); |
|
| 6746 | + | return il::Val::Undef; |
|
| 6587 | 6747 | } |
|
| 6588 | 6748 | ||
| 6589 | 6749 | /// Lower a `try` expression. |
|
| 6590 | 6750 | fn lowerTry(self: *mut FnLowerer, node: *ast::Node, t: ast::Try) -> il::Val throws (LowerError) { |
|
| 6591 | 6751 | let case ast::NodeValue::Call(callExpr) = t.expr.value else { |
| 6748 | 6908 | let entry = currentBlock(self); |
|
| 6749 | 6909 | ||
| 6750 | 6910 | // First pass: create blocks, resolve error types, and build switch cases. |
|
| 6751 | 6911 | let mut blocks: [BlockId; MAX_CATCH_CLAUSES] = undefined; |
|
| 6752 | 6912 | let mut errTypes: [?resolver::Type; MAX_CATCH_CLAUSES] = undefined; |
|
| 6753 | - | let mut cases: *mut [il::SwitchCase] = &mut []; |
|
| 6913 | + | let mut cases = vec::Vec⟨il::SwitchCase⟩ { data: &mut [], len: 0 }; |
|
| 6754 | 6914 | let mut defaultIdx: ?u32 = nil; |
|
| 6755 | 6915 | ||
| 6756 | 6916 | for clauseNode, i in catches { |
|
| 6757 | 6917 | let case ast::NodeValue::CatchClause(clause) = clauseNode.value |
|
| 6758 | 6918 | else panic "lowerMultiCatch: expected CatchClause"; |
| 6762 | 6922 | ||
| 6763 | 6923 | if let typeNode = clause.typeNode { |
|
| 6764 | 6924 | let errTy = try typeOf(self, typeNode); |
|
| 6765 | 6925 | set errTypes[i] = errTy; |
|
| 6766 | 6926 | ||
| 6767 | - | cases.append(il::SwitchCase { |
|
| 6927 | + | vec::append⟨il::SwitchCase⟩(&mut cases, il::SwitchCase { |
|
| 6768 | 6928 | value: getOrAssignErrorTag(self.low, errTy) as i64, |
|
| 6769 | 6929 | target: *blocks[i], |
|
| 6770 | 6930 | args: &mut [] |
|
| 6771 | 6931 | }, self.allocator); |
|
| 6772 | 6932 | } else { |
| 6785 | 6945 | } |
|
| 6786 | 6946 | emit(self, il::Instr::Switch { |
|
| 6787 | 6947 | val: il::Val::Reg(tagReg), |
|
| 6788 | 6948 | defaultTarget: *defaultTarget, |
|
| 6789 | 6949 | defaultArgs: &mut [], |
|
| 6790 | - | cases |
|
| 6950 | + | cases: vec::viewMut⟨il::SwitchCase⟩(&mut cases), |
|
| 6791 | 6951 | }); |
|
| 6792 | 6952 | ||
| 6793 | 6953 | // Second pass: emit each catch clause body. |
|
| 6794 | 6954 | for clauseNode, i in catches { |
|
| 6795 | 6955 | let case ast::NodeValue::CatchClause(clause) = clauseNode.value |
| 6863 | 7023 | // Now all predecessors of header are known, seal it. |
|
| 6864 | 7024 | try sealBlock(self, header); |
|
| 6865 | 7025 | try switchToAndSeal(self, done); |
|
| 6866 | 7026 | } |
|
| 6867 | 7027 | ||
| 6868 | - | /// Lower `slice.append(val, allocator)`. |
|
| 6869 | - | /// |
|
| 6870 | - | /// Emits inline grow-if-needed logic: |
|
| 6871 | - | /// |
|
| 6872 | - | /// load len, cap from slice header |
|
| 6873 | - | /// if len < cap: jmp @store |
|
| 6874 | - | /// else: jmp @grow |
|
| 6875 | - | /// |
|
| 6876 | - | /// @grow: |
|
| 6877 | - | /// newCap = max(cap * 2, 1) |
|
| 6878 | - | /// call allocator.func(allocator.ctx, newCap * stride, alignment) |
|
| 6879 | - | /// copy old data to new pointer |
|
| 6880 | - | /// update slice ptr and cap |
|
| 6881 | - | /// jmp @store |
|
| 6882 | - | /// |
|
| 6883 | - | /// @store: |
|
| 6884 | - | /// store element at ptr + len * stride |
|
| 6885 | - | /// increment len |
|
| 6886 | - | /// |
|
| 6887 | - | fn lowerSliceAppend(self: *mut FnLowerer, call: ast::Call, elemType: *resolver::Type) -> il::Val throws (LowerError) { |
|
| 6888 | - | let case ast::NodeValue::FieldAccess(access) = call.callee.value |
|
| 6889 | - | else throw LowerError::MissingMetadata; |
|
| 6890 | - | ||
| 6891 | - | // Get the address of the slice header. |
|
| 6892 | - | let sliceVal = try lowerExpr(self, access.parent); |
|
| 6893 | - | let sliceReg = emitValToReg(self, sliceVal); |
|
| 6894 | - | ||
| 6895 | - | // Lower the value to append and the allocator. |
|
| 6896 | - | let elemVal = try lowerExpr(self, call.args[0]); |
|
| 6897 | - | let allocVal = try lowerExpr(self, call.args[1]); |
|
| 6898 | - | let allocReg = emitValToReg(self, allocVal); |
|
| 6899 | - | ||
| 6900 | - | let elemLayout = resolver::getTypeLayout(*elemType); |
|
| 6901 | - | let stride = elemLayout.size; |
|
| 6902 | - | let alignment = elemLayout.alignment; |
|
| 6903 | - | ||
| 6904 | - | // Load current length and capacity. |
|
| 6905 | - | let lenVal = loadSliceLen(self, sliceReg); |
|
| 6906 | - | let capVal = loadSliceCap(self, sliceReg); |
|
| 6907 | - | ||
| 6908 | - | // Branch: if length is smaller than capacity, go to @store else @grow. |
|
| 6909 | - | let storeBlock = try createBlock(self, "append.store"); |
|
| 6910 | - | let growBlock = try createBlock(self, "append.grow"); |
|
| 6911 | - | try emitBrCmp(self, il::CmpOp::Ult, il::Type::W32, lenVal, capVal, storeBlock, growBlock); |
|
| 6912 | - | try switchToAndSeal(self, growBlock); |
|
| 6913 | - | ||
| 6914 | - | // -- @grow block ---------------------------------------------------------- |
|
| 6915 | - | ||
| 6916 | - | // `newCap = max(cap * 2, 1)`. |
|
| 6917 | - | // We are only here when at capacity, so we use `or` with `1` to ensure at least capacity `1`. |
|
| 6918 | - | let doubledVal = emitTypedBinOp(self, il::BinOp::Shl, il::Type::W32, capVal, il::Val::Imm(1)); |
|
| 6919 | - | let newCapVal = emitTypedBinOp(self, il::BinOp::Or, il::Type::W32, doubledVal, il::Val::Imm(1)); |
|
| 6920 | - | ||
| 6921 | - | // Call allocator: `a.func(a.ctx, newCap * stride, alignment)`. |
|
| 6922 | - | let allocFnReg = nextReg(self); |
|
| 6923 | - | emitLoadW64At(self, allocFnReg, allocReg, 0); |
|
| 6924 | - | ||
| 6925 | - | let allocCtxReg = nextReg(self); |
|
| 6926 | - | emitLoadW64At(self, allocCtxReg, allocReg, 8); |
|
| 6927 | - | ||
| 6928 | - | let byteSize = emitTypedBinOp(self, il::BinOp::Mul, il::Type::W32, newCapVal, il::Val::Imm(stride as i64)); |
|
| 6929 | - | let args = try allocVals(self, 3); |
|
| 6930 | - | ||
| 6931 | - | set args[0] = il::Val::Reg(allocCtxReg); |
|
| 6932 | - | set args[1] = byteSize; |
|
| 6933 | - | set args[2] = il::Val::Imm(alignment as i64); |
|
| 6934 | - | ||
| 6935 | - | let newPtrReg = nextReg(self); |
|
| 6936 | - | emit(self, il::Instr::Call { |
|
| 6937 | - | retTy: il::Type::W64, |
|
| 6938 | - | dst: newPtrReg, |
|
| 6939 | - | func: il::Val::Reg(allocFnReg), |
|
| 6940 | - | args, |
|
| 6941 | - | }); |
|
| 6942 | - | ||
| 6943 | - | // Copy old data byte-by-byte. |
|
| 6944 | - | let oldPtrReg = loadSlicePtr(self, sliceReg); |
|
| 6945 | - | let copyBytes = emitTypedBinOp(self, il::BinOp::Mul, il::Type::W32, lenVal, il::Val::Imm(stride as i64)); |
|
| 6946 | - | try emitByteCopyLoop(self, newPtrReg, oldPtrReg, copyBytes, "append"); |
|
| 6947 | - | ||
| 6948 | - | // Update slice header. |
|
| 6949 | - | emitStoreW64At(self, il::Val::Reg(newPtrReg), sliceReg, SLICE_PTR_OFFSET); |
|
| 6950 | - | emitStoreW32At(self, newCapVal, sliceReg, SLICE_CAP_OFFSET); |
|
| 6951 | - | ||
| 6952 | - | try emitJmp(self, storeBlock); |
|
| 6953 | - | try switchToAndSeal(self, storeBlock); |
|
| 6954 | - | ||
| 6955 | - | // -- @store block --------------------------------------------------------- |
|
| 6956 | - | ||
| 6957 | - | // Store element at `ptr + len * stride`. |
|
| 6958 | - | let ptrReg = loadSlicePtr(self, sliceReg); |
|
| 6959 | - | let elemDst = emitElem(self, stride, ptrReg, lenVal); |
|
| 6960 | - | try emitStore(self, elemDst, 0, *elemType, elemVal); |
|
| 6961 | - | ||
| 6962 | - | // Increment len. |
|
| 6963 | - | let newLen = emitTypedBinOp(self, il::BinOp::Add, il::Type::W32, lenVal, il::Val::Imm(1)); |
|
| 6964 | - | emitStoreW32At(self, newLen, sliceReg, SLICE_LEN_OFFSET); |
|
| 6965 | - | ||
| 6966 | - | return il::Val::Reg(sliceReg); |
|
| 6967 | - | } |
|
| 6968 | - | ||
| 6969 | - | /// Lower `slice.delete(index)`. |
|
| 6970 | - | /// |
|
| 6971 | - | /// Bounds-check the index, shift elements after it by one stride |
|
| 6972 | - | /// via a byte-copy loop, and decrement `len`. |
|
| 6973 | - | fn lowerSliceDelete(self: *mut FnLowerer, call: ast::Call, elemType: *resolver::Type) throws (LowerError) { |
|
| 6974 | - | let case ast::NodeValue::FieldAccess(access) = call.callee.value |
|
| 6975 | - | else throw LowerError::MissingMetadata; |
|
| 6976 | - | ||
| 6977 | - | let elemLayout = resolver::getTypeLayout(*elemType); |
|
| 6978 | - | let stride = elemLayout.size; |
|
| 6979 | - | ||
| 6980 | - | // Get slice header address. |
|
| 6981 | - | let sliceVal = try lowerExpr(self, access.parent); |
|
| 6982 | - | let sliceReg = emitValToReg(self, sliceVal); |
|
| 6983 | - | ||
| 6984 | - | // Lower the index argument. |
|
| 6985 | - | let indexVal = try lowerExpr(self, call.args[0]); |
|
| 6986 | - | ||
| 6987 | - | // Load len and bounds-check: index must be smaller than length. |
|
| 6988 | - | let lenVal = loadSliceLen(self, sliceReg); |
|
| 6989 | - | try emitTrapUnlessCmp(self, il::CmpOp::Ult, il::Type::W32, indexVal, lenVal); |
|
| 6990 | - | ||
| 6991 | - | // Compute the destination and source for the shift. |
|
| 6992 | - | let ptrReg = loadSlicePtr(self, sliceReg); |
|
| 6993 | - | let dst = emitElem(self, stride, ptrReg, indexVal); |
|
| 6994 | - | ||
| 6995 | - | // `src = dst + stride`. |
|
| 6996 | - | let src = emitPtrOffset(self, dst, stride as i32); |
|
| 6997 | - | ||
| 6998 | - | // Move `(len - index - 1) * stride`. |
|
| 6999 | - | let tailLen = emitTypedBinOp(self, il::BinOp::Sub, il::Type::W32, lenVal, indexVal); |
|
| 7000 | - | let tailLenMinusOne = emitTypedBinOp(self, il::BinOp::Sub, il::Type::W32, tailLen, il::Val::Imm(1)); |
|
| 7001 | - | let moveBytes = emitTypedBinOp(self, il::BinOp::Mul, il::Type::W32, tailLenMinusOne, il::Val::Imm(stride as i64)); |
|
| 7002 | - | ||
| 7003 | - | // Shift elements left via byte-copy loop. |
|
| 7004 | - | // When deleting the last element, the loop is a no-op. |
|
| 7005 | - | try emitByteCopyLoop(self, dst, src, moveBytes, "delete"); |
|
| 7006 | - | // Decrement length. |
|
| 7007 | - | let newLen = emitTypedBinOp(self, il::BinOp::Sub, il::Type::W32, lenVal, il::Val::Imm(1)); |
|
| 7008 | - | ||
| 7009 | - | emitStoreW32At(self, newLen, sliceReg, SLICE_LEN_OFFSET); |
|
| 7010 | - | } |
|
| 7011 | - | ||
| 7012 | 7028 | /// Lower a call expression, which may be a function call or type constructor. |
|
| 7013 | 7029 | fn lowerCallOrCtor(self: *mut FnLowerer, node: *ast::Node, call: ast::Call) -> il::Val throws (LowerError) { |
|
| 7014 | 7030 | let nodeData = resolver::nodeData(self.low.resolver, node).extra; |
|
| 7015 | 7031 | ||
| 7016 | - | // Check for slice method dispatch. |
|
| 7017 | - | if let case resolver::NodeExtra::SliceAppend { elemType } = nodeData { |
|
| 7018 | - | let concrete = try specializeType(self, *elemType); |
|
| 7019 | - | return try lowerSliceAppend(self, call, &concrete); |
|
| 7020 | - | } |
|
| 7021 | - | if let case resolver::NodeExtra::SliceDelete { elemType } = nodeData { |
|
| 7022 | - | let concrete = try specializeType(self, *elemType); |
|
| 7023 | - | try lowerSliceDelete(self, call, &concrete); |
|
| 7024 | - | return il::Val::Undef; |
|
| 7025 | - | } |
|
| 7026 | 7032 | // Check for trait method dispatch. |
|
| 7027 | 7033 | if let case resolver::NodeExtra::TraitMethodCall { traitInfo, methodIndex } = nodeData { |
|
| 7028 | 7034 | return try lowerTraitMethodCall(self, node, call, traitInfo, methodIndex); |
|
| 7029 | 7035 | } |
|
| 7030 | 7036 | if let case resolver::NodeExtra::GenericBoundMethodCall { |
| 7102 | 7108 | typ: il::Type::W64, |
|
| 7103 | 7109 | dst: fnPtrReg, |
|
| 7104 | 7110 | src: vtableReg, |
|
| 7105 | 7111 | offset: slotOffset, |
|
| 7106 | 7112 | }); |
|
| 7107 | - | let methodFnType = traitInfo.methods[methodIndex].fnType; |
|
| 7113 | + | let methodFnType = traitInfo.methods.data[methodIndex].fnType; |
|
| 7108 | 7114 | ||
| 7109 | 7115 | // Build args: optional return param slot + data pointer (receiver) + user args. |
|
| 7110 | 7116 | let argOffset: u32 = 1 if requiresReturnParam(methodFnType) else 0; |
|
| 7111 | 7117 | let args = try allocVals(self, call.args.len + 1 + argOffset); |
|
| 7112 | 7118 | set args[argOffset] = il::Val::Reg(dataReg); |
| 7246 | 7252 | } |
|
| 7247 | 7253 | let concreteType = try specializeType(self, resolver::Type::Parameter(param)); |
|
| 7248 | 7254 | let inst = resolver::findInstance( |
|
| 7249 | 7255 | self.low.resolver, traitInfo, concreteType |
|
| 7250 | 7256 | ) else throw LowerError::MissingMetadata; |
|
| 7251 | - | let method = &traitInfo.methods[methodIndex]; |
|
| 7257 | + | let method = &traitInfo.methods.data[methodIndex]; |
|
| 7252 | 7258 | let _ = resolver::findInstance( |
|
| 7253 | 7259 | self.low.resolver, method.owner, concreteType |
|
| 7254 | 7260 | ) else throw LowerError::MissingMetadata; |
|
| 7255 | 7261 | let methodSym = inst.methods[methodIndex]; |
|
| 7256 | 7262 | let case resolver::SymbolData::Value { |
| 7642 | 7648 | } else if let generic = try lowerGenericFnValue(self, node) { |
|
| 7643 | 7649 | set val = generic; |
|
| 7644 | 7650 | // First try local variable lookup, then global symbol lookup. |
|
| 7645 | 7651 | } else if let v = lookupLocalVar(self, node) { |
|
| 7646 | 7652 | set val = try useVar(self, v); |
|
| 7647 | - | if self.vars[*v].addressTaken { |
|
| 7653 | + | if self.vars.data[*v].addressTaken { |
|
| 7648 | 7654 | let typ = try typeOf(self, node); |
|
| 7649 | 7655 | let ptr = emitValToReg(self, val); |
|
| 7650 | 7656 | set val = emitRead(self, ptr, 0, typ); |
|
| 7651 | 7657 | } |
|
| 7652 | 7658 | } else { |
| 7727 | 7733 | let mut handled = false; |
|
| 7728 | 7734 | if let case resolver::Type::Array(array) = parentTy { |
|
| 7729 | 7735 | if let case ast::NodeValue::Ident(name) = access.child.value; |
|
| 7730 | 7736 | mem::eq(name, "len") |
|
| 7731 | 7737 | { |
|
| 7732 | - | set val = il::Val::Imm(array.length as i64); |
|
| 7738 | + | let length = resolver::concreteArrayLength(array.length) |
|
| 7739 | + | else throw LowerError::MissingMetadata; |
|
| 7740 | + | set val = il::Val::Imm(length as i64); |
|
| 7733 | 7741 | set handled = true; |
|
| 7734 | 7742 | } |
|
| 7735 | 7743 | } |
|
| 7736 | 7744 | if not handled { |
|
| 7737 | 7745 | set val = try lowerFieldAccess(self, access); |
lib/std/lang/parser.rad
+127 -87
| 2 | 2 | @test export mod tests; |
|
| 3 | 3 | ||
| 4 | 4 | use std::mem; |
|
| 5 | 5 | use std::io; |
|
| 6 | 6 | use std::fmt; |
|
| 7 | + | use std::lang::vec; |
|
| 7 | 8 | use std::lang::alloc; |
|
| 8 | 9 | use std::lang::types; |
|
| 9 | 10 | use std::lang::ast; |
|
| 10 | 11 | use std::lang::strings; |
|
| 11 | 12 | use std::lang::scanner; |
|
| 12 | 13 | ||
| 14 | + | instantiate vec::append⟨*ast::Node⟩, |
|
| 15 | + | vec::viewMut⟨*ast::Node⟩; |
|
| 16 | + | ||
| 13 | 17 | /// Maximum `u32` value. |
|
| 14 | 18 | export constant U32_MAX: u32 = 0xFFFFFFFF; |
|
| 15 | 19 | /// Minimum `i64` value. |
|
| 16 | 20 | export constant I64_MIN: i64 = -0x8000000000000000; |
|
| 17 | 21 | /// Largest magnitude representable by a negative `i64`. |
| 276 | 280 | return node(p, ast::NodeValue::ArrayRepeatLit( |
|
| 277 | 281 | ast::ArrayRepeatLit { item: firstExpr, count } |
|
| 278 | 282 | )); |
|
| 279 | 283 | } |
|
| 280 | 284 | // Regular array literal: `[a, b, ...]`. |
|
| 281 | - | let mut items = ast::nodeSlice(p.arena, 64).append(firstExpr, p.allocator); |
|
| 285 | + | let mut items = ast::nodeVec(p.arena, 64); |
|
| 286 | + | vec::append⟨*ast::Node⟩(&mut items, firstExpr, p.allocator); |
|
| 282 | 287 | ||
| 283 | 288 | while consume(p, scanner::TokenKind::Comma) and not check(p, scanner::TokenKind::RBracket) { |
|
| 284 | 289 | let elem = try parseNormalExpr(p); |
|
| 285 | - | items.append(elem, p.allocator); |
|
| 290 | + | vec::append⟨*ast::Node⟩(&mut items, elem, p.allocator); |
|
| 286 | 291 | } |
|
| 287 | 292 | try expect(p, scanner::TokenKind::RBracket, "expected `]` after array elements"); |
|
| 288 | 293 | ||
| 289 | - | return node(p, ast::NodeValue::ArrayLit(items)); |
|
| 294 | + | return node(p, ast::NodeValue::ArrayLit(vec::viewMut⟨*ast::Node⟩(&mut items))); |
|
| 290 | 295 | } |
|
| 291 | 296 | ||
| 292 | 297 | /// Parse a function call expression. |
|
| 293 | 298 | fn parseCall(p: *mut Parser, callee: *ast::Node) -> *ast::Node |
|
| 294 | 299 | throws (ParseError) |
| 392 | 397 | fn parseGenericArgs(p: *mut Parser) -> *mut [*ast::Node] throws (ParseError) { |
|
| 393 | 398 | try expect(p, scanner::TokenKind::LAngle, "expected left angle before generic arguments"); |
|
| 394 | 399 | if check(p, scanner::TokenKind::RAngle) { |
|
| 395 | 400 | throw failParsing(p, "generic argument list cannot be empty"); |
|
| 396 | 401 | } |
|
| 397 | - | let mut args = ast::nodeSlice(p.arena, 4); |
|
| 402 | + | let mut args = ast::nodeVec(p.arena, 4); |
|
| 398 | 403 | loop { |
|
| 399 | - | args.append(try parseGenericArg(p), p.allocator); |
|
| 404 | + | vec::append⟨*ast::Node⟩(&mut args, try parseGenericArg(p), p.allocator); |
|
| 400 | 405 | if not consume(p, scanner::TokenKind::Comma) { |
|
| 401 | 406 | break; |
|
| 402 | 407 | } |
|
| 403 | 408 | if check(p, scanner::TokenKind::RAngle) { |
|
| 404 | 409 | throw failParsing(p, "expected generic argument after `,`"); |
|
| 405 | 410 | } |
|
| 406 | 411 | } |
|
| 407 | 412 | try expect(p, scanner::TokenKind::RAngle, "expected right angle after generic arguments"); |
|
| 408 | - | return args; |
|
| 413 | + | return vec::viewMut⟨*ast::Node⟩(&mut args); |
|
| 409 | 414 | } |
|
| 410 | 415 | ||
| 411 | 416 | /// Parse generic arguments following a target. |
|
| 412 | 417 | fn parseGenericApply(p: *mut Parser, target: *ast::Node) -> *ast::Node |
|
| 413 | 418 | throws (ParseError) |
| 762 | 767 | { |
|
| 763 | 768 | let leaf = try parseLeaf(p); |
|
| 764 | 769 | return try parsePostfix(p, leaf); |
|
| 765 | 770 | } |
|
| 766 | 771 | ||
| 767 | - | /// Parse a builtin function call like `@sizeOf(T)` or `@alignOf(T)`. |
|
| 772 | + | /// Parse a builtin function call. |
|
| 768 | 773 | fn parseBuiltin(p: *mut Parser) -> *ast::Node |
|
| 769 | 774 | throws (ParseError) |
|
| 770 | 775 | { |
|
| 771 | 776 | // Skip the '@' to get the name. |
|
| 772 | 777 | let ident = p.current.source; |
| 778 | 783 | set kind = ast::Builtin::SizeOf; |
|
| 779 | 784 | } else if ident == "@alignOf" { |
|
| 780 | 785 | set kind = ast::Builtin::AlignOf; |
|
| 781 | 786 | } else if ident == "@sliceOf" { |
|
| 782 | 787 | set kind = ast::Builtin::SliceOf; |
|
| 788 | + | } else if ident == "@relocate" { |
|
| 789 | + | set kind = ast::Builtin::Relocate; |
|
| 783 | 790 | } else { |
|
| 784 | 791 | throw failParsing(p, "unknown builtin"); |
|
| 785 | 792 | } |
|
| 786 | 793 | try expect(p, scanner::TokenKind::LParen, "expected `(` after builtin name"); |
|
| 787 | 794 | ||
| 788 | 795 | // Parse arguments into a list. Use capacity 4 to handle any valid argument count |
|
| 789 | 796 | // plus some extra for error recovery. |
|
| 790 | - | let mut args = ast::nodeSlice(p.arena, 4); |
|
| 797 | + | let mut args = ast::nodeVec(p.arena, 4); |
|
| 791 | 798 | ||
| 792 | - | if kind == ast::Builtin::SliceOf { |
|
| 799 | + | if kind == ast::Builtin::SliceOf or kind == ast::Builtin::Relocate { |
|
| 793 | 800 | // Parse comma-separated expressions until closing paren. |
|
| 794 | 801 | // Argument count validation is done in semantic analysis. |
|
| 795 | 802 | while not check(p, scanner::TokenKind::RParen) { |
|
| 796 | - | args.append(try parseExpr(p), p.allocator); |
|
| 803 | + | vec::append⟨*ast::Node⟩(&mut args, try parseExpr(p), p.allocator); |
|
| 797 | 804 | if not consume(p, scanner::TokenKind::Comma) { |
|
| 798 | 805 | break; |
|
| 799 | 806 | } |
|
| 800 | 807 | } |
|
| 801 | 808 | } else { |
|
| 802 | - | args.append(try parseType(p), p.allocator); |
|
| 809 | + | vec::append⟨*ast::Node⟩(&mut args, try parseType(p), p.allocator); |
|
| 803 | 810 | } |
|
| 804 | 811 | try expect(p, scanner::TokenKind::RParen, "expected `)` after builtin argument"); |
|
| 805 | 812 | ||
| 806 | - | return node(p, ast::NodeValue::BuiltinCall { kind, args }); |
|
| 813 | + | return node(p, ast::NodeValue::BuiltinCall { |
|
| 814 | + | kind, args: vec::viewMut⟨*ast::Node⟩(&mut args), |
|
| 815 | + | }); |
|
| 807 | 816 | } |
|
| 808 | 817 | ||
| 809 | 818 | /// Parse a single expression. |
|
| 810 | 819 | /// |
|
| 811 | 820 | /// Parses unary and binary operators using precedence climbing. |
| 871 | 880 | throw failParsing(p, "expected assignment after `set`"); |
|
| 872 | 881 | } |
|
| 873 | 882 | ||
| 874 | 883 | /// Parse leading attributes and declaration modifiers. |
|
| 875 | 884 | fn parseAttributes(p: *mut Parser) -> ?ast::Attributes { |
|
| 876 | - | let mut attrs = ast::nodeSlice(p.arena, 4); |
|
| 885 | + | let mut attrs = ast::nodeVec(p.arena, 4); |
|
| 877 | 886 | ||
| 878 | 887 | if let attr = tryParseAnnotation(p) { |
|
| 879 | - | attrs.append(attr, p.allocator); |
|
| 888 | + | vec::append⟨*ast::Node⟩(&mut attrs, attr, p.allocator); |
|
| 880 | 889 | } |
|
| 881 | 890 | if consume(p, scanner::TokenKind::Export) { |
|
| 882 | - | attrs.append(nodeAttribute(p, ast::Attribute::Export), p.allocator); |
|
| 891 | + | vec::append⟨*ast::Node⟩(&mut attrs, nodeAttribute(p, ast::Attribute::Export), p.allocator); |
|
| 883 | 892 | } |
|
| 884 | 893 | if consume(p, scanner::TokenKind::Unsafe) { |
|
| 885 | - | attrs.append(nodeAttribute(p, ast::Attribute::Unsafe), p.allocator); |
|
| 894 | + | vec::append⟨*ast::Node⟩(&mut attrs, nodeAttribute(p, ast::Attribute::Unsafe), p.allocator); |
|
| 886 | 895 | } |
|
| 887 | 896 | if attrs.len > 0 { |
|
| 888 | - | return ast::Attributes { list: attrs }; |
|
| 897 | + | return ast::Attributes { list: vec::viewMut⟨*ast::Node⟩(&mut attrs) }; |
|
| 889 | 898 | } |
|
| 890 | 899 | return nil; |
|
| 891 | 900 | } |
|
| 892 | 901 | ||
| 893 | 902 | /// Try to parse an annotation like `@default`. |
| 1036 | 1045 | } |
|
| 1037 | 1046 | } |
|
| 1038 | 1047 | ||
| 1039 | 1048 | /// Parse statements until the specified ending token is encountered. |
|
| 1040 | 1049 | /// |
|
| 1041 | - | /// Adds each parsed statement to the given block's statement list. |
|
| 1042 | - | export fn parseStmtsUntil(p: *mut Parser, end: scanner::TokenKind, blk: *mut ast::Block) |
|
| 1043 | - | throws (ParseError) |
|
| 1044 | - | { |
|
| 1050 | + | /// Adds each parsed statement to the given transient statement vector. |
|
| 1051 | + | export fn parseStmtsUntil( |
|
| 1052 | + | p: *mut Parser, |
|
| 1053 | + | end: scanner::TokenKind, |
|
| 1054 | + | statements: *mut vec::Vec⟨*ast::Node⟩, |
|
| 1055 | + | ) throws (ParseError) { |
|
| 1045 | 1056 | while not check(p, end) { |
|
| 1046 | 1057 | let stmt = try parseStmt(p); |
|
| 1047 | - | blk.statements.append(stmt, p.allocator); |
|
| 1058 | + | vec::append⟨*ast::Node⟩(statements, stmt, p.allocator); |
|
| 1048 | 1059 | ||
| 1049 | 1060 | if check(p, end) or check(p, scanner::TokenKind::Eof) { |
|
| 1050 | 1061 | break; |
|
| 1051 | 1062 | } |
|
| 1052 | 1063 | if not consume(p, scanner::TokenKind::Semicolon) { |
| 1061 | 1072 | /// Parse a block of statements enclosed in curly braces. |
|
| 1062 | 1073 | export fn parseBlock(p: *mut Parser) -> *ast::Node |
|
| 1063 | 1074 | throws (ParseError) |
|
| 1064 | 1075 | { |
|
| 1065 | 1076 | let start = p.current; |
|
| 1066 | - | let mut blk = mkBlock(p, 64); |
|
| 1077 | + | let mut statements = mkStatementVec(p, 64); |
|
| 1067 | 1078 | ||
| 1068 | 1079 | if not consume(p, scanner::TokenKind::LBrace) { |
|
| 1069 | 1080 | throw failParsing(p, "expected `{`"); |
|
| 1070 | 1081 | } |
|
| 1071 | - | try parseStmtsUntil(p, scanner::TokenKind::RBrace, &mut blk); |
|
| 1082 | + | try parseStmtsUntil(p, scanner::TokenKind::RBrace, &mut statements); |
|
| 1072 | 1083 | try expect(p, scanner::TokenKind::RBrace, "expected `}`"); |
|
| 1073 | 1084 | ||
| 1085 | + | let blk = ast::Block { statements: vec::viewMut⟨*ast::Node⟩(&mut statements) }; |
|
| 1074 | 1086 | return node(p, ast::NodeValue::Block(blk)); |
|
| 1075 | 1087 | } |
|
| 1076 | 1088 | ||
| 1077 | - | /// Create an empty block with no statements. |
|
| 1078 | - | fn mkBlock(p: *mut Parser, cap: u32) -> ast::Block { |
|
| 1079 | - | return ast::Block { statements: ast::nodeSlice(p.arena, cap) }; |
|
| 1089 | + | /// Create an empty transient statement vector with the requested capacity. |
|
| 1090 | + | fn mkStatementVec(p: *mut Parser, capacity: u32) -> vec::Vec⟨*ast::Node⟩ { |
|
| 1091 | + | return ast::nodeVec(p.arena, capacity); |
|
| 1080 | 1092 | } |
|
| 1081 | 1093 | ||
| 1082 | 1094 | /// Create a block containing a single statement node. |
|
| 1083 | 1095 | fn mkBlockWith(p: *mut Parser, node: *ast::Node) -> ast::Block { |
|
| 1084 | - | let stmts = ast::nodeSlice(p.arena, 1).append(node, p.allocator); |
|
| 1085 | - | return ast::Block { statements: stmts }; |
|
| 1096 | + | let mut statements = ast::nodeVec(p.arena, 1); |
|
| 1097 | + | vec::append⟨*ast::Node⟩(&mut statements, node, p.allocator); |
|
| 1098 | + | return ast::Block { statements: vec::viewMut⟨*ast::Node⟩(&mut statements) }; |
|
| 1086 | 1099 | } |
|
| 1087 | 1100 | ||
| 1088 | 1101 | /// Parse the branch that follows `else` in let-else style constructs. |
|
| 1089 | 1102 | /// |
|
| 1090 | 1103 | /// Allows either a block, a single statement like `return`, |
| 1433 | 1446 | try expect(p, scanner::TokenKind::Try, "expected `try`"); |
|
| 1434 | 1447 | ||
| 1435 | 1448 | let shouldPanic = consume(p, scanner::TokenKind::Bang); |
|
| 1436 | 1449 | let returnsOptional = consume(p, scanner::TokenKind::Question); |
|
| 1437 | 1450 | let expr = try parseUnaryExpr(p); |
|
| 1438 | - | let mut catches = ast::nodeSlice(p.arena, 4); |
|
| 1451 | + | let mut catches = ast::nodeVec(p.arena, 4); |
|
| 1439 | 1452 | ||
| 1440 | 1453 | while consume(p, scanner::TokenKind::Catch) { |
|
| 1441 | 1454 | let mut binding: ?*ast::Node = nil; |
|
| 1442 | 1455 | let mut typeNode: ?*ast::Node = nil; |
|
| 1443 | 1456 |
| 1454 | 1467 | } |
|
| 1455 | 1468 | let body = try parseBlock(p); |
|
| 1456 | 1469 | let clause = node(p, ast::NodeValue::CatchClause( |
|
| 1457 | 1470 | ast::CatchClause { binding, typeNode, body } |
|
| 1458 | 1471 | )); |
|
| 1459 | - | catches.append(clause, p.allocator); |
|
| 1472 | + | vec::append⟨*ast::Node⟩(&mut catches, clause, p.allocator); |
|
| 1460 | 1473 | } |
|
| 1461 | - | return node(p, ast::NodeValue::Try( |
|
| 1462 | - | ast::Try { expr, catches, shouldPanic, returnsOptional } |
|
| 1463 | - | )); |
|
| 1474 | + | return node(p, ast::NodeValue::Try(ast::Try { |
|
| 1475 | + | expr, |
|
| 1476 | + | catches: vec::viewMut⟨*ast::Node⟩(&mut catches), |
|
| 1477 | + | shouldPanic, |
|
| 1478 | + | returnsOptional, |
|
| 1479 | + | })); |
|
| 1464 | 1480 | } |
|
| 1465 | 1481 | ||
| 1466 | 1482 | /// Parse an `if` expression, with optional `else` or `else if` clauses. |
|
| 1467 | 1483 | /// |
|
| 1468 | 1484 | /// The `else if` construct is handled by creating a recursive structure: |
| 1536 | 1552 | try expect(p, scanner::TokenKind::Match, "expected `match`"); |
|
| 1537 | 1553 | ||
| 1538 | 1554 | let subject = try parseCond(p); |
|
| 1539 | 1555 | try expect(p, scanner::TokenKind::LBrace, "expected `{` before match prongs"); |
|
| 1540 | 1556 | ||
| 1541 | - | let mut prongs = ast::nodeSlice(p.arena, 128); |
|
| 1557 | + | let mut prongs = ast::nodeVec(p.arena, 128); |
|
| 1542 | 1558 | while not check(p, scanner::TokenKind::RBrace) and |
|
| 1543 | 1559 | not check(p, scanner::TokenKind::Eof) // TODO: We shouldn't have to manually check for EOF. |
|
| 1544 | 1560 | { |
|
| 1545 | 1561 | let prongNode = try parseMatchProng(p); |
|
| 1546 | - | prongs.append(prongNode, p.allocator); |
|
| 1562 | + | vec::append⟨*ast::Node⟩(&mut prongs, prongNode, p.allocator); |
|
| 1547 | 1563 | consume(p, scanner::TokenKind::Comma); |
|
| 1548 | 1564 | } |
|
| 1549 | 1565 | try expect(p, scanner::TokenKind::RBrace, "expected `}` after match prongs"); |
|
| 1550 | 1566 | ||
| 1551 | - | return node(p, ast::NodeValue::Match( |
|
| 1552 | - | ast::Match { subject, prongs } |
|
| 1553 | - | )); |
|
| 1567 | + | return node(p, ast::NodeValue::Match(ast::Match { |
|
| 1568 | + | subject, prongs: vec::viewMut⟨*ast::Node⟩(&mut prongs), |
|
| 1569 | + | })); |
|
| 1554 | 1570 | } |
|
| 1555 | 1571 | ||
| 1556 | 1572 | /// Parse a single `match` prong. |
|
| 1557 | 1573 | fn parseMatchProng(p: *mut Parser) -> *ast::Node |
|
| 1558 | 1574 | throws (ParseError) |
|
| 1559 | 1575 | { |
|
| 1560 | 1576 | let mut guard: ?*ast::Node = nil; |
|
| 1561 | 1577 | ||
| 1562 | 1578 | // Case prong: `case <pattern>, ... if <guard> => <body>`. |
|
| 1563 | 1579 | if consume(p, scanner::TokenKind::Case) { |
|
| 1564 | - | let mut patterns = ast::nodeSlice(p.arena, 16); |
|
| 1580 | + | let mut patterns = ast::nodeVec(p.arena, 16); |
|
| 1565 | 1581 | loop { |
|
| 1566 | 1582 | let pattern = try parseMatchPattern(p); |
|
| 1567 | - | patterns.append(pattern, p.allocator); |
|
| 1583 | + | vec::append⟨*ast::Node⟩(&mut patterns, pattern, p.allocator); |
|
| 1568 | 1584 | ||
| 1569 | 1585 | if not consume(p, scanner::TokenKind::Comma) { |
|
| 1570 | 1586 | break; |
|
| 1571 | 1587 | } |
|
| 1572 | 1588 | // After a comma, check for tokens that start a new prong. |
| 1579 | 1595 | set guard = try parseCond(p); |
|
| 1580 | 1596 | } |
|
| 1581 | 1597 | try expect(p, scanner::TokenKind::FatArrow, "expected `=>` after case pattern"); |
|
| 1582 | 1598 | let body = try parseStmt(p); |
|
| 1583 | 1599 | ||
| 1584 | - | return node(p, ast::NodeValue::MatchProng( |
|
| 1585 | - | ast::MatchProng { arm: ast::ProngArm::Case(patterns), guard, body } |
|
| 1586 | - | )); |
|
| 1600 | + | return node(p, ast::NodeValue::MatchProng(ast::MatchProng { |
|
| 1601 | + | arm: ast::ProngArm::Case(vec::viewMut⟨*ast::Node⟩(&mut patterns)), |
|
| 1602 | + | guard, |
|
| 1603 | + | body, |
|
| 1604 | + | })); |
|
| 1587 | 1605 | } |
|
| 1588 | 1606 | // Else prong: `else if <guard> => <body>`. |
|
| 1589 | 1607 | if consume(p, scanner::TokenKind::Else) { |
|
| 1590 | 1608 | if consume(p, scanner::TokenKind::If) { |
|
| 1591 | 1609 | set guard = try parseCond(p); |
| 1663 | 1681 | ) -> *mut [*ast::Node] |
|
| 1664 | 1682 | throws (ParseError) |
|
| 1665 | 1683 | { |
|
| 1666 | 1684 | let terminator = scanner::TokenKind::RBrace if mode == RecordFieldMode::Labeled |
|
| 1667 | 1685 | else scanner::TokenKind::RParen; |
|
| 1668 | - | let mut fields = ast::nodeSlice(p.arena, MAX_RECORD_FIELDS); |
|
| 1686 | + | let mut fields = ast::nodeVec(p.arena, MAX_RECORD_FIELDS); |
|
| 1669 | 1687 | while not check(p, terminator) { |
|
| 1670 | 1688 | let mut recordField: ast::NodeValue = undefined; |
|
| 1671 | 1689 | match mode { |
|
| 1672 | 1690 | case RecordFieldMode::Labeled => { |
|
| 1673 | 1691 | // Allow optional `let` keyword before field name. |
| 1692 | 1710 | set recordField = ast::NodeValue::RecordField { |
|
| 1693 | 1711 | field: nil, type, value: nil, |
|
| 1694 | 1712 | }; |
|
| 1695 | 1713 | } |
|
| 1696 | 1714 | } |
|
| 1697 | - | fields.append(node(p, recordField), p.allocator); |
|
| 1715 | + | vec::append⟨*ast::Node⟩(&mut fields, node(p, recordField), p.allocator); |
|
| 1698 | 1716 | ||
| 1699 | 1717 | if not consume(p, scanner::TokenKind::Comma) { |
|
| 1700 | 1718 | break; |
|
| 1701 | 1719 | } |
|
| 1702 | 1720 | } |
|
| 1703 | 1721 | try expect(p, terminator, "expected closing delimiter after record fields"); |
|
| 1704 | 1722 | ||
| 1705 | - | return fields; |
|
| 1723 | + | return vec::viewMut⟨*ast::Node⟩(&mut fields); |
|
| 1706 | 1724 | } |
|
| 1707 | 1725 | ||
| 1708 | 1726 | /// Parse an optional generic parameter list. |
|
| 1709 | 1727 | fn parseGenericParams(p: *mut Parser) -> *mut [*ast::Node] throws (ParseError) { |
|
| 1710 | - | let mut params = ast::nodeSlice(p.arena, 4); |
|
| 1728 | + | let mut params = ast::nodeVec(p.arena, 4); |
|
| 1711 | 1729 | if not consume(p, scanner::TokenKind::LAngle) { |
|
| 1712 | - | return params; |
|
| 1730 | + | return vec::viewMut⟨*ast::Node⟩(&mut params); |
|
| 1713 | 1731 | } |
|
| 1714 | 1732 | if check(p, scanner::TokenKind::RAngle) { |
|
| 1715 | 1733 | throw failParsing(p, "generic parameter list cannot be empty"); |
|
| 1716 | 1734 | } |
|
| 1717 | 1735 | loop { |
| 1731 | 1749 | let bounds = try parseDerives(p); |
|
| 1732 | 1750 | set param = node(p, ast::NodeValue::GenericParam( |
|
| 1733 | 1751 | ast::GenericParam::Type { name, bounds } |
|
| 1734 | 1752 | )); |
|
| 1735 | 1753 | } |
|
| 1736 | - | params.append(param, p.allocator); |
|
| 1754 | + | vec::append⟨*ast::Node⟩(&mut params, param, p.allocator); |
|
| 1737 | 1755 | if not consume(p, scanner::TokenKind::Comma) { |
|
| 1738 | 1756 | break; |
|
| 1739 | 1757 | } |
|
| 1740 | 1758 | if check(p, scanner::TokenKind::RAngle) { |
|
| 1741 | 1759 | throw failParsing(p, "expected generic parameter after `,`"); |
|
| 1742 | 1760 | } |
|
| 1743 | 1761 | } |
|
| 1744 | 1762 | try expect(p, scanner::TokenKind::RAngle, "expected right angle after generic parameters"); |
|
| 1745 | - | return params; |
|
| 1763 | + | return vec::viewMut⟨*ast::Node⟩(&mut params); |
|
| 1746 | 1764 | } |
|
| 1747 | 1765 | ||
| 1748 | 1766 | /// Parse an optional derives list (`: Trait + Trait`). |
|
| 1749 | 1767 | fn parseDerives(p: *mut Parser) -> *mut [*ast::Node] throws (ParseError) { |
|
| 1750 | - | let mut derives = ast::nodeSlice(p.arena, 4); |
|
| 1768 | + | let mut derives = ast::nodeVec(p.arena, 4); |
|
| 1751 | 1769 | ||
| 1752 | 1770 | if not consume(p, scanner::TokenKind::Colon) { |
|
| 1753 | - | return derives; |
|
| 1771 | + | return vec::viewMut⟨*ast::Node⟩(&mut derives); |
|
| 1754 | 1772 | } |
|
| 1755 | 1773 | loop { |
|
| 1756 | 1774 | let t = try parseTypePath(p); |
|
| 1757 | - | derives.append(t, p.allocator); |
|
| 1775 | + | vec::append⟨*ast::Node⟩(&mut derives, t, p.allocator); |
|
| 1758 | 1776 | ||
| 1759 | 1777 | if not consume(p, scanner::TokenKind::Plus) { |
|
| 1760 | 1778 | break; |
|
| 1761 | 1779 | } |
|
| 1762 | 1780 | } |
|
| 1763 | - | return derives; |
|
| 1781 | + | return vec::viewMut⟨*ast::Node⟩(&mut derives); |
|
| 1764 | 1782 | } |
|
| 1765 | 1783 | ||
| 1766 | 1784 | /// Parse a single record literal field. |
|
| 1767 | 1785 | /// Can be either labeled, or shorthand. |
|
| 1768 | 1786 | fn parseRecordLitField(p: *mut Parser) -> *ast::Node |
| 1786 | 1804 | /// Eg. `{ x: 1, y: 2 }` |
|
| 1787 | 1805 | /// Eg. `{ x: 1, .. }` |
|
| 1788 | 1806 | fn parseRecordLit(p: *mut Parser, typeName: ?*ast::Node) -> *ast::Node |
|
| 1789 | 1807 | throws (ParseError) |
|
| 1790 | 1808 | { |
|
| 1791 | - | let mut fields = ast::nodeSlice(p.arena, MAX_RECORD_FIELDS); |
|
| 1809 | + | let mut fields = ast::nodeVec(p.arena, MAX_RECORD_FIELDS); |
|
| 1792 | 1810 | let mut ignoreRest = false; |
|
| 1793 | 1811 | try expect(p, scanner::TokenKind::LBrace, "expected `{` to begin record literal"); |
|
| 1794 | 1812 | ||
| 1795 | 1813 | while not check(p, scanner::TokenKind::RBrace) { |
|
| 1796 | 1814 | // Check for `..` to ignore remaining fields. |
|
| 1797 | 1815 | if consume(p, scanner::TokenKind::DotDot) { |
|
| 1798 | 1816 | set ignoreRest = true; |
|
| 1799 | 1817 | break; |
|
| 1800 | 1818 | } |
|
| 1801 | 1819 | let field = try parseRecordLitField(p); |
|
| 1802 | - | fields.append(field, p.allocator); |
|
| 1820 | + | vec::append⟨*ast::Node⟩(&mut fields, field, p.allocator); |
|
| 1803 | 1821 | ||
| 1804 | 1822 | if not consume(p, scanner::TokenKind::Comma) { |
|
| 1805 | 1823 | break; |
|
| 1806 | 1824 | } |
|
| 1807 | 1825 | } |
|
| 1808 | 1826 | try expect(p, scanner::TokenKind::RBrace, "expected `}` to end record literal"); |
|
| 1809 | 1827 | ||
| 1810 | - | return node(p, ast::NodeValue::RecordLit( |
|
| 1811 | - | ast::RecordLit { typeName, fields, ignoreRest } |
|
| 1812 | - | )); |
|
| 1828 | + | return node(p, ast::NodeValue::RecordLit(ast::RecordLit { |
|
| 1829 | + | typeName, |
|
| 1830 | + | fields: vec::viewMut⟨*ast::Node⟩(&mut fields), |
|
| 1831 | + | ignoreRest, |
|
| 1832 | + | })); |
|
| 1813 | 1833 | } |
|
| 1814 | 1834 | ||
| 1815 | 1835 | /// Parse a named record declaration. |
|
| 1816 | 1836 | /// `record Point { x: i32, y: i32 }`, or `record Pair(i32, i32);` |
|
| 1817 | 1837 | fn parseRecordDecl(p: *mut Parser, attrs: ?ast::Attributes) -> *ast::Node |
| 1849 | 1869 | let params = try parseGenericParams(p); |
|
| 1850 | 1870 | let derives = try parseDerives(p); |
|
| 1851 | 1871 | ||
| 1852 | 1872 | try expect(p, scanner::TokenKind::LBrace, "expected `{` before union body"); |
|
| 1853 | 1873 | ||
| 1854 | - | let mut variants = ast::nodeSlice(p.arena, 128); |
|
| 1874 | + | let mut variants = ast::nodeVec(p.arena, 128); |
|
| 1855 | 1875 | while not check(p, scanner::TokenKind::RBrace) { |
|
| 1856 | 1876 | // Allow optional `case` keyword before variant name. |
|
| 1857 | 1877 | consume(p, scanner::TokenKind::Case); |
|
| 1858 | 1878 | ||
| 1859 | 1879 | let variantName = try parseIdent(p, "expected variant name"); |
| 1877 | 1897 | let variant = node(p, ast::NodeValue::UnionDeclVariant( |
|
| 1878 | 1898 | ast::UnionDeclVariant { |
|
| 1879 | 1899 | name: variantName, index: variants.len as u32, value: explicitValue, type: payloadType, |
|
| 1880 | 1900 | } |
|
| 1881 | 1901 | )); |
|
| 1882 | - | variants.append(variant, p.allocator); |
|
| 1902 | + | vec::append⟨*ast::Node⟩(&mut variants, variant, p.allocator); |
|
| 1883 | 1903 | ||
| 1884 | 1904 | if not consume(p, scanner::TokenKind::Comma) { |
|
| 1885 | 1905 | break; |
|
| 1886 | 1906 | } |
|
| 1887 | 1907 | } |
|
| 1888 | 1908 | try expect(p, scanner::TokenKind::RBrace, "expected `}`"); |
|
| 1889 | 1909 | ||
| 1890 | - | return node(p, ast::NodeValue::UnionDecl( |
|
| 1891 | - | ast::UnionDecl { name, params, variants, attrs, derives } |
|
| 1892 | - | )); |
|
| 1910 | + | return node(p, ast::NodeValue::UnionDecl(ast::UnionDecl { |
|
| 1911 | + | name, |
|
| 1912 | + | params, |
|
| 1913 | + | variants: vec::viewMut⟨*ast::Node⟩(&mut variants), |
|
| 1914 | + | attrs, |
|
| 1915 | + | derives, |
|
| 1916 | + | })); |
|
| 1893 | 1917 | } |
|
| 1894 | 1918 | ||
| 1895 | 1919 | /// Parse a function parameter. |
|
| 1896 | 1920 | fn parseFnParam(p: *mut Parser) -> *ast::Node |
|
| 1897 | 1921 | throws (ParseError) |
| 1908 | 1932 | /// Parse an optional `throws` clause and return the collected type list. |
|
| 1909 | 1933 | fn parseThrowList(p: *mut Parser) -> *mut [*ast::Node] |
|
| 1910 | 1934 | throws (ParseError) |
|
| 1911 | 1935 | { |
|
| 1912 | 1936 | if not consume(p, scanner::TokenKind::Throws) { |
|
| 1913 | - | return ast::nodeSlice(p.arena, 0); |
|
| 1937 | + | return &mut []; |
|
| 1914 | 1938 | } |
|
| 1915 | 1939 | return try parseList( |
|
| 1916 | 1940 | p, |
|
| 1917 | 1941 | scanner::TokenKind::LParen, |
|
| 1918 | 1942 | scanner::TokenKind::RParen, |
| 1946 | 1970 | /// Parse a function signature following the function name. |
|
| 1947 | 1971 | fn parseFnTypeSig(p: *mut Parser) -> ast::FnSig |
|
| 1948 | 1972 | throws (ParseError) |
|
| 1949 | 1973 | { |
|
| 1950 | 1974 | try expect(p, scanner::TokenKind::LParen, "expected `(` after function name"); |
|
| 1951 | - | let mut params = ast::nodeSlice(p.arena, 8); |
|
| 1975 | + | let mut params = ast::nodeVec(p.arena, 8); |
|
| 1952 | 1976 | ||
| 1953 | 1977 | while not check(p, scanner::TokenKind::RParen) { |
|
| 1954 | 1978 | let param = try parseFnParam(p); |
|
| 1955 | - | params.append(param, p.allocator); |
|
| 1979 | + | vec::append⟨*ast::Node⟩(&mut params, param, p.allocator); |
|
| 1956 | 1980 | ||
| 1957 | 1981 | if not consume(p, scanner::TokenKind::Comma) { |
|
| 1958 | 1982 | break; |
|
| 1959 | 1983 | } |
|
| 1960 | 1984 | } |
| 1964 | 1988 | if consume(p, scanner::TokenKind::Arrow) { |
|
| 1965 | 1989 | set returnType = try parseType(p); |
|
| 1966 | 1990 | } |
|
| 1967 | 1991 | let throwList = try parseThrowList(p); |
|
| 1968 | 1992 | ||
| 1969 | - | return ast::FnSig { params, returnType, throwList }; |
|
| 1993 | + | return ast::FnSig { |
|
| 1994 | + | params: vec::viewMut⟨*ast::Node⟩(&mut params), |
|
| 1995 | + | returnType, |
|
| 1996 | + | throwList, |
|
| 1997 | + | }; |
|
| 1970 | 1998 | } |
|
| 1971 | 1999 | ||
| 1972 | 2000 | /// Parse a function declaration. |
|
| 1973 | 2001 | fn parseFnDecl(p: *mut Parser, attrs: ?ast::Attributes) -> *ast::Node |
|
| 1974 | 2002 | throws (ParseError) |
| 1987 | 2015 | ||
| 1988 | 2016 | if consume(p, scanner::TokenKind::Semicolon) { |
|
| 1989 | 2017 | if let a = attrs; ast::attributesContains(&a, ast::Attribute::Extern) { |
|
| 1990 | 2018 | // Keep existing attributes unchanged. |
|
| 1991 | 2019 | } else { |
|
| 1992 | - | let mut list = ast::nodeSlice(p.arena, 4); |
|
| 2020 | + | let mut list = ast::nodeVec(p.arena, 4); |
|
| 1993 | 2021 | if let a = attrs { |
|
| 1994 | 2022 | for i in 0..a.list.len { |
|
| 1995 | - | list.append(a.list[i], p.allocator); |
|
| 2023 | + | vec::append⟨*ast::Node⟩(&mut list, a.list[i], p.allocator); |
|
| 1996 | 2024 | } |
|
| 1997 | 2025 | } |
|
| 1998 | 2026 | let attrNode = nodeAttribute(p, ast::Attribute::Extern); |
|
| 1999 | - | list.append(attrNode, p.allocator); |
|
| 2000 | - | set fnAttrs = ast::Attributes { list }; |
|
| 2027 | + | vec::append⟨*ast::Node⟩(&mut list, attrNode, p.allocator); |
|
| 2028 | + | set fnAttrs = ast::Attributes { list: vec::viewMut⟨*ast::Node⟩(&mut list) }; |
|
| 2001 | 2029 | } |
|
| 2002 | 2030 | } else { |
|
| 2003 | 2031 | set body = try parseBlock(p); |
|
| 2004 | 2032 | } |
|
| 2005 | 2033 | return node(p, ast::NodeValue::FnDecl( |
| 2343 | 2371 | export fn parseModule(p: *mut Parser) -> *mut ast::Node |
|
| 2344 | 2372 | throws (ParseError) |
|
| 2345 | 2373 | { |
|
| 2346 | 2374 | advance(p); // Set the parser up with a first token. |
|
| 2347 | 2375 | ||
| 2348 | - | let mut blk = mkBlock(p, 512); |
|
| 2349 | - | try parseStmtsUntil(p, scanner::TokenKind::Eof, &mut blk); |
|
| 2376 | + | let mut statements = mkStatementVec(p, 512); |
|
| 2377 | + | try parseStmtsUntil(p, scanner::TokenKind::Eof, &mut statements); |
|
| 2350 | 2378 | consume(p, scanner::TokenKind::Eof); |
|
| 2351 | 2379 | ||
| 2380 | + | let blk = ast::Block { statements: vec::viewMut⟨*ast::Node⟩(&mut statements) }; |
|
| 2352 | 2381 | return node(p, ast::NodeValue::Block(blk)); |
|
| 2353 | 2382 | } |
|
| 2354 | 2383 | ||
| 2355 | 2384 | /// Consume a token of the given kind if present. |
|
| 2356 | 2385 | export fn consume(p: *mut Parser, kind: scanner::TokenKind) -> bool { |
| 2386 | 2415 | } |
|
| 2387 | 2416 | ||
| 2388 | 2417 | /// Parse one or more explicit specialization roots. |
|
| 2389 | 2418 | fn parseInstantiate(p: *mut Parser) -> *ast::Node throws (ParseError) { |
|
| 2390 | 2419 | try expect(p, scanner::TokenKind::Instantiate, "expected `instantiate`"); |
|
| 2391 | - | let mut applications = ast::nodeSlice(p.arena, 4); |
|
| 2420 | + | let mut applications = ast::nodeVec(p.arena, 4); |
|
| 2392 | 2421 | loop { |
|
| 2393 | 2422 | let target = try parseTypePath(p); |
|
| 2394 | 2423 | if not check(p, scanner::TokenKind::LAngle) { |
|
| 2395 | 2424 | throw failParsing(p, "`instantiate` requires a generic application"); |
|
| 2396 | 2425 | } |
|
| 2397 | - | applications.append(try parseGenericApply(p, target), p.allocator); |
|
| 2426 | + | vec::append⟨*ast::Node⟩(&mut applications, try parseGenericApply(p, target), p.allocator); |
|
| 2398 | 2427 | if not consume(p, scanner::TokenKind::Comma) { |
|
| 2399 | 2428 | break; |
|
| 2400 | 2429 | } |
|
| 2401 | 2430 | } |
|
| 2402 | - | return node(p, ast::NodeValue::Instantiate(applications)); |
|
| 2431 | + | return node(p, ast::NodeValue::Instantiate( |
|
| 2432 | + | vec::viewMut⟨*ast::Node⟩(&mut applications) |
|
| 2433 | + | )); |
|
| 2403 | 2434 | } |
|
| 2404 | 2435 | ||
| 2405 | 2436 | /// Parse a trait declaration. |
|
| 2406 | 2437 | /// Syntax: `trait Name { fn (*Trait) method(...) -> T; ... }` |
|
| 2407 | 2438 | fn parseTraitDecl(p: *mut Parser, attrs: ?ast::Attributes) -> *ast::Node |
| 2410 | 2441 | try expect(p, scanner::TokenKind::Trait, "expected `trait`"); |
|
| 2411 | 2442 | let name = try parseIdent(p, "expected trait name"); |
|
| 2412 | 2443 | let supertraits = try parseDerives(p); |
|
| 2413 | 2444 | try expect(p, scanner::TokenKind::LBrace, "expected `{` after trait name"); |
|
| 2414 | 2445 | ||
| 2415 | - | let mut methods = ast::nodeSlice(p.arena, ast::MAX_TRAIT_METHODS); |
|
| 2446 | + | let mut methods = ast::nodeVec(p.arena, ast::MAX_TRAIT_METHODS); |
|
| 2416 | 2447 | while not check(p, scanner::TokenKind::RBrace) and |
|
| 2417 | 2448 | not check(p, scanner::TokenKind::Eof) |
|
| 2418 | 2449 | { |
|
| 2419 | 2450 | let method = try parseTraitMethodSig(p); |
|
| 2420 | - | methods.append(method, p.allocator); |
|
| 2451 | + | vec::append⟨*ast::Node⟩(&mut methods, method, p.allocator); |
|
| 2421 | 2452 | } |
|
| 2422 | 2453 | try expect(p, scanner::TokenKind::RBrace, "expected `}` after trait methods"); |
|
| 2423 | 2454 | ||
| 2424 | - | return node(p, ast::NodeValue::TraitDecl { name, supertraits, methods, attrs }); |
|
| 2455 | + | return node(p, ast::NodeValue::TraitDecl { |
|
| 2456 | + | name, |
|
| 2457 | + | supertraits, |
|
| 2458 | + | methods: vec::viewMut⟨*ast::Node⟩(&mut methods), |
|
| 2459 | + | attrs, |
|
| 2460 | + | }); |
|
| 2425 | 2461 | } |
|
| 2426 | 2462 | ||
| 2427 | 2463 | /// Parse a trait method signature. |
|
| 2428 | 2464 | /// Syntax: `fn (*Trait) fnord(<params>) -> ReturnType;` |
|
| 2429 | 2465 | fn parseTraitMethodSig(p: *mut Parser) -> *ast::Node |
| 2456 | 2492 | let traitName = try parseTypePath(p); |
|
| 2457 | 2493 | try expect(p, scanner::TokenKind::For, "expected `for` after trait name"); |
|
| 2458 | 2494 | let targetType = try parseType(p); |
|
| 2459 | 2495 | try expect(p, scanner::TokenKind::LBrace, "expected `{` after target type"); |
|
| 2460 | 2496 | ||
| 2461 | - | let mut methods = ast::nodeSlice(p.arena, ast::MAX_TRAIT_METHODS); |
|
| 2497 | + | let mut methods = ast::nodeVec(p.arena, ast::MAX_TRAIT_METHODS); |
|
| 2462 | 2498 | ||
| 2463 | 2499 | while not check(p, scanner::TokenKind::RBrace) and |
|
| 2464 | 2500 | not check(p, scanner::TokenKind::Eof) |
|
| 2465 | 2501 | { |
|
| 2466 | 2502 | let attrs = parseAttributes(p); |
|
| 2467 | 2503 | try expect(p, scanner::TokenKind::Fn, "expected `fn`"); |
|
| 2468 | 2504 | let method = try parseMethodDecl(p, attrs); |
|
| 2469 | 2505 | ||
| 2470 | - | methods.append(method, p.allocator); |
|
| 2506 | + | vec::append⟨*ast::Node⟩(&mut methods, method, p.allocator); |
|
| 2471 | 2507 | } |
|
| 2472 | 2508 | try expect(p, scanner::TokenKind::RBrace, "expected `}` after instance methods"); |
|
| 2473 | 2509 | ||
| 2474 | - | return node(p, ast::NodeValue::InstanceDecl { traitName, targetType, methods }); |
|
| 2510 | + | return node(p, ast::NodeValue::InstanceDecl { |
|
| 2511 | + | traitName, |
|
| 2512 | + | targetType, |
|
| 2513 | + | methods: vec::viewMut⟨*ast::Node⟩(&mut methods), |
|
| 2514 | + | }); |
|
| 2475 | 2515 | } |
|
| 2476 | 2516 | ||
| 2477 | 2517 | /// Parse a method declaration with a receiver. |
|
| 2478 | 2518 | /// Syntax: `fn (t: *mut Type) fnord(<params>) -> ReturnType { body }` |
|
| 2479 | 2519 | /// |
| 2505 | 2545 | open: scanner::TokenKind, |
|
| 2506 | 2546 | close: scanner::TokenKind, |
|
| 2507 | 2547 | parseItem: fn (*mut Parser) -> *ast::Node throws (ParseError) |
|
| 2508 | 2548 | ) -> *mut [*ast::Node] throws (ParseError) { |
|
| 2509 | 2549 | try expect(p, open, listExpectMessage(open)); |
|
| 2510 | - | let mut items = ast::nodeSlice(p.arena, 8); |
|
| 2550 | + | let mut items = ast::nodeVec(p.arena, 8); |
|
| 2511 | 2551 | ||
| 2512 | 2552 | while not check(p, close) { |
|
| 2513 | 2553 | let item = try parseItem(p); |
|
| 2514 | - | items.append(item, p.allocator); |
|
| 2554 | + | vec::append⟨*ast::Node⟩(&mut items, item, p.allocator); |
|
| 2515 | 2555 | ||
| 2516 | 2556 | if not consume(p, scanner::TokenKind::Comma) { |
|
| 2517 | 2557 | break; |
|
| 2518 | 2558 | } |
|
| 2519 | 2559 | } |
|
| 2520 | 2560 | try expect(p, close, listExpectMessage(close)); |
|
| 2521 | 2561 | ||
| 2522 | - | return items; |
|
| 2562 | + | return vec::viewMut⟨*ast::Node⟩(&mut items); |
|
| 2523 | 2563 | } |
lib/std/lang/resolver.rad
+394 -359
| 13 | 13 | // TODO: `ensureNominalResolved` should just run when you call `typeFor`. |
|
| 14 | 14 | // TODO: Have different types for positional vs. named field records. |
|
| 15 | 15 | ||
| 16 | 16 | use std::mem; |
|
| 17 | 17 | use std::io; |
|
| 18 | + | use std::lang::vec; |
|
| 18 | 19 | use std::lang::alloc; |
|
| 19 | 20 | use std::lang::types; |
|
| 20 | 21 | use std::lang::ast; |
|
| 21 | 22 | use std::lang::parser; |
|
| 22 | 23 | use std::lang::module; |
| 76 | 77 | name: *[u8], |
|
| 77 | 78 | /// Module-local identity used by semantic tables. |
|
| 78 | 79 | moduleId: u16, |
|
| 79 | 80 | nodeId: u32, |
|
| 80 | 81 | /// Method signatures, including from supertraits. |
|
| 81 | - | methods: *mut [TraitMethod], |
|
| 82 | + | methods: vec::Vec⟨TraitMethod⟩, |
|
| 82 | 83 | /// Supertraits that must also be implemented. |
|
| 83 | - | supertraits: *mut [*TraitType], |
|
| 84 | + | supertraits: vec::Vec⟨*TraitType⟩, |
|
| 84 | 85 | /// Rigid `Self` type used by static signatures. |
|
| 85 | 86 | selfType: *GenericParamType, |
|
| 86 | 87 | /// Whether signature resolution has started or completed. |
|
| 87 | 88 | state: TraitState, |
|
| 88 | 89 | /// Whether every vtable-exposed method is object-safe. |
| 135 | 136 | ||
| 136 | 137 | /// Identifier for the synthetic `len` field. |
|
| 137 | 138 | export constant LEN_FIELD: *[u8] = "len"; |
|
| 138 | 139 | /// Identifier for the synthetic `ptr` field. |
|
| 139 | 140 | export constant PTR_FIELD: *[u8] = "ptr"; |
|
| 140 | - | /// Identifier for the synthetic `cap` field. |
|
| 141 | - | export constant CAP_FIELD: *[u8] = "cap"; |
|
| 142 | 141 | ||
| 143 | 142 | /// Maximum `u16` value. |
|
| 144 | 143 | constant U16_MAX: u16 = 0xFFFF; |
|
| 145 | 144 | /// Maximum `u8` value. |
|
| 146 | 145 | constant U8_MAX: u16 = 0xFF; |
| 183 | 182 | symbol: *mut Symbol, |
|
| 184 | 183 | } |
|
| 185 | 184 | ||
| 186 | 185 | /// Array type payload. |
|
| 187 | 186 | export record ArrayType { |
|
| 187 | + | /// Element type. |
|
| 188 | 188 | item: *Type, |
|
| 189 | - | length: u32, |
|
| 189 | + | /// Typed constant descriptor for the array length. |
|
| 190 | + | length: *Type, |
|
| 190 | 191 | } |
|
| 191 | 192 | ||
| 192 | 193 | /// Anonymous record whose field layout depends on rigid parameters. |
|
| 193 | 194 | export record GenericRecordType { |
|
| 194 | 195 | /// Fields in declaration order. |
| 276 | 277 | export record SliceRangeInfo { |
|
| 277 | 278 | /// Element type of the resulting slice. |
|
| 278 | 279 | itemType: *Type, |
|
| 279 | 280 | /// Whether the resulting slice is mutable. |
|
| 280 | 281 | mutable: bool, |
|
| 281 | - | /// Static capacity if container is an array. |
|
| 282 | - | capacity: ?u32, |
|
| 282 | + | /// Typed array length descriptor, or `nil` when slicing a slice. |
|
| 283 | + | capacity: ?*Type, |
|
| 283 | 284 | } |
|
| 284 | 285 | ||
| 285 | 286 | /// Pre-computed metadata for `for` loop iteration. |
|
| 286 | 287 | /// Used by the lowerer to avoid re-analyzing the iterable type. |
|
| 287 | 288 | export union ForLoopInfo { |
| 290 | 291 | valType: *Type, |
|
| 291 | 292 | range: ast::Range, |
|
| 292 | 293 | bindingName: ?*[u8], |
|
| 293 | 294 | indexName: ?*[u8] |
|
| 294 | 295 | }, |
|
| 295 | - | /// Iterating over an array or slice. For arrays, the length field is set. |
|
| 296 | + | /// Iterating over an array or slice. |
|
| 296 | 297 | Collection { |
|
| 298 | + | /// Element type. |
|
| 297 | 299 | elemType: *Type, |
|
| 298 | - | length: ?u32, |
|
| 300 | + | /// Typed array length descriptor, or `nil` for a slice. |
|
| 301 | + | length: ?*Type, |
|
| 302 | + | /// Optional element binding name. |
|
| 299 | 303 | bindingName: ?*[u8], |
|
| 304 | + | /// Optional index binding name. |
|
| 300 | 305 | indexName: ?*[u8] |
|
| 301 | 306 | }, |
|
| 302 | 307 | } |
|
| 303 | 308 | ||
| 304 | 309 | /// A rigid type parameter belonging to one generic declaration. |
| 342 | 347 | /// Whether the declaration explicitly carries the `Linear` marker. |
|
| 343 | 348 | declaredLinear: bool, |
|
| 344 | 349 | /// Whether a generic function body has already been checked. |
|
| 345 | 350 | bodyResolved: bool, |
|
| 346 | 351 | /// Symbolic body types consumed by lowering, recorded during body analysis. |
|
| 347 | - | typeUses: *mut [GenericTypeUse], |
|
| 352 | + | typeUses: vec::Vec⟨GenericTypeUse⟩, |
|
| 348 | 353 | /// Next generic template. |
|
| 349 | 354 | next: ?*mut GenericTemplate, |
|
| 350 | 355 | } |
|
| 351 | 356 | ||
| 352 | 357 | /// Canonical concrete specialization of a generic record or union. |
| 516 | 521 | Pointer(PointerType), |
|
| 517 | 522 | /// Pointer-like slice. |
|
| 518 | 523 | Slice(SliceType), |
|
| 519 | 524 | /// Eg. `[i32; 32]`. |
|
| 520 | 525 | Array(ArrayType), |
|
| 521 | - | /// Array type whose length depends on a rigid constant parameter. |
|
| 522 | - | GenericArray { |
|
| 523 | - | item: *Type, |
|
| 524 | - | length: *ast::Node, |
|
| 525 | - | }, |
|
| 526 | 526 | /// Rigid integer constant parameter within a generic declaration. |
|
| 527 | 527 | ConstParameter(*GenericParamType), |
|
| 528 | 528 | /// Canonical typed integer generic argument. |
|
| 529 | 529 | ConstArgument { |
|
| 530 | 530 | type: *Type, |
| 549 | 549 | GenericDataApply(*GenericDataApplyType), |
|
| 550 | 550 | /// An erased pointer-like type with a v-table. |
|
| 551 | 551 | TraitObject(TraitObjectType), |
|
| 552 | 552 | } |
|
| 553 | 553 | ||
| 554 | + | /// Return a concrete `u32` array length from its typed descriptor. |
|
| 555 | + | export fn concreteArrayLength(length: *Type) -> ?u32 { |
|
| 556 | + | let case Type::ConstArgument { type, value } = *length else return nil; |
|
| 557 | + | if *type <> Type::U32 or value.negative |
|
| 558 | + | or value.magnitude > parser::U32_MAX as u64 |
|
| 559 | + | { |
|
| 560 | + | return nil; |
|
| 561 | + | } |
|
| 562 | + | return value.magnitude as u32; |
|
| 563 | + | } |
|
| 564 | + | ||
| 554 | 565 | /// Structured diagnostic payload for type mismatches. |
|
| 555 | 566 | export record TypeMismatch { |
|
| 556 | 567 | expected: Type, |
|
| 557 | 568 | actual: Type, |
|
| 558 | 569 | } |
| 910 | 921 | GenericSpecializationLimit, |
|
| 911 | 922 | } |
|
| 912 | 923 | ||
| 913 | 924 | /// Diagnostics returned by the analyzer. |
|
| 914 | 925 | export record Diagnostics { |
|
| 926 | + | /// Recorded errors in analysis order. |
|
| 915 | 927 | errors: *mut [Error], |
|
| 916 | 928 | } |
|
| 917 | 929 | ||
| 918 | 930 | /// Call context. |
|
| 919 | 931 | union CallCtx { |
| 968 | 980 | /// Whether the receiver is the first explicit call argument. |
|
| 969 | 981 | explicitReceiver: bool, |
|
| 970 | 982 | }, |
|
| 971 | 983 | /// Standalone method call metadata. |
|
| 972 | 984 | MethodCall { method: *MethodEntry }, |
|
| 973 | - | /// Slice `.append(val, allocator)` method call. |
|
| 974 | - | SliceAppend { elemType: *Type }, |
|
| 975 | - | /// Slice `.delete(index)` method call. |
|
| 976 | - | SliceDelete { elemType: *Type }, |
|
| 977 | 985 | /// Concrete specialization selected by an explicit generic function value. |
|
| 978 | 986 | GenericFnCall(*GenericFnSpecialization), |
|
| 979 | 987 | /// Symbolic generic call resolved under the caller's specialization. |
|
| 980 | 988 | GenericFnDependency(*GenericFnDependency), |
|
| 981 | 989 | } |
| 1165 | 1173 | /// Combined semantic metadata table indexed by node ID. |
|
| 1166 | 1174 | nodeData: NodeDataTable, |
|
| 1167 | 1175 | /// Linked list of interned types. |
|
| 1168 | 1176 | types: ?*TypeNode, |
|
| 1169 | 1177 | /// Diagnostics recorded so far. |
|
| 1170 | - | errors: *mut [Error], |
|
| 1178 | + | errors: vec::Vec⟨Error⟩, |
|
| 1171 | 1179 | /// Module graph for the current package. |
|
| 1172 | 1180 | moduleGraph: *module::ModuleGraph, |
|
| 1173 | 1181 | /// Cache of module scopes indexed by module ID. |
|
| 1174 | 1182 | moduleScopes: [?*mut Scope; module::MAX_MODULES], |
|
| 1175 | 1183 | /// Trait instance registry. |
| 1205 | 1213 | record TypeNode { |
|
| 1206 | 1214 | ty: Type, |
|
| 1207 | 1215 | next: ?*TypeNode, |
|
| 1208 | 1216 | } |
|
| 1209 | 1217 | ||
| 1218 | + | instantiate vec::append⟨*Type⟩, |
|
| 1219 | + | vec::view⟨*Type⟩; |
|
| 1220 | + | ||
| 1221 | + | instantiate vec::append⟨RecordField⟩, |
|
| 1222 | + | vec::view⟨RecordField⟩; |
|
| 1223 | + | ||
| 1224 | + | instantiate vec::append⟨UnionVariant⟩, |
|
| 1225 | + | vec::view⟨UnionVariant⟩; |
|
| 1226 | + | ||
| 1227 | + | instantiate vec::append⟨*GenericParamType⟩, |
|
| 1228 | + | vec::view⟨*GenericParamType⟩; |
|
| 1229 | + | ||
| 1230 | + | instantiate vec::append⟨TraitMethod⟩, |
|
| 1231 | + | vec::view⟨TraitMethod⟩; |
|
| 1232 | + | ||
| 1233 | + | instantiate vec::append⟨*TraitType⟩, |
|
| 1234 | + | vec::view⟨*TraitType⟩; |
|
| 1235 | + | ||
| 1236 | + | instantiate vec::append⟨GenericTypeUse⟩, |
|
| 1237 | + | vec::view⟨GenericTypeUse⟩; |
|
| 1238 | + | ||
| 1239 | + | instantiate vec::push⟨Error⟩, |
|
| 1240 | + | vec::viewMut⟨Error⟩; |
|
| 1241 | + | ||
| 1210 | 1242 | /// Allocate and intern a type in the arena, returning a pointer for deduplication. |
|
| 1211 | 1243 | export fn allocType(self: *mut Resolver, ty: Type) -> *Type { |
|
| 1212 | 1244 | // Search existing types for a match. |
|
| 1213 | 1245 | let mut cursor = self.types; |
|
| 1214 | 1246 | while let node = cursor { |
| 1226 | 1258 | set self.types = node; |
|
| 1227 | 1259 | ||
| 1228 | 1260 | return &node.ty; |
|
| 1229 | 1261 | } |
|
| 1230 | 1262 | ||
| 1263 | + | /// Allocate the canonical typed descriptor for a concrete array length. |
|
| 1264 | + | fn allocConcreteArrayLength(self: *mut Resolver, length: u32) -> *Type { |
|
| 1265 | + | return allocType(self, Type::ConstArgument { |
|
| 1266 | + | type: allocType(self, Type::U32), |
|
| 1267 | + | value: ConstInt { |
|
| 1268 | + | magnitude: length as u64, |
|
| 1269 | + | bits: 32, |
|
| 1270 | + | signed: false, |
|
| 1271 | + | negative: false, |
|
| 1272 | + | }, |
|
| 1273 | + | }); |
|
| 1274 | + | } |
|
| 1275 | + | ||
| 1276 | + | /// Allocate a symbolic array length descriptor for a generic constant expression. |
|
| 1277 | + | fn allocSymbolicArrayLength(self: *mut Resolver, expression: *ast::Node) -> *Type { |
|
| 1278 | + | if let sym = symbolFor(self, expression) { |
|
| 1279 | + | if let case SymbolData::ConstParameter(param) = sym.data { |
|
| 1280 | + | if let declaredType = param.constType; *declaredType == Type::U32 { |
|
| 1281 | + | return allocType(self, Type::ConstParameter(param)); |
|
| 1282 | + | } |
|
| 1283 | + | } |
|
| 1284 | + | } |
|
| 1285 | + | return allocType(self, Type::GenericConstExpr { |
|
| 1286 | + | type: allocType(self, Type::U32), |
|
| 1287 | + | expr: expression, |
|
| 1288 | + | }); |
|
| 1289 | + | } |
|
| 1290 | + | ||
| 1231 | 1291 | /// Return whether a type contains a rigid generic parameter. |
|
| 1232 | 1292 | export fn containsGenericParameter(ty: Type) -> bool { |
|
| 1233 | 1293 | match ty { |
|
| 1234 | 1294 | case Type::Pointer(pointer) => |
|
| 1235 | 1295 | return containsGenericParameter(*pointer.target), |
|
| 1236 | 1296 | case Type::Slice(slice) => |
|
| 1237 | 1297 | return containsGenericParameter(*slice.item), |
|
| 1238 | 1298 | case Type::Parameter(_), Type::ConstParameter(_), |
|
| 1239 | 1299 | Type::GenericConstExpr { .. } => return true, |
|
| 1240 | - | case Type::Array(array) => return containsGenericParameter(*array.item), |
|
| 1241 | - | case Type::GenericArray { .. } => return true, |
|
| 1300 | + | case Type::Array(array) => |
|
| 1301 | + | return containsGenericParameter(*array.item) |
|
| 1302 | + | or containsGenericParameter(*array.length), |
|
| 1242 | 1303 | case Type::Optional(inner) => return containsGenericParameter(*inner), |
|
| 1243 | 1304 | // Symbolic anonymous records require materialization even when their |
|
| 1244 | 1305 | // own fields happen not to mention a rigid parameter. |
|
| 1245 | 1306 | case Type::GenericRecord(_) => return true, |
|
| 1246 | 1307 | case Type::GenericDataApply(_) => return true, |
| 1325 | 1386 | mutable: slice.mutable, |
|
| 1326 | 1387 | }); |
|
| 1327 | 1388 | } |
|
| 1328 | 1389 | case Type::Array(array) => { |
|
| 1329 | 1390 | let item = try materializeConcreteGenericData(self, *array.item, site); |
|
| 1391 | + | let length = try materializeConcreteGenericData( |
|
| 1392 | + | self, *array.length, site |
|
| 1393 | + | ); |
|
| 1330 | 1394 | return Type::Array(ArrayType { |
|
| 1331 | 1395 | item: allocType(self, item), |
|
| 1332 | - | length: array.length, |
|
| 1396 | + | length: allocType(self, length), |
|
| 1333 | 1397 | }); |
|
| 1334 | 1398 | } |
|
| 1335 | - | case Type::GenericArray { item, length } => { |
|
| 1336 | - | let inner = try materializeConcreteGenericData(self, *item, site); |
|
| 1337 | - | return Type::GenericArray { item: allocType(self, inner), length }; |
|
| 1338 | - | } |
|
| 1339 | 1399 | case Type::Optional(inner) => { |
|
| 1340 | 1400 | let value = try materializeConcreteGenericData(self, *inner, site); |
|
| 1341 | 1401 | return Type::Optional(allocType(self, value)); |
|
| 1342 | 1402 | } |
|
| 1343 | 1403 | case Type::GenericDataApply(app) => { |
|
| 1344 | 1404 | let a = alloc::arenaAllocator(&mut self.arena); |
|
| 1345 | - | let mut args: *mut [*Type] = &mut []; |
|
| 1405 | + | let mut args = vec::Vec⟨*Type⟩ { data: &mut [], len: 0 }; |
|
| 1346 | 1406 | let mut concrete = true; |
|
| 1347 | 1407 | for arg in app.args { |
|
| 1348 | 1408 | let value = try materializeConcreteGenericData(self, *arg, site); |
|
| 1349 | 1409 | set concrete = concrete and not containsGenericParameter(value); |
|
| 1350 | - | args.append(allocType(self, value), a); |
|
| 1410 | + | vec::append⟨*Type⟩(&mut args, allocType(self, value), a); |
|
| 1351 | 1411 | } |
|
| 1412 | + | let argsView = vec::view⟨*Type⟩(&args); |
|
| 1352 | 1413 | if concrete { |
|
| 1353 | 1414 | let nominal = try specializeGenericData( |
|
| 1354 | - | self, app.site, app.template, &args[..], false |
|
| 1415 | + | self, app.site, app.template, argsView, false |
|
| 1355 | 1416 | ); |
|
| 1356 | 1417 | return Type::Nominal(nominal); |
|
| 1357 | 1418 | } |
|
| 1358 | 1419 | let application = try! alloc::alloc( |
|
| 1359 | 1420 | &mut self.arena, |
|
| 1360 | 1421 | @sizeOf(GenericDataApplyType), |
|
| 1361 | 1422 | @alignOf(GenericDataApplyType), |
|
| 1362 | 1423 | ) as *mut GenericDataApplyType; |
|
| 1363 | 1424 | set *application = GenericDataApplyType { |
|
| 1364 | 1425 | template: app.template, |
|
| 1365 | - | args: &args[..], |
|
| 1426 | + | args: argsView, |
|
| 1366 | 1427 | site: app.site, |
|
| 1367 | 1428 | }; |
|
| 1368 | 1429 | return Type::GenericDataApply(application); |
|
| 1369 | 1430 | } |
|
| 1370 | 1431 | case Type::Fn(info) => { |
|
| 1371 | 1432 | let a = alloc::arenaAllocator(&mut self.arena); |
|
| 1372 | - | let mut params: *mut [*Type] = &mut []; |
|
| 1373 | - | let mut throwTypes: *mut [*Type] = &mut []; |
|
| 1433 | + | let mut params = vec::Vec⟨*Type⟩ { data: &mut [], len: 0 }; |
|
| 1434 | + | let mut throwTypes = vec::Vec⟨*Type⟩ { data: &mut [], len: 0 }; |
|
| 1374 | 1435 | for param in info.paramTypes { |
|
| 1375 | 1436 | let value = try materializeConcreteGenericData(self, *param, site); |
|
| 1376 | - | params.append(allocType(self, value), a); |
|
| 1437 | + | vec::append⟨*Type⟩(&mut params, allocType(self, value), a); |
|
| 1377 | 1438 | } |
|
| 1378 | 1439 | for thrown in info.throwList { |
|
| 1379 | 1440 | let value = try materializeConcreteGenericData(self, *thrown, site); |
|
| 1380 | - | throwTypes.append(allocType(self, value), a); |
|
| 1441 | + | vec::append⟨*Type⟩(&mut throwTypes, allocType(self, value), a); |
|
| 1381 | 1442 | } |
|
| 1382 | 1443 | let result = try materializeConcreteGenericData( |
|
| 1383 | 1444 | self, *info.returnType, site |
|
| 1384 | 1445 | ); |
|
| 1385 | 1446 | return Type::Fn(allocFnType(self, FnType { |
|
| 1386 | - | paramTypes: ¶ms[..], |
|
| 1447 | + | paramTypes: vec::view⟨*Type⟩(¶ms), |
|
| 1387 | 1448 | returnType: allocType(self, result), |
|
| 1388 | - | throwList: &throwTypes[..], |
|
| 1449 | + | throwList: vec::view⟨*Type⟩(&throwTypes), |
|
| 1389 | 1450 | isUnsafe: info.isUnsafe, |
|
| 1390 | 1451 | localCount: info.localCount, |
|
| 1391 | 1452 | })); |
|
| 1392 | 1453 | } |
|
| 1393 | 1454 | case Type::GenericRecord(rec) => { |
|
| 1394 | 1455 | let a = alloc::arenaAllocator(&mut self.arena); |
|
| 1395 | - | let mut fields: *mut [RecordField] = &mut []; |
|
| 1456 | + | let mut fields = vec::Vec⟨RecordField⟩ { data: &mut [], len: 0 }; |
|
| 1396 | 1457 | let mut symbolic = false; |
|
| 1397 | 1458 | for field in rec.fields { |
|
| 1398 | 1459 | let fieldType = try materializeConcreteGenericData( |
|
| 1399 | 1460 | self, field.fieldType, site |
|
| 1400 | 1461 | ); |
|
| 1401 | 1462 | set symbolic = symbolic or containsGenericParameter(fieldType); |
|
| 1402 | - | fields.append(RecordField { |
|
| 1463 | + | vec::append⟨RecordField⟩(&mut fields, RecordField { |
|
| 1403 | 1464 | name: field.name, |
|
| 1404 | 1465 | fieldType, |
|
| 1405 | 1466 | offset: field.offset, |
|
| 1406 | 1467 | }, a); |
|
| 1407 | 1468 | } |
| 1409 | 1470 | &mut self.arena, |
|
| 1410 | 1471 | @sizeOf(GenericRecordType), |
|
| 1411 | 1472 | @alignOf(GenericRecordType), |
|
| 1412 | 1473 | ) as *mut GenericRecordType; |
|
| 1413 | 1474 | set *updatedRec = GenericRecordType { |
|
| 1414 | - | fields: &fields[..], |
|
| 1475 | + | fields: vec::view⟨RecordField⟩(&fields), |
|
| 1415 | 1476 | labeled: rec.labeled, |
|
| 1416 | 1477 | }; |
|
| 1417 | 1478 | let updated = Type::GenericRecord(updatedRec); |
|
| 1418 | 1479 | if symbolic { |
|
| 1419 | 1480 | return updated; |
| 1517 | 1578 | mutable: slice.mutable, |
|
| 1518 | 1579 | }); |
|
| 1519 | 1580 | } |
|
| 1520 | 1581 | case Type::Array(array) => { |
|
| 1521 | 1582 | let item = copyStructuralTypeToArena(*array.item, arena); |
|
| 1583 | + | let length = copyStructuralTypeToArena(*array.length, arena); |
|
| 1522 | 1584 | return Type::Array(ArrayType { |
|
| 1523 | 1585 | item: allocArenaType(arena, item), |
|
| 1524 | - | length: array.length, |
|
| 1586 | + | length: allocArenaType(arena, length), |
|
| 1525 | 1587 | }); |
|
| 1526 | 1588 | } |
|
| 1527 | 1589 | case Type::Optional(inner) => { |
|
| 1528 | 1590 | let stored = copyStructuralTypeToArena(*inner, arena); |
|
| 1529 | 1591 | return Type::Optional(allocArenaType(arena, stored)); |
|
| 1530 | 1592 | } |
|
| 1531 | 1593 | case Type::Fn(info) => { |
|
| 1532 | 1594 | let a = alloc::arenaAllocator(arena); |
|
| 1533 | - | let mut params: *mut [*Type] = &mut []; |
|
| 1534 | - | let mut throwList: *mut [*Type] = &mut []; |
|
| 1595 | + | let mut params = vec::Vec⟨*Type⟩ { data: &mut [], len: 0 }; |
|
| 1596 | + | let mut throwList = vec::Vec⟨*Type⟩ { data: &mut [], len: 0 }; |
|
| 1535 | 1597 | for param in info.paramTypes { |
|
| 1536 | 1598 | let stored = copyStructuralTypeToArena(*param, arena); |
|
| 1537 | - | params.append(allocArenaType(arena, stored), a); |
|
| 1599 | + | vec::append⟨*Type⟩(&mut params, allocArenaType(arena, stored), a); |
|
| 1538 | 1600 | } |
|
| 1539 | 1601 | for thrown in info.throwList { |
|
| 1540 | 1602 | let stored = copyStructuralTypeToArena(*thrown, arena); |
|
| 1541 | - | throwList.append(allocArenaType(arena, stored), a); |
|
| 1603 | + | vec::append⟨*Type⟩(&mut throwList, allocArenaType(arena, stored), a); |
|
| 1542 | 1604 | } |
|
| 1543 | 1605 | let returnType = copyStructuralTypeToArena(*info.returnType, arena); |
|
| 1544 | 1606 | let storedInfo = try! alloc::alloc( |
|
| 1545 | 1607 | arena, @sizeOf(FnType), @alignOf(FnType) |
|
| 1546 | 1608 | ) as *mut FnType; |
|
| 1547 | 1609 | set *storedInfo = FnType { |
|
| 1548 | - | paramTypes: ¶ms[..], |
|
| 1610 | + | paramTypes: vec::view⟨*Type⟩(¶ms), |
|
| 1549 | 1611 | returnType: allocArenaType(arena, returnType), |
|
| 1550 | - | throwList: &throwList[..], |
|
| 1612 | + | throwList: vec::view⟨*Type⟩(&throwList), |
|
| 1551 | 1613 | isUnsafe: info.isUnsafe, |
|
| 1552 | 1614 | localCount: info.localCount, |
|
| 1553 | 1615 | }; |
|
| 1554 | 1616 | return Type::Fn(storedInfo); |
|
| 1555 | 1617 | } |
| 1619 | 1681 | mutable: slice.mutable, |
|
| 1620 | 1682 | }); |
|
| 1621 | 1683 | } |
|
| 1622 | 1684 | case Type::Array(array) => { |
|
| 1623 | 1685 | let item = try substituteTypeWithContext(context, *array.item, sub); |
|
| 1686 | + | let length = try substituteTypeWithContext( |
|
| 1687 | + | context, *array.length, sub |
|
| 1688 | + | ); |
|
| 1624 | 1689 | return Type::Array(ArrayType { |
|
| 1625 | 1690 | item: allocSubstitutedType(context, item), |
|
| 1626 | - | length: array.length, |
|
| 1627 | - | }); |
|
| 1628 | - | } |
|
| 1629 | - | case Type::GenericArray { item, length } => { |
|
| 1630 | - | let concreteItem = try substituteTypeWithContext(context, *item, sub); |
|
| 1631 | - | let mut arrayLength: u32 = 0; |
|
| 1632 | - | match *context { |
|
| 1633 | - | case TypeSubstitutionContext::Resolution { resolver, .. } => { |
|
| 1634 | - | let value = constValueWithSubstitution(resolver, length, sub) |
|
| 1635 | - | else throw emitError(resolver, length, ErrorKind::ConstExprRequired); |
|
| 1636 | - | if not validateConstIntRange(value, Type::U32) { |
|
| 1637 | - | throw emitError(resolver, length, ErrorKind::NumericLiteralOverflow); |
|
| 1638 | - | } |
|
| 1639 | - | let case ConstValue::Int(int) = value |
|
| 1640 | - | else throw emitError(resolver, length, ErrorKind::ConstExprRequired); |
|
| 1641 | - | set arrayLength = int.magnitude as u32; |
|
| 1642 | - | } |
|
| 1643 | - | case TypeSubstitutionContext::ReadOnly { resolver, .. } => { |
|
| 1644 | - | let value = constIntWithSubstitution( |
|
| 1645 | - | resolver, length, Type::U32, sub |
|
| 1646 | - | ) else throw ResolveError::Failure; |
|
| 1647 | - | set arrayLength = value.magnitude as u32; |
|
| 1648 | - | } |
|
| 1649 | - | } |
|
| 1650 | - | return Type::Array(ArrayType { |
|
| 1651 | - | item: allocSubstitutedType(context, concreteItem), |
|
| 1652 | - | length: arrayLength, |
|
| 1691 | + | length: allocSubstitutedType(context, length), |
|
| 1653 | 1692 | }); |
|
| 1654 | 1693 | } |
|
| 1655 | 1694 | case Type::Optional(inner) => { |
|
| 1656 | 1695 | let value = try substituteTypeWithContext(context, *inner, sub); |
|
| 1657 | 1696 | return Type::Optional(allocSubstitutedType(context, value)); |
|
| 1658 | 1697 | } |
|
| 1659 | 1698 | case Type::GenericDataApply(app) => { |
|
| 1660 | 1699 | let a = alloc::arenaAllocator(substitutionArena(context)); |
|
| 1661 | - | let mut args: *mut [*Type] = &mut []; |
|
| 1700 | + | let mut args = vec::Vec⟨*Type⟩ { data: &mut [], len: 0 }; |
|
| 1662 | 1701 | let mut symbolic = false; |
|
| 1663 | 1702 | for arg in app.args { |
|
| 1664 | 1703 | let replacement = try substituteTypeWithContext(context, *arg, sub); |
|
| 1665 | 1704 | set symbolic = symbolic or containsGenericParameter(replacement); |
|
| 1666 | - | args.append(allocSubstitutedType(context, replacement), a); |
|
| 1705 | + | vec::append⟨*Type⟩(&mut args, allocSubstitutedType(context, replacement), a); |
|
| 1667 | 1706 | } |
|
| 1707 | + | let argsView = vec::view⟨*Type⟩(&args); |
|
| 1668 | 1708 | match *context { |
|
| 1669 | 1709 | case TypeSubstitutionContext::Resolution { resolver, .. } => { |
|
| 1670 | 1710 | if symbolic { |
|
| 1671 | 1711 | let application = try! alloc::alloc( |
|
| 1672 | 1712 | &mut resolver.arena, |
|
| 1673 | 1713 | @sizeOf(GenericDataApplyType), |
|
| 1674 | 1714 | @alignOf(GenericDataApplyType), |
|
| 1675 | 1715 | ) as *mut GenericDataApplyType; |
|
| 1676 | 1716 | set *application = GenericDataApplyType { |
|
| 1677 | 1717 | template: app.template, |
|
| 1678 | - | args: &args[..], |
|
| 1718 | + | args: argsView, |
|
| 1679 | 1719 | site: app.site, |
|
| 1680 | 1720 | }; |
|
| 1681 | 1721 | return Type::GenericDataApply(application); |
|
| 1682 | 1722 | } |
|
| 1683 | 1723 | let nominal = try specializeGenericData( |
|
| 1684 | - | resolver, app.site, app.template, &args[..], false |
|
| 1724 | + | resolver, app.site, app.template, argsView, false |
|
| 1685 | 1725 | ); |
|
| 1686 | 1726 | return Type::Nominal(nominal); |
|
| 1687 | 1727 | } |
|
| 1688 | 1728 | case TypeSubstitutionContext::ReadOnly { resolver, .. } => { |
|
| 1689 | 1729 | if symbolic { |
|
| 1690 | 1730 | throw ResolveError::Failure; |
|
| 1691 | 1731 | } |
|
| 1692 | 1732 | let specialization = findGenericDataSpecialization( |
|
| 1693 | - | resolver, app.template, &args[..] |
|
| 1733 | + | resolver, app.template, argsView |
|
| 1694 | 1734 | ) else throw ResolveError::Failure; |
|
| 1695 | 1735 | return Type::Nominal(specialization.nominal); |
|
| 1696 | 1736 | } |
|
| 1697 | 1737 | } |
|
| 1698 | 1738 | } |
| 1703 | 1743 | .. |
|
| 1704 | 1744 | } = *context { |
|
| 1705 | 1745 | set persistentArena = arena; |
|
| 1706 | 1746 | } |
|
| 1707 | 1747 | let a = alloc::arenaAllocator(persistentArena); |
|
| 1708 | - | let mut fields: *mut [RecordField] = &mut []; |
|
| 1748 | + | let mut fields = vec::Vec⟨RecordField⟩ { data: &mut [], len: 0 }; |
|
| 1709 | 1749 | let mut offset: u32 = 0; |
|
| 1710 | 1750 | let mut alignment: u32 = 1; |
|
| 1711 | 1751 | for field in rec.fields { |
|
| 1712 | 1752 | let fieldType = try substituteTypeWithContext( |
|
| 1713 | 1753 | context, field.fieldType, sub |
| 1732 | 1772 | ); |
|
| 1733 | 1773 | } |
|
| 1734 | 1774 | } |
|
| 1735 | 1775 | let fieldLayout = getTypeLayout(fieldType); |
|
| 1736 | 1776 | set offset = mem::alignUp(offset, fieldLayout.alignment); |
|
| 1737 | - | fields.append(RecordField { |
|
| 1777 | + | vec::append⟨RecordField⟩(&mut fields, RecordField { |
|
| 1738 | 1778 | name: field.name, |
|
| 1739 | 1779 | fieldType: storedFieldType, |
|
| 1740 | 1780 | offset: offset as i32, |
|
| 1741 | 1781 | }, a); |
|
| 1742 | 1782 | set offset += fieldLayout.size; |
| 1744 | 1784 | } |
|
| 1745 | 1785 | let nominal = try! alloc::alloc( |
|
| 1746 | 1786 | persistentArena, @sizeOf(NominalType), @alignOf(NominalType) |
|
| 1747 | 1787 | ) as *mut NominalType; |
|
| 1748 | 1788 | set *nominal = NominalType::Record(RecordType { |
|
| 1749 | - | fields: &fields[..], |
|
| 1789 | + | fields: vec::view⟨RecordField⟩(&fields), |
|
| 1750 | 1790 | labeled: rec.labeled, |
|
| 1751 | 1791 | layout: Layout { |
|
| 1752 | 1792 | size: mem::alignUp(offset, alignment), |
|
| 1753 | 1793 | alignment, |
|
| 1754 | 1794 | }, |
| 1757 | 1797 | return Type::Nominal(nominal); |
|
| 1758 | 1798 | } |
|
| 1759 | 1799 | case Type::Fn(info) => { |
|
| 1760 | 1800 | let arena = substitutionArena(context); |
|
| 1761 | 1801 | let a = alloc::arenaAllocator(arena); |
|
| 1762 | - | let mut params: *mut [*Type] = &mut []; |
|
| 1763 | - | let mut throwTypes: *mut [*Type] = &mut []; |
|
| 1802 | + | let mut params = vec::Vec⟨*Type⟩ { data: &mut [], len: 0 }; |
|
| 1803 | + | let mut throwTypes = vec::Vec⟨*Type⟩ { data: &mut [], len: 0 }; |
|
| 1764 | 1804 | for param in info.paramTypes { |
|
| 1765 | 1805 | let concrete = try substituteTypeWithContext(context, *param, sub); |
|
| 1766 | - | params.append(allocSubstitutedType(context, concrete), a); |
|
| 1806 | + | vec::append⟨*Type⟩(&mut params, allocSubstitutedType(context, concrete), a); |
|
| 1767 | 1807 | } |
|
| 1768 | 1808 | for thrown in info.throwList { |
|
| 1769 | 1809 | let concrete = try substituteTypeWithContext(context, *thrown, sub); |
|
| 1770 | - | throwTypes.append(allocSubstitutedType(context, concrete), a); |
|
| 1810 | + | vec::append⟨*Type⟩(&mut throwTypes, allocSubstitutedType(context, concrete), a); |
|
| 1771 | 1811 | } |
|
| 1772 | 1812 | let result = try substituteTypeWithContext( |
|
| 1773 | 1813 | context, *info.returnType, sub |
|
| 1774 | 1814 | ); |
|
| 1775 | 1815 | let fnType = try! alloc::alloc( |
|
| 1776 | 1816 | arena, @sizeOf(FnType), @alignOf(FnType) |
|
| 1777 | 1817 | ) as *mut FnType; |
|
| 1778 | 1818 | set *fnType = FnType { |
|
| 1779 | - | paramTypes: ¶ms[..], |
|
| 1819 | + | paramTypes: vec::view⟨*Type⟩(¶ms), |
|
| 1780 | 1820 | returnType: allocSubstitutedType(context, result), |
|
| 1781 | - | throwList: &throwTypes[..], |
|
| 1821 | + | throwList: vec::view⟨*Type⟩(&throwTypes), |
|
| 1782 | 1822 | isUnsafe: info.isUnsafe, |
|
| 1783 | 1823 | localCount: info.localCount, |
|
| 1784 | 1824 | }; |
|
| 1785 | 1825 | return Type::Fn(fnType); |
|
| 1786 | 1826 | } |
| 1861 | 1901 | } |
|
| 1862 | 1902 | ||
| 1863 | 1903 | /// Returns an error, if any, associated with the given node. |
|
| 1864 | 1904 | fn errorForNode(self: *Resolver, node: *ast::Node) -> ?*Error { |
|
| 1865 | 1905 | for i in 0..self.errors.len { |
|
| 1866 | - | let err = &self.errors[i]; |
|
| 1906 | + | let err = &self.errors.data[i]; |
|
| 1867 | 1907 | if err.node == node { |
|
| 1868 | 1908 | return err; |
|
| 1869 | 1909 | } |
|
| 1870 | 1910 | } |
|
| 1871 | 1911 | return nil; |
| 1941 | 1981 | unsafeDepth: 0, |
|
| 1942 | 1982 | config, |
|
| 1943 | 1983 | arena, |
|
| 1944 | 1984 | nodeData: NodeDataTable { entries: storage.nodeData }, |
|
| 1945 | 1985 | types: nil, |
|
| 1946 | - | errors: @sliceOf(storage.errors.ptr, 0, storage.errors.len), |
|
| 1986 | + | errors: vec::Vec⟨Error⟩ { data: storage.errors, len: 0 }, |
|
| 1947 | 1987 | // TODO: Shouldn't be undefined. |
|
| 1948 | 1988 | moduleGraph: undefined, |
|
| 1949 | 1989 | moduleScopes, |
|
| 1950 | 1990 | instances: undefined, |
|
| 1951 | 1991 | instancesLen: 0, |
| 1958 | 1998 | genericDataSpecializations: nil, |
|
| 1959 | 1999 | genericRoots: 0, |
|
| 1960 | 2000 | genericSpecializationCount: 0, |
|
| 1961 | 2001 | }; |
|
| 1962 | 2002 | } |
|
| 2003 | + | /// Return the diagnostics collected by the resolver. |
|
| 2004 | + | fn diagnostics(self: *mut Resolver) -> Diagnostics { |
|
| 2005 | + | return Diagnostics { errors: vec::viewMut⟨Error⟩(&mut self.errors) }; |
|
| 2006 | + | } |
|
| 1963 | 2007 | ||
| 1964 | 2008 | /// Return `true` if there are no errors in the diagnostics. |
|
| 1965 | 2009 | export fn success(diag: *Diagnostics) -> bool { |
|
| 1966 | 2010 | return diag.errors.len == 0; |
|
| 1967 | 2011 | } |
| 1975 | 2019 | } |
|
| 1976 | 2020 | ||
| 1977 | 2021 | /// Record an error diagnostic and return an error sentinel suitable for throwing. |
|
| 1978 | 2022 | fn emitError(self: *mut Resolver, node: ?*ast::Node, kind: ErrorKind) -> ResolveError { |
|
| 1979 | 2023 | // If our error list is full, just return an error without recording it. |
|
| 1980 | - | if self.errors.len >= self.errors.cap { |
|
| 2024 | + | if self.errors.len >= self.errors.data.len { |
|
| 1981 | 2025 | return ResolveError::Failure; |
|
| 1982 | 2026 | } |
|
| 1983 | 2027 | // Don't record more than one error per node. |
|
| 1984 | 2028 | if let n = node; errorForNode(self, n) <> nil { |
|
| 1985 | 2029 | return ResolveError::Failure; |
|
| 1986 | 2030 | } |
|
| 1987 | - | let idx = self.errors.len; |
|
| 1988 | - | set self.errors = @sliceOf(self.errors.ptr, idx + 1, self.errors.cap); |
|
| 1989 | - | set self.errors[idx] = Error { kind, node, moduleId: self.currentMod }; |
|
| 2031 | + | assert vec::push⟨Error⟩( |
|
| 2032 | + | &mut self.errors, |
|
| 2033 | + | Error { kind, node, moduleId: self.currentMod }, |
|
| 2034 | + | ), "emitError: error storage unexpectedly full"; |
|
| 1990 | 2035 | ||
| 1991 | 2036 | return ResolveError::Failure; |
|
| 1992 | 2037 | } |
|
| 1993 | 2038 | ||
| 1994 | 2039 | /// Like [`emitError`], but for type mismatches specifically. |
| 2144 | 2189 | fn recordGenericTypeUse(self: *mut Resolver, site: *ast::Node, ty: Type) { |
|
| 2145 | 2190 | let current = self.currentGenericTemplate else return; |
|
| 2146 | 2191 | if not containsGenericParameter(ty) { |
|
| 2147 | 2192 | return; |
|
| 2148 | 2193 | } |
|
| 2149 | - | current.typeUses.append( |
|
| 2194 | + | vec::append⟨GenericTypeUse⟩( |
|
| 2195 | + | &mut current.typeUses, |
|
| 2150 | 2196 | GenericTypeUse { site, ty }, |
|
| 2151 | 2197 | alloc::arenaAllocator(&mut self.arena), |
|
| 2152 | 2198 | ); |
|
| 2153 | 2199 | } |
|
| 2154 | 2200 |
| 2216 | 2262 | } |
|
| 2217 | 2263 | ||
| 2218 | 2264 | /// Associate slice range metadata with a subscript expression. |
|
| 2219 | 2265 | fn setSliceRangeInfo(self: *mut Resolver, node: *ast::Node, info: SliceRangeInfo) { |
|
| 2220 | 2266 | recordGenericTypeUse(self, node, *info.itemType); |
|
| 2267 | + | if let length = info.capacity { |
|
| 2268 | + | recordGenericTypeUse(self, node, *length); |
|
| 2269 | + | } |
|
| 2221 | 2270 | set self.nodeData.entries[node.id].extra = NodeExtra::SliceRange(info); |
|
| 2222 | 2271 | } |
|
| 2223 | 2272 | ||
| 2224 | 2273 | /// Associate union variant metadata with a pattern or constructor node. |
|
| 2225 | 2274 | fn setVariantInfo(self: *mut Resolver, node: *ast::Node, ordinal: u32, tag: u32) { |
| 2249 | 2298 | fn setForLoopInfo(self: *mut Resolver, node: *ast::Node, info: ForLoopInfo) { |
|
| 2250 | 2299 | set self.nodeData.entries[node.id].extra = NodeExtra::ForLoop(info); |
|
| 2251 | 2300 | match info { |
|
| 2252 | 2301 | case ForLoopInfo::Range { valType, .. } => |
|
| 2253 | 2302 | recordGenericTypeUse(self, node, *valType), |
|
| 2254 | - | case ForLoopInfo::Collection { elemType, .. } => |
|
| 2255 | - | recordGenericTypeUse(self, node, *elemType), |
|
| 2303 | + | case ForLoopInfo::Collection { elemType, length, .. } => { |
|
| 2304 | + | recordGenericTypeUse(self, node, *elemType); |
|
| 2305 | + | if let descriptor = length { |
|
| 2306 | + | recordGenericTypeUse(self, node, *descriptor); |
|
| 2307 | + | } |
|
| 2308 | + | } |
|
| 2256 | 2309 | } |
|
| 2257 | 2310 | } |
|
| 2258 | 2311 | ||
| 2259 | 2312 | /// Retrieve the constant value associated with a node, if any. |
|
| 2260 | 2313 | export fn constValueEntry(self: *Resolver, node: *ast::Node) -> ?ConstValue { |
| 2464 | 2517 | } |
|
| 2465 | 2518 | } |
|
| 2466 | 2519 | return layout; |
|
| 2467 | 2520 | } |
|
| 2468 | 2521 | ||
| 2469 | - | /// Get the layout of an array type. |
|
| 2522 | + | /// Get the layout of a concrete array type. |
|
| 2470 | 2523 | export fn getArrayLayout(arr: ArrayType) -> Layout { |
|
| 2524 | + | let length = concreteArrayLength(arr.length) |
|
| 2525 | + | else panic "getArrayLayout: symbolic array length"; |
|
| 2471 | 2526 | let itemLayout = getTypeLayout(*arr.item); |
|
| 2472 | 2527 | return Layout { |
|
| 2473 | - | size: itemLayout.size * arr.length, |
|
| 2528 | + | size: itemLayout.size * length, |
|
| 2474 | 2529 | alignment: itemLayout.alignment, |
|
| 2475 | 2530 | }; |
|
| 2476 | 2531 | } |
|
| 2477 | 2532 | ||
| 2478 | 2533 | /// Get the layout of an optional type. |
| 2844 | 2899 | match to { |
|
| 2845 | 2900 | case Type::Array(lhs) => { |
|
| 2846 | 2901 | let case Type::Array(rhs) = from |
|
| 2847 | 2902 | else return nil; |
|
| 2848 | 2903 | ||
| 2849 | - | if lhs.length <> rhs.length { |
|
| 2904 | + | if not typesEqual(*lhs.length, *rhs.length) { |
|
| 2850 | 2905 | return nil; |
|
| 2851 | 2906 | } |
|
| 2852 | 2907 | // For array literals, check each element individually for |
|
| 2853 | 2908 | // assignability. |
|
| 2854 | 2909 | match rval.value { |
|
| 2855 | 2910 | case ast::NodeValue::ArrayLit(items) => { |
|
| 2856 | - | if rhs.length == 0 and lhs.length == 0 { |
|
| 2911 | + | if let length = concreteArrayLength(lhs.length); length == 0 { |
|
| 2857 | 2912 | return Coercion::Identity; |
|
| 2858 | 2913 | } |
|
| 2859 | 2914 | // TODO: This won't work, because we should be setting coercions |
|
| 2860 | 2915 | // for every list item, but we don't. It's best to not have an |
|
| 2861 | 2916 | // `isAssignable` function and just have one that records coercions. |
| 2996 | 3051 | } |
|
| 2997 | 3052 | return bEnd == nil; |
|
| 2998 | 3053 | } |
|
| 2999 | 3054 | case Type::Array(aa) => { |
|
| 3000 | 3055 | let case Type::Array(ab) = b else return false; |
|
| 3001 | - | return aa.length == ab.length and typesEqual(*aa.item, *ab.item); |
|
| 3056 | + | return typesEqual(*aa.length, *ab.length) |
|
| 3057 | + | and typesEqual(*aa.item, *ab.item); |
|
| 3002 | 3058 | } |
|
| 3003 | 3059 | case Type::Optional(oa) => { |
|
| 3004 | 3060 | let case Type::Optional(ob) = b else return false; |
|
| 3005 | 3061 | return typesEqual(*oa, *ob); |
|
| 3006 | 3062 | } |
| 3144 | 3200 | case 1 => return RecordField { |
|
| 3145 | 3201 | name: LEN_FIELD, |
|
| 3146 | 3202 | fieldType: Type::U32, |
|
| 3147 | 3203 | offset: PTR_SIZE as i32, |
|
| 3148 | 3204 | }, |
|
| 3149 | - | case 2 => return RecordField { |
|
| 3150 | - | name: CAP_FIELD, |
|
| 3151 | - | fieldType: Type::U32, |
|
| 3152 | - | offset: PTR_SIZE as i32 + 4, |
|
| 3153 | - | }, |
|
| 3154 | 3205 | else => return nil, |
|
| 3155 | 3206 | } |
|
| 3156 | 3207 | } |
|
| 3157 | 3208 | if let case Type::Nominal(NominalType::Record(recInfo)) = ty; |
|
| 3158 | 3209 | index < recInfo.fields.len |
| 4023 | 4074 | ) -> RecordType throws (ResolveError) { |
|
| 4024 | 4075 | if fields.len > parser::MAX_RECORD_FIELDS { |
|
| 4025 | 4076 | throw emitError(self, node, ErrorKind::Internal); |
|
| 4026 | 4077 | } |
|
| 4027 | 4078 | let a = alloc::arenaAllocator(&mut self.arena); |
|
| 4028 | - | let mut result: *mut [RecordField] = &mut []; |
|
| 4079 | + | let mut result = vec::Vec⟨RecordField⟩ { data: &mut [], len: 0 }; |
|
| 4029 | 4080 | let mut offset: u32 = 0; |
|
| 4030 | 4081 | let mut alignment: u32 = 1; |
|
| 4031 | 4082 | for fieldNode, i in fields { |
|
| 4032 | 4083 | let case ast::NodeValue::RecordField { |
|
| 4033 | 4084 | field: nameNode, |
| 4066 | 4117 | if labeled { |
|
| 4067 | 4118 | let requiredName = nameNode |
|
| 4068 | 4119 | else panic "buildRecordType: labeled record field missing name"; |
|
| 4069 | 4120 | set name = try nodeName(self, requiredName); |
|
| 4070 | 4121 | } |
|
| 4071 | - | result.append(RecordField { |
|
| 4122 | + | vec::append⟨RecordField⟩(&mut result, RecordField { |
|
| 4072 | 4123 | name, |
|
| 4073 | 4124 | fieldType, |
|
| 4074 | 4125 | offset: offset as i32, |
|
| 4075 | 4126 | }, a); |
|
| 4076 | 4127 | set offset += layout.size; |
|
| 4077 | 4128 | set alignment = max(alignment, layout.alignment); |
|
| 4078 | 4129 | } |
|
| 4079 | 4130 | return RecordType { |
|
| 4080 | - | fields: &result[..], |
|
| 4131 | + | fields: vec::view⟨RecordField⟩(&result), |
|
| 4081 | 4132 | labeled, |
|
| 4082 | 4133 | layout: Layout { |
|
| 4083 | 4134 | size: mem::alignUp(offset, alignment), |
|
| 4084 | 4135 | alignment, |
|
| 4085 | 4136 | }, |
| 4096 | 4147 | source: AggregateMemberSource, |
|
| 4097 | 4148 | ) -> UnionType throws (ResolveError) { |
|
| 4098 | 4149 | assert decl.variants.len <= MAX_UNION_VARIANTS, |
|
| 4099 | 4150 | "buildUnionType: maximum union variants exceeded"; |
|
| 4100 | 4151 | let a = alloc::arenaAllocator(&mut self.arena); |
|
| 4101 | - | let mut variants: *mut [UnionVariant] = &mut []; |
|
| 4152 | + | let mut variants = vec::Vec⟨UnionVariant⟩ { data: &mut [], len: 0 }; |
|
| 4102 | 4153 | let mut iota: u32 = 0; |
|
| 4103 | 4154 | let mut tagSubstitution: ?*Substitution = nil; |
|
| 4104 | 4155 | if let case AggregateMemberSource::Generic { |
|
| 4105 | 4156 | substitution, .. |
|
| 4106 | 4157 | } = source { |
| 4152 | 4203 | name, |
|
| 4153 | 4204 | variantNode, |
|
| 4154 | 4205 | 0, |
|
| 4155 | 4206 | ); |
|
| 4156 | 4207 | set symbol.moduleId = owner.moduleId; |
|
| 4157 | - | variants.append(UnionVariant { name, valueType, symbol }, a); |
|
| 4208 | + | vec::append⟨UnionVariant⟩( |
|
| 4209 | + | &mut variants, UnionVariant { name, valueType, symbol }, a |
|
| 4210 | + | ); |
|
| 4158 | 4211 | } |
|
| 4159 | - | let info = computeUnionLayout(&variants[..]); |
|
| 4212 | + | let variantView = vec::view⟨UnionVariant⟩(&variants); |
|
| 4213 | + | let info = computeUnionLayout(variantView); |
|
| 4160 | 4214 | return UnionType { |
|
| 4161 | - | variants: &variants[..], |
|
| 4215 | + | variants: variantView, |
|
| 4162 | 4216 | layout: info.layout, |
|
| 4163 | 4217 | valOffset: info.valOffset, |
|
| 4164 | 4218 | isAllVoid: info.isAllVoid, |
|
| 4165 | 4219 | declaredLinear, |
|
| 4166 | 4220 | }; |
| 4285 | 4339 | expected: template.params.len, |
|
| 4286 | 4340 | actual: app.args.len, |
|
| 4287 | 4341 | })); |
|
| 4288 | 4342 | } |
|
| 4289 | 4343 | let a = alloc::arenaAllocator(&mut self.arena); |
|
| 4290 | - | let mut args: *mut [*Type] = &mut []; |
|
| 4344 | + | let mut args = vec::Vec⟨*Type⟩ { data: &mut [], len: 0 }; |
|
| 4291 | 4345 | for argNode, i in app.args { |
|
| 4292 | 4346 | let argType = try resolveGenericArgument(self, argNode, template.params[i]); |
|
| 4293 | 4347 | if containsGenericParameter(argType) { |
|
| 4294 | 4348 | throw emitError(self, argNode, ErrorKind::GenericConcreteArgumentsRequired); |
|
| 4295 | 4349 | } |
|
| 4296 | - | args.append(allocType(self, argType), a); |
|
| 4350 | + | vec::append⟨*Type⟩(&mut args, allocType(self, argType), a); |
|
| 4297 | 4351 | } |
|
| 4298 | 4352 | let nominal = try specializeGenericData( |
|
| 4299 | - | self, node, templateSym, &args[..], rooted |
|
| 4353 | + | self, node, templateSym, vec::view⟨*Type⟩(&args), rooted |
|
| 4300 | 4354 | ); |
|
| 4301 | 4355 | ||
| 4302 | 4356 | setNodeSymbol(self, node, templateSym); |
|
| 4303 | 4357 | setNodeType(self, node, Type::Nominal(nominal)); |
|
| 4304 | 4358 | return nominal; |
| 4420 | 4474 | expected: template.params.len, |
|
| 4421 | 4475 | actual: app.args.len, |
|
| 4422 | 4476 | })); |
|
| 4423 | 4477 | } |
|
| 4424 | 4478 | let a = alloc::arenaAllocator(&mut self.arena); |
|
| 4425 | - | let mut args: *mut [*Type] = &mut []; |
|
| 4479 | + | let mut args = vec::Vec⟨*Type⟩ { data: &mut [], len: 0 }; |
|
| 4426 | 4480 | let caller = currentGenericTemplateSymbol(self); |
|
| 4427 | 4481 | for argNode, i in app.args { |
|
| 4428 | 4482 | let argType = try resolveGenericArgument(self, argNode, template.params[i]); |
|
| 4429 | 4483 | let symbolic = containsGenericParameter(argType); |
|
| 4430 | 4484 | if symbolic and caller == nil { |
| 4439 | 4493 | self, argNode, ErrorKind::GenericBoundUnsatisfied(bound.name) |
|
| 4440 | 4494 | ); |
|
| 4441 | 4495 | } |
|
| 4442 | 4496 | } |
|
| 4443 | 4497 | } |
|
| 4444 | - | args.append(allocType(self, argType), a); |
|
| 4498 | + | vec::append⟨*Type⟩(&mut args, allocType(self, argType), a); |
|
| 4445 | 4499 | } |
|
| 4500 | + | let argsView = vec::view⟨*Type⟩(&args); |
|
| 4446 | 4501 | if rooted { |
|
| 4447 | 4502 | if caller <> nil { |
|
| 4448 | 4503 | throw emitError(self, node, ErrorKind::GenericConcreteArgumentsRequired); |
|
| 4449 | 4504 | } |
|
| 4450 | 4505 | let specialization = try internGenericFnSpecialization( |
|
| 4451 | - | self, templateSym, &args[..], node, 0 |
|
| 4506 | + | self, templateSym, argsView, node, 0 |
|
| 4452 | 4507 | ); |
|
| 4453 | 4508 | setNodeSymbol(self, node, templateSym); |
|
| 4454 | 4509 | setNodeType(self, node, Type::Fn(specialization.fnType)); |
|
| 4455 | 4510 | set self.nodeData.entries[node.id].extra = |
|
| 4456 | 4511 | NodeExtra::GenericFnCall(specialization); |
|
| 4457 | 4512 | return specialization.fnType; |
|
| 4458 | 4513 | } |
|
| 4459 | 4514 | if caller == nil { |
|
| 4460 | - | if let existing = findGenericFnSpecialization(self, templateSym, &args[..]) { |
|
| 4515 | + | if let existing = findGenericFnSpecialization(self, templateSym, argsView) { |
|
| 4461 | 4516 | setNodeSymbol(self, node, templateSym); |
|
| 4462 | 4517 | setNodeType(self, node, Type::Fn(existing.fnType)); |
|
| 4463 | 4518 | set self.nodeData.entries[node.id].extra = |
|
| 4464 | 4519 | NodeExtra::GenericFnCall(existing); |
|
| 4465 | 4520 | return existing.fnType; |
|
| 4466 | 4521 | } |
|
| 4467 | 4522 | } |
|
| 4468 | - | let sub = Substitution { params: template.params, args: &args[..] }; |
|
| 4523 | + | let sub = Substitution { params: template.params, args: argsView }; |
|
| 4469 | 4524 | let applied = try substituteType(self, Type::Fn(signature), &sub, node); |
|
| 4470 | 4525 | let case Type::Fn(appliedFn) = applied |
|
| 4471 | 4526 | else throw emitError(self, node, ErrorKind::Internal); |
|
| 4472 | 4527 | recordGenericFnDependency( |
|
| 4473 | - | self, node, caller, templateSym, &args[..], appliedFn |
|
| 4528 | + | self, node, caller, templateSym, argsView, appliedFn |
|
| 4474 | 4529 | ); |
|
| 4475 | 4530 | return appliedFn; |
|
| 4476 | 4531 | } |
|
| 4477 | 4532 | ||
| 4478 | 4533 | /// Expand explicit roots through symbolic generic calls to a fixed point. |
| 4497 | 4552 | }; |
|
| 4498 | 4553 | let mut edge = self.genericFnDependencies; |
|
| 4499 | 4554 | while let dependency = edge { |
|
| 4500 | 4555 | if dependency.caller == specialization.template { |
|
| 4501 | 4556 | let a = alloc::arenaAllocator(&mut self.arena); |
|
| 4502 | - | let mut concreteArgs: *mut [*Type] = &mut []; |
|
| 4557 | + | let mut concreteArgs = vec::Vec⟨*Type⟩ { data: &mut [], len: 0 }; |
|
| 4503 | 4558 | for arg in dependency.args { |
|
| 4504 | 4559 | let concrete = try substituteType( |
|
| 4505 | 4560 | self, *arg, &callerSub, dependency.site |
|
| 4506 | 4561 | ); |
|
| 4507 | 4562 | if containsGenericParameter(concrete) { |
| 4509 | 4564 | self, |
|
| 4510 | 4565 | dependency.site, |
|
| 4511 | 4566 | ErrorKind::GenericConcreteArgumentsRequired, |
|
| 4512 | 4567 | ); |
|
| 4513 | 4568 | } |
|
| 4514 | - | concreteArgs.append(allocType(self, concrete), a); |
|
| 4569 | + | vec::append⟨*Type⟩( |
|
| 4570 | + | &mut concreteArgs, allocType(self, concrete), a |
|
| 4571 | + | ); |
|
| 4515 | 4572 | } |
|
| 4573 | + | let concreteArgsView = vec::view⟨*Type⟩(&concreteArgs); |
|
| 4516 | 4574 | let calleeTemplate = genericTemplateFor(self, dependency.callee) |
|
| 4517 | 4575 | else throw emitError( |
|
| 4518 | 4576 | self, dependency.site, ErrorKind::Internal |
|
| 4519 | 4577 | ); |
|
| 4520 | - | for arg, i in concreteArgs { |
|
| 4578 | + | for arg, i in concreteArgsView { |
|
| 4521 | 4579 | for bound in calleeTemplate.params[i].bounds { |
|
| 4522 | 4580 | if findInstance(self, bound, *arg) == nil { |
|
| 4523 | 4581 | throw emitError( |
|
| 4524 | 4582 | self, |
|
| 4525 | 4583 | dependency.site, |
| 4529 | 4587 | } |
|
| 4530 | 4588 | } |
|
| 4531 | 4589 | let concreteCallee = try internGenericFnSpecialization( |
|
| 4532 | 4590 | self, |
|
| 4533 | 4591 | dependency.callee, |
|
| 4534 | - | &concreteArgs[..], |
|
| 4592 | + | concreteArgsView, |
|
| 4535 | 4593 | dependency.site, |
|
| 4536 | 4594 | specialization.depth + 1, |
|
| 4537 | 4595 | ); |
|
| 4538 | 4596 | let resolution = try! alloc::alloc( |
|
| 4539 | 4597 | &mut self.arena, |
| 4594 | 4652 | ); |
|
| 4595 | 4653 | let sub = Substitution { |
|
| 4596 | 4654 | params: template.params, |
|
| 4597 | 4655 | args: specialization.args, |
|
| 4598 | 4656 | }; |
|
| 4599 | - | for typeUse in template.typeUses { |
|
| 4657 | + | for typeUse in vec::view⟨GenericTypeUse⟩(&template.typeUses) { |
|
| 4600 | 4658 | let concrete = try substituteType( |
|
| 4601 | 4659 | self, typeUse.ty, &sub, typeUse.site |
|
| 4602 | 4660 | ); |
|
| 4603 | 4661 | if containsGenericParameter(concrete) { |
|
| 4604 | 4662 | throw emitError( |
| 5506 | 5564 | ) -> *[*GenericParamType] throws (ResolveError) { |
|
| 5507 | 5565 | if nodes.len > MAX_GENERIC_PARAMS { |
|
| 5508 | 5566 | throw emitError(self, owner, ErrorKind::GenericParameterLimit); |
|
| 5509 | 5567 | } |
|
| 5510 | 5568 | let a = alloc::arenaAllocator(&mut self.arena); |
|
| 5511 | - | let mut result: *mut [*GenericParamType] = &mut []; |
|
| 5569 | + | let mut result = vec::Vec⟨*GenericParamType⟩ { data: &mut [], len: 0 }; |
|
| 5512 | 5570 | for paramNode, index in nodes { |
|
| 5513 | 5571 | let case ast::NodeValue::GenericParam(param) = paramNode.value |
|
| 5514 | 5572 | else throw emitError(self, paramNode, ErrorKind::Internal); |
|
| 5515 | 5573 | let mut paramName: *[u8] = undefined; |
|
| 5516 | 5574 | let mut nameNode: *ast::Node = undefined; |
|
| 5517 | - | let mut traitBounds: *mut [*TraitType] = &mut []; |
|
| 5575 | + | let mut traitBounds = vec::Vec⟨*TraitType⟩ { data: &mut [], len: 0 }; |
|
| 5518 | 5576 | let mut constType: ?*Type = nil; |
|
| 5519 | 5577 | match param { |
|
| 5520 | 5578 | case ast::GenericParam::Const { name, type } => { |
|
| 5521 | 5579 | set nameNode = name; |
|
| 5522 | 5580 | set paramName = try nodeName(self, name); |
| 5533 | 5591 | let boundSym = try resolveNamePath(self, bound); |
|
| 5534 | 5592 | let case SymbolData::Trait(traitInfo) = boundSym.data else { |
|
| 5535 | 5593 | throw emitError(self, bound, ErrorKind::GenericBoundNotTrait); |
|
| 5536 | 5594 | }; |
|
| 5537 | 5595 | setNodeSymbol(self, bound, boundSym); |
|
| 5538 | - | traitBounds.append(traitInfo, a); |
|
| 5596 | + | vec::append⟨*TraitType⟩(&mut traitBounds, traitInfo, a); |
|
| 5539 | 5597 | } |
|
| 5540 | 5598 | } |
|
| 5541 | 5599 | } |
|
| 5542 | 5600 | let used = try! alloc::alloc( |
|
| 5543 | 5601 | &mut self.arena, @sizeOf(bool), @alignOf(bool) |
| 5551 | 5609 | set *p = GenericParamType { |
|
| 5552 | 5610 | owner, |
|
| 5553 | 5611 | node: paramNode, |
|
| 5554 | 5612 | name: paramName, |
|
| 5555 | 5613 | index, |
|
| 5556 | - | bounds: &traitBounds[..], |
|
| 5614 | + | bounds: vec::view⟨*TraitType⟩(&traitBounds), |
|
| 5557 | 5615 | used, |
|
| 5558 | 5616 | constType, |
|
| 5559 | 5617 | }; |
|
| 5560 | 5618 | let data = SymbolData::ConstParameter(p) if constType <> nil |
|
| 5561 | 5619 | else SymbolData::TypeParameter(p); |
| 5568 | 5626 | setNodeType(self, paramNode, *ty); |
|
| 5569 | 5627 | } else { |
|
| 5570 | 5628 | setNodeType(self, nameNode, Type::Parameter(p)); |
|
| 5571 | 5629 | setNodeType(self, paramNode, Type::Parameter(p)); |
|
| 5572 | 5630 | } |
|
| 5573 | - | result.append(p, a); |
|
| 5631 | + | vec::append⟨*GenericParamType⟩(&mut result, p, a); |
|
| 5574 | 5632 | } |
|
| 5575 | - | return &result[..]; |
|
| 5633 | + | return vec::view⟨*GenericParamType⟩(&result); |
|
| 5576 | 5634 | } |
|
| 5577 | 5635 | ||
| 5578 | 5636 | /// Retrieve sparse metadata for a generic declaration symbol. |
|
| 5579 | 5637 | export fn genericTemplateFor(self: *Resolver, symbol: *Symbol) -> ?*GenericTemplate { |
|
| 5580 | 5638 | let mut cursor = self.genericTemplates; |
| 5667 | 5725 | { |
|
| 5668 | 5726 | throw emitError(self, node, ErrorKind::GenericFnAttribute); |
|
| 5669 | 5727 | } |
|
| 5670 | 5728 | } |
|
| 5671 | 5729 | let a = alloc::arenaAllocator(&mut self.arena); |
|
| 5672 | - | let mut paramTypes: *mut [*Type] = &mut []; |
|
| 5673 | - | let mut throwList: *mut [*Type] = &mut []; |
|
| 5730 | + | let mut paramTypes = vec::Vec⟨*Type⟩ { data: &mut [], len: 0 }; |
|
| 5731 | + | let mut throwList = vec::Vec⟨*Type⟩ { data: &mut [], len: 0 }; |
|
| 5674 | 5732 | let mut fnType = FnType { |
|
| 5675 | 5733 | paramTypes: &[], |
|
| 5676 | 5734 | returnType: allocType(self, Type::Void), |
|
| 5677 | 5735 | throwList: &[], |
|
| 5678 | 5736 | isUnsafe: ast::hasAttribute(attrMask, ast::Attribute::Unsafe), |
| 5711 | 5769 | self, paramNode, typeContext |
|
| 5712 | 5770 | ) catch e { |
|
| 5713 | 5771 | exitFn(self); |
|
| 5714 | 5772 | throw e; |
|
| 5715 | 5773 | }; |
|
| 5716 | - | paramTypes.append(allocType(self, paramTy), a); |
|
| 5774 | + | vec::append⟨*Type⟩(&mut paramTypes, allocType(self, paramTy), a); |
|
| 5717 | 5775 | } |
|
| 5718 | 5776 | ||
| 5719 | 5777 | if decl.sig.throwList.len > MAX_FN_THROWS { |
|
| 5720 | 5778 | exitFn(self); |
|
| 5721 | 5779 | throw emitError(self, node, ErrorKind::FnThrowOverflow(CountMismatch { |
| 5732 | 5790 | }; |
|
| 5733 | 5791 | try ensureStorableType(self, throwNode, throwTy) catch e { |
|
| 5734 | 5792 | exitFn(self); |
|
| 5735 | 5793 | throw e; |
|
| 5736 | 5794 | }; |
|
| 5737 | - | throwList.append(allocType(self, throwTy), a); |
|
| 5795 | + | vec::append⟨*Type⟩(&mut throwList, allocType(self, throwTy), a); |
|
| 5738 | 5796 | } |
|
| 5739 | 5797 | exitFn(self); |
|
| 5740 | - | set fnType.paramTypes = ¶mTypes[..]; |
|
| 5741 | - | set fnType.throwList = &throwList[..]; |
|
| 5798 | + | set fnType.paramTypes = vec::view⟨*Type⟩(¶mTypes); |
|
| 5799 | + | set fnType.throwList = vec::view⟨*Type⟩(&throwList); |
|
| 5742 | 5800 | ||
| 5743 | 5801 | let fnInfo = allocFnType(self, fnType); |
|
| 5744 | 5802 | let ty = Type::Fn(fnInfo); |
|
| 5745 | 5803 | let sym = try bindValueIdent(self, decl.name, node, ty, false, 0, attrMask) |
|
| 5746 | 5804 | else throw emitError(self, node, ErrorKind::ExpectedIdentifier); |
| 5751 | 5809 | params: genericParams, |
|
| 5752 | 5810 | signature: fnInfo, |
|
| 5753 | 5811 | members: &[], |
|
| 5754 | 5812 | declaredLinear: false, |
|
| 5755 | 5813 | bodyResolved: false, |
|
| 5756 | - | typeUses: &mut [], |
|
| 5814 | + | typeUses: vec::Vec⟨GenericTypeUse⟩ { data: &mut [], len: 0 }, |
|
| 5757 | 5815 | next: nil, |
|
| 5758 | 5816 | }); |
|
| 5759 | 5817 | } |
|
| 5760 | 5818 | return ty; |
|
| 5761 | 5819 | } |
| 5928 | 5986 | params: genericParams, |
|
| 5929 | 5987 | signature: nil, |
|
| 5930 | 5988 | members: &[], |
|
| 5931 | 5989 | declaredLinear, |
|
| 5932 | 5990 | bodyResolved: true, |
|
| 5933 | - | typeUses: &mut [], |
|
| 5991 | + | typeUses: vec::Vec⟨GenericTypeUse⟩ { data: &mut [], len: 0 }, |
|
| 5934 | 5992 | next: nil, |
|
| 5935 | 5993 | }); |
|
| 5936 | 5994 | let a = alloc::arenaAllocator(&mut self.arena); |
|
| 5937 | - | let mut memberTypes: *mut [*Type] = &mut []; |
|
| 5995 | + | let mut memberTypes = vec::Vec⟨*Type⟩ { data: &mut [], len: 0 }; |
|
| 5938 | 5996 | for member in members { |
|
| 5939 | 5997 | let memberTy = try resolveGenericDataMember(self, member) catch e { |
|
| 5940 | 5998 | exitScope(self); |
|
| 5941 | 5999 | throw e; |
|
| 5942 | 6000 | }; |
|
| 5943 | - | memberTypes.append(allocType(self, memberTy), a); |
|
| 6001 | + | vec::append⟨*Type⟩(&mut memberTypes, allocType(self, memberTy), a); |
|
| 5944 | 6002 | } |
|
| 5945 | 6003 | exitScope(self); |
|
| 5946 | - | set metadata.members = &memberTypes[..]; |
|
| 6004 | + | set metadata.members = vec::view⟨*Type⟩(&memberTypes); |
|
| 5947 | 6005 | } |
|
| 5948 | 6006 | ||
| 5949 | 6007 | /// Resolve record field types for a named record declaration. |
|
| 5950 | 6008 | fn resolveRecordBody(self: *mut Resolver, node: *ast::Node, decl: ast::RecordDecl) |
|
| 5951 | 6009 | throws (ResolveError) |
| 6015 | 6073 | }; |
|
| 6016 | 6074 | set *entry = TraitType { |
|
| 6017 | 6075 | name, |
|
| 6018 | 6076 | moduleId: self.currentMod, |
|
| 6019 | 6077 | nodeId: node.id, |
|
| 6020 | - | methods: &mut [], |
|
| 6021 | - | supertraits: &mut [], |
|
| 6078 | + | methods: vec::Vec⟨TraitMethod⟩ { data: &mut [], len: 0 }, |
|
| 6079 | + | supertraits: vec::Vec⟨*TraitType⟩ { data: &mut [], len: 0 }, |
|
| 6022 | 6080 | selfType, |
|
| 6023 | 6081 | state: TraitState::Queued, |
|
| 6024 | 6082 | objectSafe: true, |
|
| 6025 | 6083 | }; |
|
| 6026 | 6084 | return entry; |
| 6048 | 6106 | } |
|
| 6049 | 6107 | ||
| 6050 | 6108 | /// Find a trait method by name. |
|
| 6051 | 6109 | export fn findTraitMethod(traitType: *TraitType, name: *[u8]) -> ?*TraitMethod { |
|
| 6052 | 6110 | for i in 0..traitType.methods.len { |
|
| 6053 | - | if traitType.methods[i].name == name { |
|
| 6054 | - | return &traitType.methods[i]; |
|
| 6111 | + | if traitType.methods.data[i].name == name { |
|
| 6112 | + | return &traitType.methods.data[i]; |
|
| 6055 | 6113 | } |
|
| 6056 | 6114 | } |
|
| 6057 | 6115 | return nil; |
|
| 6058 | 6116 | } |
|
| 6059 | 6117 |
| 6116 | 6174 | expected: ast::MAX_TRAIT_METHODS, |
|
| 6117 | 6175 | actual: traitType.methods.len as u32 + superTrait.methods.len as u32, |
|
| 6118 | 6176 | })); |
|
| 6119 | 6177 | } |
|
| 6120 | 6178 | // Copy inherited methods into this trait's method table. |
|
| 6121 | - | for inherited in superTrait.methods { |
|
| 6179 | + | for inherited in vec::view⟨TraitMethod⟩(&superTrait.methods) { |
|
| 6122 | 6180 | if let _ = findTraitMethod(traitType, inherited.name) { |
|
| 6123 | 6181 | throw emitError(self, superNode, ErrorKind::DuplicateBinding(inherited.name)); |
|
| 6124 | 6182 | } |
|
| 6125 | - | traitType.methods.append(TraitMethod { |
|
| 6183 | + | vec::append⟨TraitMethod⟩(&mut traitType.methods, TraitMethod { |
|
| 6126 | 6184 | name: inherited.name, |
|
| 6127 | 6185 | fnType: inherited.fnType, |
|
| 6128 | 6186 | mutable: inherited.mutable, |
|
| 6129 | 6187 | receiverClass: inherited.receiverClass, |
|
| 6130 | 6188 | owner: inherited.owner, |
|
| 6131 | - | index: traitType.methods.len as u32, |
|
| 6189 | + | index: traitType.methods.len, |
|
| 6132 | 6190 | }, a); |
|
| 6133 | 6191 | } |
|
| 6134 | - | traitType.supertraits.append(superTrait, a); |
|
| 6192 | + | vec::append⟨*TraitType⟩(&mut traitType.supertraits, superTrait, a); |
|
| 6135 | 6193 | if not superTrait.objectSafe { |
|
| 6136 | 6194 | set traitType.objectSafe = false; |
|
| 6137 | 6195 | } |
|
| 6138 | 6196 | } |
|
| 6139 | 6197 |
| 6171 | 6229 | if receiverTargetName <> traitType.name { |
|
| 6172 | 6230 | throw emitError(self, receiver, ErrorKind::TraitReceiverMismatch); |
|
| 6173 | 6231 | } |
|
| 6174 | 6232 | // Resolve parameter types and return type. |
|
| 6175 | 6233 | let a = alloc::arenaAllocator(&mut self.arena); |
|
| 6176 | - | let mut paramTypes: *mut [*Type] = &mut []; |
|
| 6177 | - | let mut throwList: *mut [*Type] = &mut []; |
|
| 6234 | + | let mut paramTypes = vec::Vec⟨*Type⟩ { data: &mut [], len: 0 }; |
|
| 6235 | + | let mut throwList = vec::Vec⟨*Type⟩ { data: &mut [], len: 0 }; |
|
| 6178 | 6236 | let mut retType = allocType(self, Type::Void); |
|
| 6179 | 6237 | ||
| 6180 | 6238 | if sig.params.len > MAX_FN_PARAMS { |
|
| 6181 | 6239 | throw emitError(self, methodNode, ErrorKind::FnParamOverflow(CountMismatch { |
|
| 6182 | 6240 | expected: MAX_FN_PARAMS, |
| 6185 | 6243 | } |
|
| 6186 | 6244 | for paramNode in sig.params { |
|
| 6187 | 6245 | let case ast::NodeValue::FnParam(param) = paramNode.value |
|
| 6188 | 6246 | else throw emitError(self, paramNode, ErrorKind::ExpectedIdentifier); |
|
| 6189 | 6247 | let paramTy = try resolveTraitSignatureType(self, traitType, param.type); |
|
| 6190 | - | paramTypes.append(allocType(self, paramTy), a); |
|
| 6248 | + | vec::append⟨*Type⟩(&mut paramTypes, allocType(self, paramTy), a); |
|
| 6191 | 6249 | } |
|
| 6192 | 6250 | if let ret = sig.returnType { |
|
| 6193 | 6251 | set retType = allocType( |
|
| 6194 | 6252 | self, try resolveTraitSignatureType(self, traitType, ret) |
|
| 6195 | 6253 | ); |
| 6201 | 6259 | actual: sig.throwList.len, |
|
| 6202 | 6260 | })); |
|
| 6203 | 6261 | } |
|
| 6204 | 6262 | for throwNode in sig.throwList { |
|
| 6205 | 6263 | let throwTy = try resolveTraitSignatureType(self, traitType, throwNode); |
|
| 6206 | - | throwList.append(allocType(self, throwTy), a); |
|
| 6264 | + | vec::append⟨*Type⟩(&mut throwList, allocType(self, throwTy), a); |
|
| 6207 | 6265 | } |
|
| 6208 | 6266 | let fnType = FnType { |
|
| 6209 | - | paramTypes: ¶mTypes[..], |
|
| 6267 | + | paramTypes: vec::view⟨*Type⟩(¶mTypes), |
|
| 6210 | 6268 | returnType: retType, |
|
| 6211 | - | throwList: &throwList[..], |
|
| 6269 | + | throwList: vec::view⟨*Type⟩(&throwList), |
|
| 6212 | 6270 | isUnsafe: ast::hasAttribute(attrMask, ast::Attribute::Unsafe), |
|
| 6213 | 6271 | localCount: 0, |
|
| 6214 | 6272 | }; |
|
| 6215 | 6273 | if containsGenericParameter(Type::Fn(&fnType)) { |
|
| 6216 | 6274 | set traitType.objectSafe = false; |
|
| 6217 | 6275 | } |
|
| 6218 | - | traitType.methods.append(TraitMethod { |
|
| 6276 | + | vec::append⟨TraitMethod⟩(&mut traitType.methods, TraitMethod { |
|
| 6219 | 6277 | name: methodName, |
|
| 6220 | 6278 | fnType: allocFnType(self, fnType), |
|
| 6221 | 6279 | mutable, |
|
| 6222 | 6280 | receiverClass, |
|
| 6223 | 6281 | owner: traitType, |
|
| 6224 | - | index: traitType.methods.len as u32, |
|
| 6282 | + | index: traitType.methods.len, |
|
| 6225 | 6283 | }, a); |
|
| 6226 | 6284 | ||
| 6227 | 6285 | setNodeType(self, methodNode, Type::Void); |
|
| 6228 | 6286 | } |
|
| 6229 | 6287 | set traitType.state = TraitState::Complete; |
| 6409 | 6467 | } |
|
| 6410 | 6468 | } |
|
| 6411 | 6469 | ||
| 6412 | 6470 | // Build final function type: receiver plus trait's canonical types. |
|
| 6413 | 6471 | let a = alloc::arenaAllocator(&mut self.arena); |
|
| 6414 | - | // TODO: Improve this pattern, maybe via something like `(&[]).append(..)`? |
|
| 6415 | - | let mut paramTypes: *mut [*Type] = &mut []; |
|
| 6416 | - | paramTypes.append(allocType(self, receiverPtrType), a); |
|
| 6472 | + | let mut paramTypes = vec::Vec⟨*Type⟩ { data: &mut [], len: 0 }; |
|
| 6473 | + | vec::append⟨*Type⟩( |
|
| 6474 | + | &mut paramTypes, allocType(self, receiverPtrType), a |
|
| 6475 | + | ); |
|
| 6417 | 6476 | ||
| 6418 | 6477 | for ty in expectedFn.paramTypes { |
|
| 6419 | - | paramTypes.append(ty, a); |
|
| 6478 | + | vec::append⟨*Type⟩(&mut paramTypes, ty, a); |
|
| 6420 | 6479 | } |
|
| 6421 | 6480 | let fnType = FnType { |
|
| 6422 | - | paramTypes: ¶mTypes[..], |
|
| 6481 | + | paramTypes: vec::view⟨*Type⟩(¶mTypes), |
|
| 6423 | 6482 | returnType: expectedFn.returnType, |
|
| 6424 | 6483 | throwList: expectedFn.throwList, |
|
| 6425 | 6484 | isUnsafe: expectedFn.isUnsafe, |
|
| 6426 | 6485 | localCount: 0, |
|
| 6427 | 6486 | }; |
| 6443 | 6502 | set entry.methods[tm.index] = sym; |
|
| 6444 | 6503 | set covered[tm.index] = true; |
|
| 6445 | 6504 | } |
|
| 6446 | 6505 | ||
| 6447 | 6506 | // Fill inherited method slots from supertrait instances. |
|
| 6448 | - | for superTrait in traitInfo.supertraits { |
|
| 6507 | + | for superTrait in vec::view⟨*TraitType⟩(&traitInfo.supertraits) { |
|
| 6449 | 6508 | let superInst = findInstance(self, superTrait, concreteType) |
|
| 6450 | 6509 | else throw emitError(self, node, ErrorKind::MissingSupertraitInstance(superTrait.name)); |
|
| 6451 | - | for superMethod, mi in superTrait.methods { |
|
| 6510 | + | for superMethod, mi in vec::view⟨TraitMethod⟩(&superTrait.methods) { |
|
| 6452 | 6511 | let merged = findTraitMethod(traitInfo, superMethod.name) |
|
| 6453 | 6512 | else panic "resolveInstanceDecl: inherited method not found"; |
|
| 6454 | 6513 | if not covered[merged.index] { |
|
| 6455 | 6514 | set entry.methods[merged.index] = superInst.methods[mi]; |
|
| 6456 | 6515 | set covered[merged.index] = true; |
|
| 6457 | 6516 | } |
|
| 6458 | 6517 | } |
|
| 6459 | 6518 | } |
|
| 6460 | 6519 | ||
| 6461 | 6520 | // Check that all trait methods are implemented. |
|
| 6462 | - | for method, i in traitInfo.methods { |
|
| 6521 | + | for method, i in vec::view⟨TraitMethod⟩(&traitInfo.methods) { |
|
| 6463 | 6522 | if not covered[i] { |
|
| 6464 | 6523 | throw emitError(self, node, ErrorKind::MissingTraitMethod(method.name)); |
|
| 6465 | 6524 | } |
|
| 6466 | 6525 | } |
|
| 6467 | 6526 | set self.instances[self.instancesLen] = entry; |
| 6573 | 6632 | throw emitError(self, name, ErrorKind::DuplicateBinding(methodName)); |
|
| 6574 | 6633 | } |
|
| 6575 | 6634 | ||
| 6576 | 6635 | // Resolve parameter types. |
|
| 6577 | 6636 | let a = alloc::arenaAllocator(&mut self.arena); |
|
| 6578 | - | let mut paramTypes: *mut [*Type] = &mut []; |
|
| 6637 | + | let mut paramTypes = vec::Vec⟨*Type⟩ { data: &mut [], len: 0 }; |
|
| 6579 | 6638 | ||
| 6580 | 6639 | // Receiver is the first parameter. |
|
| 6581 | 6640 | let receiverPtrType = Type::Pointer(PointerType { |
|
| 6582 | 6641 | class: receiver.class, |
|
| 6583 | 6642 | target: allocType(self, concreteType), |
|
| 6584 | 6643 | mutable: receiver.mutable, |
|
| 6585 | 6644 | }); |
|
| 6586 | - | paramTypes.append(allocType(self, receiverPtrType), a); |
|
| 6645 | + | vec::append⟨*Type⟩( |
|
| 6646 | + | &mut paramTypes, allocType(self, receiverPtrType), a |
|
| 6647 | + | ); |
|
| 6587 | 6648 | ||
| 6588 | 6649 | for paramNode in sig.params { |
|
| 6589 | 6650 | let case ast::NodeValue::FnParam(param) = paramNode.value |
|
| 6590 | 6651 | else throw emitError(self, paramNode, ErrorKind::ExpectedIdentifier); |
|
| 6591 | 6652 | let paramTy = try resolveValueType(self, param.type); |
|
| 6592 | - | paramTypes.append(allocType(self, paramTy), a); |
|
| 6653 | + | vec::append⟨*Type⟩(&mut paramTypes, allocType(self, paramTy), a); |
|
| 6593 | 6654 | } |
|
| 6594 | 6655 | ||
| 6595 | 6656 | // Resolve return type. |
|
| 6596 | 6657 | let mut returnType = Type::Void; |
|
| 6597 | 6658 | if let retNode = sig.returnType { |
|
| 6598 | 6659 | set returnType = try resolveValueType(self, retNode); |
|
| 6599 | 6660 | } |
|
| 6600 | 6661 | ||
| 6601 | 6662 | // Resolve throw list. |
|
| 6602 | - | let mut throwTypes: *mut [*Type] = &mut []; |
|
| 6663 | + | let mut throwTypes = vec::Vec⟨*Type⟩ { data: &mut [], len: 0 }; |
|
| 6603 | 6664 | for throwNode in sig.throwList { |
|
| 6604 | 6665 | let throwTy = try resolveValueType(self, throwNode); |
|
| 6605 | - | throwTypes.append(allocType(self, throwTy), a); |
|
| 6666 | + | vec::append⟨*Type⟩(&mut throwTypes, allocType(self, throwTy), a); |
|
| 6606 | 6667 | } |
|
| 6607 | 6668 | ||
| 6608 | 6669 | let retTypePtr = allocType(self, returnType); |
|
| 6609 | - | let throwList = &throwTypes[..]; |
|
| 6670 | + | let throwList = vec::view⟨*Type⟩(&throwTypes); |
|
| 6671 | + | let paramTypesView = vec::view⟨*Type⟩(¶mTypes); |
|
| 6610 | 6672 | ||
| 6611 | 6673 | let isUnsafe = ast::hasAttribute(attrMask, ast::Attribute::Unsafe); |
|
| 6612 | 6674 | // Full function type (receiver + params) for lowering. |
|
| 6613 | 6675 | let fullFnType = FnType { |
|
| 6614 | - | paramTypes: ¶mTypes[..], |
|
| 6676 | + | paramTypes: paramTypesView, |
|
| 6615 | 6677 | returnType: retTypePtr, |
|
| 6616 | 6678 | throwList, |
|
| 6617 | 6679 | isUnsafe, |
|
| 6618 | 6680 | localCount: 0, |
|
| 6619 | 6681 | }; |
|
| 6620 | 6682 | let fnTy = Type::Fn(allocFnType(self, fullFnType)); |
|
| 6621 | 6683 | ||
| 6622 | 6684 | // Function type excluding receiver, for call arg checking. |
|
| 6623 | 6685 | let checkFnType = FnType { |
|
| 6624 | - | paramTypes: ¶mTypes[1..], |
|
| 6686 | + | paramTypes: ¶mTypesView[1..], |
|
| 6625 | 6687 | returnType: retTypePtr, |
|
| 6626 | 6688 | throwList, |
|
| 6627 | 6689 | isUnsafe, |
|
| 6628 | 6690 | localCount: 0, |
|
| 6629 | 6691 | }; |
| 6921 | 6983 | } else => {} |
|
| 6922 | 6984 | } |
|
| 6923 | 6985 | } |
|
| 6924 | 6986 | case Type::Array(arrayInfo) => { |
|
| 6925 | 6987 | if let case ast::NodeValue::ArrayLit(items) = pattern.value { |
|
| 6926 | - | if items.len as u32 <> arrayInfo.length { |
|
| 6988 | + | let length = concreteArrayLength(arrayInfo.length) |
|
| 6989 | + | else throw emitError(self, pattern, ErrorKind::ConstExprRequired); |
|
| 6990 | + | if items.len as u32 <> length { |
|
| 6927 | 6991 | throw emitError(self, pattern, ErrorKind::RecordFieldCountMismatch( |
|
| 6928 | - | CountMismatch { expected: arrayInfo.length, actual: items.len as u32 } |
|
| 6992 | + | CountMismatch { expected: length, actual: items.len as u32 } |
|
| 6929 | 6993 | )); |
|
| 6930 | 6994 | } |
|
| 6931 | 6995 | let elemTy = *arrayInfo.item; |
|
| 6932 | 6996 | for item in items { |
|
| 6933 | 6997 | try resolveCasePattern(self, item, elemTy, IdentMode::Bind, matchBy); |
| 7780 | 7844 | self: *mut Resolver, |
|
| 7781 | 7845 | node: *ast::Node, |
|
| 7782 | 7846 | kind: ast::Builtin, |
|
| 7783 | 7847 | args: *mut [*ast::Node] |
|
| 7784 | 7848 | ) -> Type throws (ResolveError) { |
|
| 7785 | - | // Handle `@sliceOf(ptr, len)` and `@sliceOf(ptr, len, cap)`. |
|
| 7849 | + | // Handle `@sliceOf(ptr, len)`. |
|
| 7786 | 7850 | if kind == ast::Builtin::SliceOf { |
|
| 7787 | - | if args.len <> 2 and args.len <> 3 { |
|
| 7851 | + | if args.len <> 2 { |
|
| 7788 | 7852 | throw emitError(self, node, ErrorKind::BuiltinArgCountMismatch(CountMismatch { |
|
| 7789 | 7853 | expected: 2, |
|
| 7790 | 7854 | actual: args.len as u32, |
|
| 7791 | 7855 | })); |
|
| 7792 | 7856 | } |
|
| 7793 | 7857 | let ptrType = try visit(self, args[0], Type::Unknown); |
|
| 7794 | 7858 | let case Type::Pointer(ptr) = ptrType else { |
|
| 7795 | 7859 | throw emitError(self, node, ErrorKind::ExpectedPointer); |
|
| 7796 | 7860 | }; |
|
| 7797 | 7861 | let _ = try checkAssignable(self, args[1], Type::U32); |
|
| 7798 | - | if args.len == 3 { |
|
| 7799 | - | let _ = try checkAssignable(self, args[2], Type::U32); |
|
| 7800 | - | } |
|
| 7801 | 7862 | return setNodeType(self, node, Type::Slice(SliceType { |
|
| 7802 | 7863 | class: ptr.class, |
|
| 7803 | 7864 | item: ptr.target, |
|
| 7804 | 7865 | mutable: ptr.mutable, |
|
| 7805 | 7866 | })); |
|
| 7806 | 7867 | } |
|
| 7868 | + | if kind == ast::Builtin::Relocate { |
|
| 7869 | + | if args.len <> 2 { |
|
| 7870 | + | throw emitError(self, node, ErrorKind::BuiltinArgCountMismatch(CountMismatch { |
|
| 7871 | + | expected: 2, |
|
| 7872 | + | actual: args.len as u32, |
|
| 7873 | + | })); |
|
| 7874 | + | } |
|
| 7875 | + | let destinationType = try visit(self, args[0], Type::Unknown); |
|
| 7876 | + | let case Type::Slice(destination) = destinationType else { |
|
| 7877 | + | throw emitError(self, args[0], ErrorKind::ExpectedIndexable); |
|
| 7878 | + | }; |
|
| 7879 | + | if not destination.mutable or not typesEqual(*destination.item, Type::U8) { |
|
| 7880 | + | throw emitTypeMismatch(self, args[0], TypeMismatch { |
|
| 7881 | + | expected: Type::Slice(SliceType { |
|
| 7882 | + | class: destination.class, |
|
| 7883 | + | item: allocType(self, Type::U8), |
|
| 7884 | + | mutable: true, |
|
| 7885 | + | }), |
|
| 7886 | + | actual: destinationType, |
|
| 7887 | + | }); |
|
| 7888 | + | } |
|
| 7889 | + | let sourceType = try visit(self, args[1], Type::Unknown); |
|
| 7890 | + | let case Type::Slice(source) = sourceType else { |
|
| 7891 | + | throw emitError(self, args[1], ErrorKind::ExpectedIndexable); |
|
| 7892 | + | }; |
|
| 7893 | + | if not source.mutable or not typesEqual(*source.item, Type::U8) { |
|
| 7894 | + | throw emitTypeMismatch(self, args[1], TypeMismatch { |
|
| 7895 | + | expected: Type::Slice(SliceType { |
|
| 7896 | + | class: source.class, |
|
| 7897 | + | item: allocType(self, Type::U8), |
|
| 7898 | + | mutable: true, |
|
| 7899 | + | }), |
|
| 7900 | + | actual: sourceType, |
|
| 7901 | + | }); |
|
| 7902 | + | } |
|
| 7903 | + | return setNodeType(self, node, Type::Void); |
|
| 7904 | + | } |
|
| 7807 | 7905 | if args.len <> 1 { |
|
| 7808 | 7906 | throw emitError(self, node, ErrorKind::BuiltinArgCountMismatch(CountMismatch { |
|
| 7809 | 7907 | expected: 1, |
|
| 7810 | 7908 | actual: args.len as u32, |
|
| 7811 | 7909 | })); |
|
| 7812 | 7910 | } |
|
| 7813 | 7911 | ||
| 7814 | 7912 | let ty = try resolveValueType(self, args[0]); |
|
| 7913 | + | recordGenericTypeUse(self, node, ty); |
|
| 7914 | + | if containsGenericParameter(ty) { |
|
| 7915 | + | return setNodeType(self, node, Type::U32); |
|
| 7916 | + | } |
|
| 7815 | 7917 | // Ensure the type body is resolved before computing layout. |
|
| 7816 | 7918 | // TODO: Somehow, ensuring the type is resolved should just happen all |
|
| 7817 | 7919 | // the time, lazily. |
|
| 7818 | 7920 | try ensureTypeResolved(self, ty, args[0]); |
|
| 7819 | - | if containsGenericParameter(ty) { |
|
| 7820 | - | throw emitError(self, args[0], ErrorKind::GenericLayoutRequired); |
|
| 7821 | - | } |
|
| 7822 | 7921 | // TODO: This should be stored in `symbol` instead of having to recompute it. |
|
| 7823 | 7922 | // That way there's a canonical place to look for code gen. |
|
| 7824 | 7923 | let layout = getTypeLayout(ty); |
|
| 7825 | - | ||
| 7826 | 7924 | // Evaluate the built-in. |
|
| 7827 | 7925 | let mut value: u32 = undefined; |
|
| 7828 | 7926 | match kind { |
|
| 7829 | 7927 | case ast::Builtin::SizeOf => { |
|
| 7830 | 7928 | set value = layout.size; |
| 7833 | 7931 | set value = layout.alignment; |
|
| 7834 | 7932 | }, |
|
| 7835 | 7933 | case ast::Builtin::SliceOf => { |
|
| 7836 | 7934 | panic "unreachable: @sliceOf handled above"; |
|
| 7837 | 7935 | } |
|
| 7936 | + | case ast::Builtin::Relocate => { |
|
| 7937 | + | panic "resolveBuiltinCall: unreachable relocation builtin"; |
|
| 7938 | + | } |
|
| 7838 | 7939 | } |
|
| 7839 | 7940 | // Record as constant value for constant folding. |
|
| 7840 | 7941 | setNodeConstValue(self, node, ConstValue::Int(ConstInt { |
|
| 7841 | 7942 | magnitude: value as u64, |
|
| 7842 | 7943 | bits: 32, |
| 7891 | 7992 | return true; |
|
| 7892 | 7993 | } |
|
| 7893 | 7994 | } |
|
| 7894 | 7995 | return typesEqual(pattern, evidence); |
|
| 7895 | 7996 | } |
|
| 7997 | + | if let case Type::ConstParameter(param) = pattern { |
|
| 7998 | + | let case Type::ConstArgument { .. } = actual else return false; |
|
| 7999 | + | for candidate, i in params { |
|
| 8000 | + | if candidate == param { |
|
| 8001 | + | if let prior = inferred[i] { |
|
| 8002 | + | return typesEqual(*prior, actual); |
|
| 8003 | + | } |
|
| 8004 | + | set inferred[i] = allocType(self, actual); |
|
| 8005 | + | return true; |
|
| 8006 | + | } |
|
| 8007 | + | } |
|
| 8008 | + | return typesEqual(pattern, actual); |
|
| 8009 | + | } |
|
| 7896 | 8010 | if typesEqual(pattern, actual) { |
|
| 7897 | 8011 | return true; |
|
| 7898 | 8012 | } |
|
| 7899 | 8013 | if not containsGenericParameter(pattern) { |
|
| 7900 | 8014 | return true; |
| 7930 | 8044 | self, *inner, *actualInner, params, inferred |
|
| 7931 | 8045 | ); |
|
| 7932 | 8046 | } |
|
| 7933 | 8047 | case Type::Array(array) => { |
|
| 7934 | 8048 | let case Type::Array(actualArray) = actual else return false; |
|
| 7935 | - | return array.length == actualArray.length and inferGenericArgument( |
|
| 8049 | + | return inferGenericArgument( |
|
| 8050 | + | self, *array.length, *actualArray.length, params, inferred |
|
| 8051 | + | ) and inferGenericArgument( |
|
| 7936 | 8052 | self, *array.item, *actualArray.item, params, inferred |
|
| 7937 | 8053 | ); |
|
| 7938 | 8054 | } |
|
| 7939 | 8055 | case Type::GenericDataApply(application) => { |
|
| 7940 | 8056 | let case Type::Nominal(nominal) = actual else return false; |
| 7995 | 8111 | &mut inferred[..], |
|
| 7996 | 8112 | ) { |
|
| 7997 | 8113 | throw emitError(self, callee, ErrorKind::GenericInferenceConflict); |
|
| 7998 | 8114 | } |
|
| 7999 | 8115 | let a = alloc::arenaAllocator(&mut self.arena); |
|
| 8000 | - | let mut args: *mut [*Type] = &mut []; |
|
| 8116 | + | let mut args = vec::Vec⟨*Type⟩ { data: &mut [], len: 0 }; |
|
| 8001 | 8117 | for _, i in template.params { |
|
| 8002 | 8118 | let arg = inferred[i] else { |
|
| 8003 | 8119 | throw emitError( |
|
| 8004 | 8120 | self, callee, ErrorKind::GenericInferenceIncomplete |
|
| 8005 | 8121 | ); |
|
| 8006 | 8122 | }; |
|
| 8007 | - | args.append(arg, a); |
|
| 8123 | + | vec::append⟨*Type⟩(&mut args, arg, a); |
|
| 8008 | 8124 | } |
|
| 8009 | - | for arg, i in args { |
|
| 8125 | + | let argsView = vec::view⟨*Type⟩(&args); |
|
| 8126 | + | for arg, i in argsView { |
|
| 8010 | 8127 | if not containsGenericParameter(*arg) { |
|
| 8011 | 8128 | for bound in template.params[i].bounds { |
|
| 8012 | 8129 | if findInstance(self, bound, *arg) == nil { |
|
| 8013 | 8130 | throw emitError( |
|
| 8014 | 8131 | self, |
| 8017 | 8134 | ); |
|
| 8018 | 8135 | } |
|
| 8019 | 8136 | } |
|
| 8020 | 8137 | } |
|
| 8021 | 8138 | } |
|
| 8022 | - | let sub = Substitution { params: template.params, args: &args[..] }; |
|
| 8139 | + | let sub = Substitution { params: template.params, args: argsView }; |
|
| 8023 | 8140 | let applied = try substituteType(self, Type::Fn(signature), &sub, callee); |
|
| 8024 | 8141 | let case Type::Fn(appliedFn) = applied |
|
| 8025 | 8142 | else throw emitError(self, callee, ErrorKind::Internal); |
|
| 8026 | 8143 | let caller = currentGenericTemplateSymbol(self); |
|
| 8027 | 8144 | if caller == nil { |
|
| 8028 | 8145 | if let existing = findGenericFnSpecialization( |
|
| 8029 | - | self, templateSym, &args[..] |
|
| 8146 | + | self, templateSym, argsView |
|
| 8030 | 8147 | ) { |
|
| 8031 | 8148 | setNodeSymbol(self, callee, templateSym); |
|
| 8032 | 8149 | setNodeType(self, callee, Type::Fn(existing.fnType)); |
|
| 8033 | 8150 | set self.nodeData.entries[callee.id].extra = |
|
| 8034 | 8151 | NodeExtra::GenericFnCall(existing); |
|
| 8035 | 8152 | return existing.fnType; |
|
| 8036 | 8153 | } |
|
| 8037 | 8154 | } |
|
| 8038 | 8155 | recordGenericFnDependency( |
|
| 8039 | - | self, callee, caller, templateSym, &args[..], appliedFn |
|
| 8156 | + | self, callee, caller, templateSym, argsView, appliedFn |
|
| 8040 | 8157 | ); |
|
| 8041 | 8158 | return appliedFn; |
|
| 8042 | 8159 | } |
|
| 8043 | 8160 | ||
| 8044 | 8161 | /// Resolve `Trait::method(receiver, ...)` for a rigid bounded parameter. |
| 8089 | 8206 | self, Type::Fn(method.fnType), &sub, node |
|
| 8090 | 8207 | ); |
|
| 8091 | 8208 | let case Type::Fn(methodFn) = substituted |
|
| 8092 | 8209 | else throw emitError(self, node, ErrorKind::Internal); |
|
| 8093 | 8210 | let a = alloc::arenaAllocator(&mut self.arena); |
|
| 8094 | - | let mut params: *mut [*Type] = &mut []; |
|
| 8095 | - | params.append(allocType(self, receiverTy), a); |
|
| 8211 | + | let mut params = vec::Vec⟨*Type⟩ { data: &mut [], len: 0 }; |
|
| 8212 | + | vec::append⟨*Type⟩(&mut params, allocType(self, receiverTy), a); |
|
| 8096 | 8213 | for methodParam in methodFn.paramTypes { |
|
| 8097 | - | params.append(methodParam, a); |
|
| 8214 | + | vec::append⟨*Type⟩(&mut params, methodParam, a); |
|
| 8098 | 8215 | } |
|
| 8099 | 8216 | let fullFn = allocFnType(self, FnType { |
|
| 8100 | - | paramTypes: ¶ms[..], |
|
| 8217 | + | paramTypes: vec::view⟨*Type⟩(¶ms), |
|
| 8101 | 8218 | returnType: methodFn.returnType, |
|
| 8102 | 8219 | throwList: methodFn.throwList, |
|
| 8103 | 8220 | isUnsafe: methodFn.isUnsafe, |
|
| 8104 | 8221 | localCount: 0, |
|
| 8105 | 8222 | }); |
| 8120 | 8237 | call: ast::Call, |
|
| 8121 | 8238 | ctx: CallCtx, |
|
| 8122 | 8239 | expected: Type, |
|
| 8123 | 8240 | ) -> Type throws (ResolveError) |
|
| 8124 | 8241 | { |
|
| 8125 | - | // Intercept method calls on slices before inferring the callee. |
|
| 8126 | - | if let case ast::NodeValue::FieldAccess(access) = call.callee.value { |
|
| 8127 | - | let parentTy = try infer(self, access.parent); |
|
| 8128 | - | if isUnsafePointerType(parentTy) { |
|
| 8129 | - | try requireUnsafe(self, access.parent); |
|
| 8130 | - | } |
|
| 8131 | - | ||
| 8132 | - | let subjectTy = autoDeref(parentTy); |
|
| 8133 | - | ||
| 8134 | - | if let case Type::Slice(slice) = subjectTy { |
|
| 8135 | - | let methodName = try nodeName(self, access.child); |
|
| 8136 | - | if methodName == "append" { |
|
| 8137 | - | return try resolveSliceAppend( |
|
| 8138 | - | self, node, access.parent, parentTy, call.args, slice.item, slice.mutable |
|
| 8139 | - | ); |
|
| 8140 | - | } |
|
| 8141 | - | if methodName == "delete" { |
|
| 8142 | - | return try resolveSliceDelete( |
|
| 8143 | - | self, node, access.parent, call.args, slice.item, slice.mutable |
|
| 8144 | - | ); |
|
| 8145 | - | } |
|
| 8146 | - | } |
|
| 8147 | - | } |
|
| 8148 | 8242 | if let bounded = try resolveQualifiedGenericBoundCall( |
|
| 8149 | 8243 | self, node, call, ctx |
|
| 8150 | 8244 | ) { |
|
| 8151 | 8245 | return bounded; |
|
| 8152 | 8246 | } |
| 8270 | 8364 | ||
| 8271 | 8365 | // Associate return type to call. |
|
| 8272 | 8366 | return setNodeType(self, node, *info.returnType); |
|
| 8273 | 8367 | } |
|
| 8274 | 8368 | ||
| 8275 | - | /// Resolve `slice.append(val, allocator)`. |
|
| 8276 | - | fn resolveSliceAppend( |
|
| 8277 | - | self: *mut Resolver, |
|
| 8278 | - | node: *ast::Node, |
|
| 8279 | - | parent: *ast::Node, |
|
| 8280 | - | parentType: Type, |
|
| 8281 | - | args: *mut [*ast::Node], |
|
| 8282 | - | elemType: *Type, |
|
| 8283 | - | mutable: bool |
|
| 8284 | - | ) -> Type throws (ResolveError) { |
|
| 8285 | - | if not mutable { |
|
| 8286 | - | throw emitError(self, parent, ErrorKind::ImmutableBinding); |
|
| 8287 | - | } |
|
| 8288 | - | if args.len <> 2 { |
|
| 8289 | - | throw emitError(self, node, ErrorKind::FnArgCountMismatch(CountMismatch { |
|
| 8290 | - | expected: 2, |
|
| 8291 | - | actual: args.len as u32, |
|
| 8292 | - | })); |
|
| 8293 | - | } |
|
| 8294 | - | // First argument must be assignable to the element type. |
|
| 8295 | - | try checkAssignable(self, args[0], *elemType); |
|
| 8296 | - | // Second argument: the allocator. We accept any type -- the lowerer |
|
| 8297 | - | // reads `.func` and `.ctx` at fixed offsets. |
|
| 8298 | - | try visit(self, args[1], Type::Unknown); |
|
| 8299 | - | recordGenericTypeUse(self, node, *elemType); |
|
| 8300 | - | set self.nodeData.entries[node.id].extra = NodeExtra::SliceAppend { elemType }; |
|
| 8301 | - | ||
| 8302 | - | // Return the parent's type so the caller can rebind: |
|
| 8303 | - | return setNodeType(self, node, parentType); |
|
| 8304 | - | } |
|
| 8305 | - | ||
| 8306 | - | /// Resolve `slice.delete(index)`. |
|
| 8307 | - | fn resolveSliceDelete( |
|
| 8308 | - | self: *mut Resolver, |
|
| 8309 | - | node: *ast::Node, |
|
| 8310 | - | parent: *ast::Node, |
|
| 8311 | - | args: *mut [*ast::Node], |
|
| 8312 | - | elemType: *Type, |
|
| 8313 | - | mutable: bool |
|
| 8314 | - | ) -> Type throws (ResolveError) { |
|
| 8315 | - | if not mutable { |
|
| 8316 | - | throw emitError(self, parent, ErrorKind::ImmutableBinding); |
|
| 8317 | - | } |
|
| 8318 | - | if args.len <> 1 { |
|
| 8319 | - | throw emitError(self, node, ErrorKind::FnArgCountMismatch(CountMismatch { |
|
| 8320 | - | expected: 1, |
|
| 8321 | - | actual: args.len as u32, |
|
| 8322 | - | })); |
|
| 8323 | - | } |
|
| 8324 | - | try checkAssignable(self, args[0], Type::U32); |
|
| 8325 | - | recordGenericTypeUse(self, node, *elemType); |
|
| 8326 | - | set self.nodeData.entries[node.id].extra = NodeExtra::SliceDelete { elemType }; |
|
| 8327 | - | ||
| 8328 | - | return setNodeType(self, node, Type::Void); |
|
| 8329 | - | } |
|
| 8330 | - | ||
| 8331 | 8369 | /// Analyze an assignment expression. |
|
| 8332 | 8370 | fn resolveAssign(self: *mut Resolver, node: *ast::Node, assign: ast::Assign) -> Type |
|
| 8333 | 8371 | throws (ResolveError) |
|
| 8334 | 8372 | { |
|
| 8335 | 8373 | // Slice assignment: `slice[range] = value`. |
| 8342 | 8380 | } |
|
| 8343 | 8381 | let subjectTy = autoDeref(containerTy); |
|
| 8344 | 8382 | try checkSliceRangeIndices(self, range); |
|
| 8345 | 8383 | ||
| 8346 | 8384 | let mut item: *Type = undefined; |
|
| 8347 | - | let mut capacity: ?u32 = nil; |
|
| 8385 | + | let mut capacity: ?*Type = nil; |
|
| 8348 | 8386 | ||
| 8349 | 8387 | if let case Type::Slice(slice) = subjectTy { |
|
| 8350 | 8388 | if not slice.mutable { |
|
| 8351 | 8389 | throw emitError(self, container, ErrorKind::ImmutableBinding); |
|
| 8352 | 8390 | } |
|
| 8353 | 8391 | set item = slice.item; |
|
| 8354 | 8392 | } else { |
|
| 8355 | 8393 | match subjectTy { |
|
| 8356 | 8394 | case Type::Array(a) => { |
|
| 8357 | - | try validateArraySliceBounds(self, range, a.length, node); |
|
| 8395 | + | if let length = concreteArrayLength(a.length) { |
|
| 8396 | + | try validateArraySliceBounds(self, range, length, node); |
|
| 8397 | + | } |
|
| 8358 | 8398 | set item = a.item; |
|
| 8359 | 8399 | set capacity = a.length; |
|
| 8360 | 8400 | } |
|
| 8361 | 8401 | else => throw emitError(self, container, ErrorKind::ExpectedIndexable), |
|
| 8362 | 8402 | } |
| 8476 | 8516 | ||
| 8477 | 8517 | match subjectTy { |
|
| 8478 | 8518 | case Type::Array(arrayInfo) => { |
|
| 8479 | 8519 | return setNodeType(self, node, *arrayInfo.item); |
|
| 8480 | 8520 | } |
|
| 8481 | - | case Type::GenericArray { item, .. } => { |
|
| 8482 | - | return setNodeType(self, node, *item); |
|
| 8483 | - | } |
|
| 8484 | 8521 | else => { |
|
| 8485 | 8522 | throw emitError(self, container, ErrorKind::ExpectedIndexable); |
|
| 8486 | 8523 | } |
|
| 8487 | 8524 | } |
|
| 8488 | 8525 | } |
| 8732 | 8769 | } |
|
| 8733 | 8770 | } |
|
| 8734 | 8771 | if expectedTy == Type::Unknown { |
|
| 8735 | 8772 | throw emitError(self, node, ErrorKind::CannotInferType); |
|
| 8736 | 8773 | }; |
|
| 8737 | - | let arrayTy = Type::Array(ArrayType { item: allocType(self, expectedTy), length }); |
|
| 8774 | + | let arrayTy = Type::Array(ArrayType { |
|
| 8775 | + | item: allocType(self, expectedTy), |
|
| 8776 | + | length: allocConcreteArrayLength(self, length), |
|
| 8777 | + | }); |
|
| 8738 | 8778 | return setNodeType(self, node, arrayTy); |
|
| 8739 | 8779 | } |
|
| 8740 | 8780 | ||
| 8741 | 8781 | /// Analyze an array repeat literal expression. |
|
| 8742 | 8782 | fn resolveArrayRepeat(self: *mut Resolver, node: *ast::Node, lit: ast::ArrayRepeatLit, hint: Type) -> Type |
|
| 8743 | 8783 | throws (ResolveError) |
|
| 8744 | 8784 | { |
|
| 8745 | 8785 | let mut itemHint = hint; |
|
| 8746 | 8786 | if let case Type::Array(ary) = hint { |
|
| 8747 | 8787 | set itemHint = *ary.item; |
|
| 8748 | - | } else if let case Type::GenericArray { item, .. } = hint { |
|
| 8749 | - | set itemHint = *item; |
|
| 8750 | 8788 | } else if let case Type::Optional(inner) = hint { |
|
| 8751 | 8789 | if let case Type::Array(ary) = *inner { |
|
| 8752 | 8790 | set itemHint = *ary.item; |
|
| 8753 | 8791 | } |
|
| 8754 | 8792 | } |
|
| 8755 | 8793 | let valueTy = try visit(self, lit.item, itemHint); |
|
| 8756 | 8794 | let _ = try checkNumeric(self, lit.count); |
|
| 8757 | - | let mut arrayTy: Type = undefined; |
|
| 8795 | + | let mut length: *Type = undefined; |
|
| 8758 | 8796 | if let value = constValueEntry(self, lit.count) { |
|
| 8759 | 8797 | if not validateConstIntRange(value, Type::U32) { |
|
| 8760 | 8798 | throw emitError(self, lit.count, ErrorKind::NumericLiteralOverflow); |
|
| 8761 | 8799 | } |
|
| 8762 | 8800 | let case ConstValue::Int(int) = value |
|
| 8763 | 8801 | else throw emitError(self, lit.count, ErrorKind::ConstExprRequired); |
|
| 8764 | - | set arrayTy = Type::Array(ArrayType { |
|
| 8765 | - | item: allocType(self, valueTy), |
|
| 8766 | - | length: int.magnitude as u32, |
|
| 8767 | - | }); |
|
| 8802 | + | set length = allocConcreteArrayLength(self, int.magnitude as u32); |
|
| 8768 | 8803 | } else if isConstExpr(self, lit.count) and |
|
| 8769 | 8804 | containsGenericConstExpr(self, lit.count) |
|
| 8770 | 8805 | { |
|
| 8771 | - | set arrayTy = Type::GenericArray { |
|
| 8772 | - | item: allocType(self, valueTy), |
|
| 8773 | - | length: lit.count, |
|
| 8774 | - | }; |
|
| 8806 | + | set length = allocSymbolicArrayLength(self, lit.count); |
|
| 8775 | 8807 | } else { |
|
| 8776 | 8808 | throw emitError(self, lit.count, ErrorKind::ConstExprRequired); |
|
| 8777 | 8809 | } |
|
| 8778 | - | return setNodeType(self, node, arrayTy); |
|
| 8810 | + | return setNodeType(self, node, Type::Array(ArrayType { |
|
| 8811 | + | item: allocType(self, valueTy), |
|
| 8812 | + | length, |
|
| 8813 | + | })); |
|
| 8779 | 8814 | } |
|
| 8780 | 8815 | ||
| 8781 | 8816 | /// Resolve union variant access. |
|
| 8782 | 8817 | fn resolveUnionVariantAccess( |
|
| 8783 | 8818 | self: *mut Resolver, |
| 8920 | 8955 | } |
|
| 8921 | 8956 | if mem::eq(fieldName, LEN_FIELD) { |
|
| 8922 | 8957 | setRecordFieldIndex(self, fieldNode, 1); |
|
| 8923 | 8958 | return setNodeType(self, node, Type::U32); |
|
| 8924 | 8959 | } |
|
| 8925 | - | if mem::eq(fieldName, CAP_FIELD) { |
|
| 8926 | - | setRecordFieldIndex(self, fieldNode, 2); |
|
| 8927 | - | return setNodeType(self, node, Type::U32); |
|
| 8928 | - | } |
|
| 8929 | 8960 | throw emitError(self, node, ErrorKind::SliceFieldUnknown(fieldName)); |
|
| 8930 | 8961 | } |
|
| 8931 | 8962 | if let case Type::TraitObject(traitObject) = subjectTy { |
|
| 8932 | 8963 | let fieldName = try nodeName(self, access.child); |
|
| 8933 | 8964 | let method = findTraitMethod(traitObject.traitInfo, fieldName) |
| 8996 | 9027 | case Type::Array(arrayInfo) => { |
|
| 8997 | 9028 | let fieldNode = access.child; |
|
| 8998 | 9029 | let fieldName = try nodeName(self, fieldNode); |
|
| 8999 | 9030 | ||
| 9000 | 9031 | if mem::eq(fieldName, LEN_FIELD) { |
|
| 9001 | - | let lengthConst = constInt(arrayInfo.length as u64, 32, false, false); |
|
| 9002 | - | setNodeConstValue(self, node, lengthConst); |
|
| 9003 | - | ||
| 9004 | - | return setNodeType(self, node, Type::U32); |
|
| 9005 | - | } |
|
| 9006 | - | throw emitError(self, node, ErrorKind::ArrayFieldUnknown(fieldName)); |
|
| 9007 | - | } |
|
| 9008 | - | ||
| 9009 | - | case Type::GenericArray { .. } => { |
|
| 9010 | - | let fieldName = try nodeName(self, access.child); |
|
| 9011 | - | if mem::eq(fieldName, LEN_FIELD) { |
|
| 9032 | + | if let length = concreteArrayLength(arrayInfo.length) { |
|
| 9033 | + | setNodeConstValue( |
|
| 9034 | + | self, node, constInt(length as u64, 32, false, false) |
|
| 9035 | + | ); |
|
| 9036 | + | } |
|
| 9012 | 9037 | return setNodeType(self, node, Type::U32); |
|
| 9013 | 9038 | } |
|
| 9014 | - | ||
| 9015 | 9039 | throw emitError(self, node, ErrorKind::ArrayFieldUnknown(fieldName)); |
|
| 9016 | 9040 | } |
|
| 9017 | 9041 | else => { |
|
| 9018 | 9042 | // Check for standalone methods on any nominal type (e.g. unions). |
|
| 9019 | 9043 | if let case Type::Nominal(_) = subjectTy { |
| 9139 | 9163 | let subjectTy = autoDeref(containerTy); |
|
| 9140 | 9164 | ||
| 9141 | 9165 | try checkSliceRangeIndices(self, range); |
|
| 9142 | 9166 | ||
| 9143 | 9167 | let mut item: *Type = undefined; |
|
| 9144 | - | let mut capacity: ?u32 = nil; |
|
| 9168 | + | let mut capacity: ?*Type = nil; |
|
| 9145 | 9169 | ||
| 9146 | 9170 | if let case Type::Slice(slice) = subjectTy { |
|
| 9147 | 9171 | if addr.mutable and not slice.mutable { |
|
| 9148 | 9172 | throw emitError(self, addr.target, ErrorKind::ImmutableBinding); |
|
| 9149 | 9173 | } |
|
| 9150 | 9174 | set item = slice.item; |
|
| 9151 | 9175 | } else { |
|
| 9152 | 9176 | match subjectTy { |
|
| 9153 | 9177 | case Type::Array(arrayInfo) => { |
|
| 9154 | - | try validateArraySliceBounds(self, range, arrayInfo.length, node); |
|
| 9178 | + | if let length = concreteArrayLength(arrayInfo.length) { |
|
| 9179 | + | try validateArraySliceBounds(self, range, length, node); |
|
| 9180 | + | } |
|
| 9155 | 9181 | set item = arrayInfo.item; |
|
| 9156 | 9182 | set capacity = arrayInfo.length; |
|
| 9157 | 9183 | } |
|
| 9158 | 9184 | else => { |
|
| 9159 | 9185 | throw emitError(self, container, ErrorKind::ExpectedIndexable); |
| 9176 | 9202 | } |
|
| 9177 | 9203 | } |
|
| 9178 | 9204 | // Derive a hint for the target type from the slice hint. |
|
| 9179 | 9205 | let mut targetHint: Type = Type::Unknown; |
|
| 9180 | 9206 | if let case Type::Slice(slice) = hint { |
|
| 9181 | - | set targetHint = Type::Array(ArrayType { item: slice.item, length: 0 }); |
|
| 9207 | + | set targetHint = Type::Array(ArrayType { |
|
| 9208 | + | item: slice.item, |
|
| 9209 | + | length: allocConcreteArrayLength(self, 0), |
|
| 9210 | + | }); |
|
| 9182 | 9211 | } |
|
| 9183 | 9212 | let targetTy = try visit(self, addr.target, targetHint); |
|
| 9184 | 9213 | ||
| 9185 | 9214 | // Mark local variable symbols as address-taken so the lowerer |
|
| 9186 | 9215 | // allocates a stack slot eagerly. |
| 10007 | 10036 | else => panic "resolveTypeSyntax: invalid integer width", |
|
| 10008 | 10037 | } |
|
| 10009 | 10038 | } |
|
| 10010 | 10039 | case ast::TypeSig::Array { itemType, length } => { |
|
| 10011 | 10040 | let item = try resolveTypeSyntax(self, itemType, context); |
|
| 10041 | + | let mut lengthType: *Type = undefined; |
|
| 10012 | 10042 | match context { |
|
| 10013 | 10043 | case TypeSyntaxContext::Concrete => { |
|
| 10014 | 10044 | let concreteLength = try checkSizeInt(self, length); |
|
| 10015 | - | set ty = Type::Array(ArrayType { |
|
| 10016 | - | item: allocType(self, item), |
|
| 10017 | - | length: concreteLength, |
|
| 10018 | - | }); |
|
| 10045 | + | set lengthType = allocConcreteArrayLength(self, concreteLength); |
|
| 10019 | 10046 | } |
|
| 10020 | 10047 | case TypeSyntaxContext::Symbolic => { |
|
| 10021 | 10048 | let _ = try checkNumeric(self, length); |
|
| 10022 | 10049 | if let value = constValueEntry(self, length) { |
|
| 10023 | 10050 | if not validateConstIntRange(value, Type::U32) { |
| 10028 | 10055 | let case ConstValue::Int(int) = value else { |
|
| 10029 | 10056 | throw emitError( |
|
| 10030 | 10057 | self, length, ErrorKind::ConstExprRequired |
|
| 10031 | 10058 | ); |
|
| 10032 | 10059 | }; |
|
| 10033 | - | set ty = Type::Array(ArrayType { |
|
| 10034 | - | item: allocType(self, item), |
|
| 10035 | - | length: int.magnitude as u32, |
|
| 10036 | - | }); |
|
| 10060 | + | set lengthType = allocConcreteArrayLength( |
|
| 10061 | + | self, int.magnitude as u32 |
|
| 10062 | + | ); |
|
| 10037 | 10063 | } else if isConstExpr(self, length) and |
|
| 10038 | 10064 | containsGenericConstExpr(self, length) |
|
| 10039 | 10065 | { |
|
| 10040 | - | set ty = Type::GenericArray { |
|
| 10041 | - | item: allocType(self, item), |
|
| 10042 | - | length, |
|
| 10043 | - | }; |
|
| 10066 | + | set lengthType = allocSymbolicArrayLength(self, length); |
|
| 10044 | 10067 | } else { |
|
| 10045 | 10068 | throw emitError( |
|
| 10046 | 10069 | self, length, ErrorKind::ConstExprRequired |
|
| 10047 | 10070 | ); |
|
| 10048 | 10071 | } |
|
| 10049 | 10072 | } |
|
| 10050 | 10073 | } |
|
| 10074 | + | set ty = Type::Array(ArrayType { |
|
| 10075 | + | item: allocType(self, item), |
|
| 10076 | + | length: lengthType, |
|
| 10077 | + | }); |
|
| 10051 | 10078 | } |
|
| 10052 | 10079 | case ast::TypeSig::Slice { class, itemType, mutable } => { |
|
| 10053 | 10080 | let item = try resolveTypeSyntax(self, itemType, context); |
|
| 10054 | 10081 | set ty = Type::Slice(SliceType { |
|
| 10055 | 10082 | class, |
| 10085 | 10112 | actual: app.args.len, |
|
| 10086 | 10113 | }), |
|
| 10087 | 10114 | ); |
|
| 10088 | 10115 | } |
|
| 10089 | 10116 | let a = alloc::arenaAllocator(&mut self.arena); |
|
| 10090 | - | let mut args: *mut [*Type] = &mut []; |
|
| 10117 | + | let mut args = vec::Vec⟨*Type⟩ { data: &mut [], len: 0 }; |
|
| 10091 | 10118 | for argNode, i in app.args { |
|
| 10092 | 10119 | let arg = try resolveGenericArgument( |
|
| 10093 | 10120 | self, argNode, template.params[i] |
|
| 10094 | 10121 | ); |
|
| 10095 | - | args.append(allocType(self, arg), a); |
|
| 10122 | + | vec::append⟨*Type⟩(&mut args, allocType(self, arg), a); |
|
| 10096 | 10123 | } |
|
| 10097 | 10124 | let symbolic = try! alloc::alloc( |
|
| 10098 | 10125 | &mut self.arena, |
|
| 10099 | 10126 | @sizeOf(GenericDataApplyType), |
|
| 10100 | 10127 | @alignOf(GenericDataApplyType), |
|
| 10101 | 10128 | ) as *mut GenericDataApplyType; |
|
| 10102 | 10129 | set *symbolic = GenericDataApplyType { |
|
| 10103 | 10130 | template: templateSym, |
|
| 10104 | - | args: &args[..], |
|
| 10131 | + | args: vec::view⟨*Type⟩(&args), |
|
| 10105 | 10132 | site: name, |
|
| 10106 | 10133 | }; |
|
| 10107 | 10134 | return setNodeType( |
|
| 10108 | 10135 | self, node, Type::GenericDataApply(symbolic) |
|
| 10109 | 10136 | ); |
| 10164 | 10191 | self, NominalType::Record(recordType) |
|
| 10165 | 10192 | )); |
|
| 10166 | 10193 | } |
|
| 10167 | 10194 | case TypeSyntaxContext::Symbolic => { |
|
| 10168 | 10195 | let a = alloc::arenaAllocator(&mut self.arena); |
|
| 10169 | - | let mut result: *mut [RecordField] = &mut []; |
|
| 10196 | + | let mut result = vec::Vec⟨RecordField⟩ { |
|
| 10197 | + | data: &mut [], |
|
| 10198 | + | len: 0, |
|
| 10199 | + | }; |
|
| 10170 | 10200 | for field in fields { |
|
| 10171 | 10201 | let case ast::NodeValue::RecordField { |
|
| 10172 | 10202 | field: fieldNameNode, |
|
| 10173 | 10203 | type: typeNode, |
|
| 10174 | 10204 | value, |
| 10186 | 10216 | } |
|
| 10187 | 10217 | let mut fieldName: ?*[u8] = nil; |
|
| 10188 | 10218 | if let nameNode = fieldNameNode { |
|
| 10189 | 10219 | set fieldName = try nodeName(self, nameNode); |
|
| 10190 | 10220 | } |
|
| 10191 | - | result.append(RecordField { |
|
| 10221 | + | vec::append⟨RecordField⟩(&mut result, RecordField { |
|
| 10192 | 10222 | name: fieldName, |
|
| 10193 | 10223 | fieldType, |
|
| 10194 | 10224 | offset: -1, |
|
| 10195 | 10225 | }, a); |
|
| 10196 | 10226 | } |
| 10198 | 10228 | &mut self.arena, |
|
| 10199 | 10229 | @sizeOf(GenericRecordType), |
|
| 10200 | 10230 | @alignOf(GenericRecordType), |
|
| 10201 | 10231 | ) as *mut GenericRecordType; |
|
| 10202 | 10232 | set *genericRecord = GenericRecordType { |
|
| 10203 | - | fields: &result[..], |
|
| 10233 | + | fields: vec::view⟨RecordField⟩(&result), |
|
| 10204 | 10234 | labeled, |
|
| 10205 | 10235 | }; |
|
| 10206 | 10236 | set ty = Type::GenericRecord(genericRecord); |
|
| 10207 | 10237 | } |
|
| 10208 | 10238 | } |
| 10223 | 10253 | actual: signature.throwList.len, |
|
| 10224 | 10254 | } |
|
| 10225 | 10255 | )); |
|
| 10226 | 10256 | } |
|
| 10227 | 10257 | let a = alloc::arenaAllocator(&mut self.arena); |
|
| 10228 | - | let mut params: *mut [*Type] = &mut []; |
|
| 10229 | - | let mut throwTypes: *mut [*Type] = &mut []; |
|
| 10258 | + | let mut params = vec::Vec⟨*Type⟩ { data: &mut [], len: 0 }; |
|
| 10259 | + | let mut throwTypes = vec::Vec⟨*Type⟩ { data: &mut [], len: 0 }; |
|
| 10230 | 10260 | for param in signature.params { |
|
| 10231 | 10261 | let paramType = try resolveContextualValueType( |
|
| 10232 | 10262 | self, param, context |
|
| 10233 | 10263 | ); |
|
| 10234 | - | params.append(allocType(self, paramType), a); |
|
| 10264 | + | vec::append⟨*Type⟩(&mut params, allocType(self, paramType), a); |
|
| 10235 | 10265 | } |
|
| 10236 | 10266 | for throwNode in signature.throwList { |
|
| 10237 | 10267 | let throwType = try resolveContextualValueType( |
|
| 10238 | 10268 | self, throwNode, context |
|
| 10239 | 10269 | ); |
|
| 10240 | 10270 | try ensureStorableType(self, throwNode, throwType); |
|
| 10241 | - | throwTypes.append(allocType(self, throwType), a); |
|
| 10271 | + | vec::append⟨*Type⟩(&mut throwTypes, allocType(self, throwType), a); |
|
| 10242 | 10272 | } |
|
| 10243 | 10273 | let mut returnType = allocType(self, Type::Void); |
|
| 10244 | 10274 | if let returnNode = signature.returnType { |
|
| 10245 | 10275 | let resolved = try resolveContextualValueType( |
|
| 10246 | 10276 | self, returnNode, context |
|
| 10247 | 10277 | ); |
|
| 10248 | 10278 | try ensureStorableType(self, returnNode, resolved); |
|
| 10249 | 10279 | set returnType = allocType(self, resolved); |
|
| 10250 | 10280 | } |
|
| 10251 | 10281 | set ty = Type::Fn(allocFnType(self, FnType { |
|
| 10252 | - | paramTypes: ¶ms[..], |
|
| 10282 | + | paramTypes: vec::view⟨*Type⟩(¶ms), |
|
| 10253 | 10283 | returnType, |
|
| 10254 | - | throwList: &throwTypes[..], |
|
| 10284 | + | throwList: vec::view⟨*Type⟩(&throwTypes), |
|
| 10255 | 10285 | isUnsafe: false, |
|
| 10256 | 10286 | localCount: 0, |
|
| 10257 | 10287 | })); |
|
| 10258 | 10288 | } |
|
| 10259 | 10289 | case ast::TypeSig::TraitObject { class, traitName, mutable } => { |
| 10299 | 10329 | export fn resolveExpr( |
|
| 10300 | 10330 | self: *mut Resolver, expr: *ast::Node, arena: *mut ast::NodeArena |
|
| 10301 | 10331 | ) -> Diagnostics throws (ResolveError) { |
|
| 10302 | 10332 | let a = alloc::arenaAllocator(&mut arena.arena); |
|
| 10303 | 10333 | let exprStmt = ast::synthNode(arena, ast::NodeValue::ExprStmt(expr)); |
|
| 10304 | - | let bodyStmts = ast::nodeSlice(arena, 1).append(exprStmt, a); |
|
| 10305 | - | let module = ast::synthFnModule(arena, ANALYZE_EXPR_FN_NAME, bodyStmts); |
|
| 10334 | + | let mut bodyStmts = ast::nodeVec(arena, 1); |
|
| 10335 | + | vec::append⟨*ast::Node⟩(&mut bodyStmts, exprStmt, a); |
|
| 10336 | + | let module = ast::synthFnModule( |
|
| 10337 | + | arena, |
|
| 10338 | + | ANALYZE_EXPR_FN_NAME, |
|
| 10339 | + | vec::viewMut⟨*ast::Node⟩(&mut bodyStmts), |
|
| 10340 | + | ); |
|
| 10306 | 10341 | ||
| 10307 | 10342 | let case ast::NodeValue::Block(block) = module.modBody.value |
|
| 10308 | 10343 | else panic "resolveExpr: expected block for module body"; |
|
| 10309 | 10344 | enterScope(self, module.modBody); |
|
| 10310 | 10345 | try resolveModuleDecls(self, &block) catch { |
|
| 10311 | - | return Diagnostics { errors: self.errors }; |
|
| 10346 | + | return diagnostics(self); |
|
| 10312 | 10347 | }; |
|
| 10313 | 10348 | try resolveModuleDefs(self, &block) catch { |
|
| 10314 | - | return Diagnostics { errors: self.errors }; |
|
| 10349 | + | return diagnostics(self); |
|
| 10315 | 10350 | }; |
|
| 10316 | 10351 | exitScope(self); |
|
| 10317 | 10352 | ||
| 10318 | - | return Diagnostics { errors: self.errors }; |
|
| 10353 | + | return diagnostics(self); |
|
| 10319 | 10354 | } |
|
| 10320 | 10355 | ||
| 10321 | 10356 | /// Analyze a parsed module root, ie. a block of top-level statements. |
|
| 10322 | 10357 | export fn resolveModuleRoot(self: *mut Resolver, root: *ast::Node) -> Diagnostics throws (ResolveError) { |
|
| 10323 | 10358 | let case ast::NodeValue::Block(block) = root.value |
|
| 10324 | 10359 | else panic "resolveModuleRoot: expected block for module root"; |
|
| 10325 | 10360 | ||
| 10326 | 10361 | enterScope(self, root); |
|
| 10327 | 10362 | try resolveModuleDecls(self, &block) catch { |
|
| 10328 | - | return Diagnostics { errors: self.errors }; |
|
| 10363 | + | return diagnostics(self); |
|
| 10329 | 10364 | }; |
|
| 10330 | 10365 | try resolveModuleDefs(self, &block) catch { |
|
| 10331 | - | return Diagnostics { errors: self.errors }; |
|
| 10366 | + | return diagnostics(self); |
|
| 10332 | 10367 | }; |
|
| 10333 | 10368 | exitScope(self); |
|
| 10334 | 10369 | setNodeType(self, root, Type::Void); |
|
| 10335 | 10370 | ||
| 10336 | 10371 | try closeGenericFnSpecializations(self) catch { |
|
| 10337 | - | return Diagnostics { errors: self.errors }; |
|
| 10372 | + | return diagnostics(self); |
|
| 10338 | 10373 | }; |
|
| 10339 | 10374 | try materializeGenericFnTypeUses(self) catch { |
|
| 10340 | - | return Diagnostics { errors: self.errors }; |
|
| 10375 | + | return diagnostics(self); |
|
| 10341 | 10376 | }; |
|
| 10342 | 10377 | try validateGenericDataRoots(self) catch { |
|
| 10343 | - | return Diagnostics { errors: self.errors }; |
|
| 10378 | + | return diagnostics(self); |
|
| 10344 | 10379 | }; |
|
| 10345 | - | return Diagnostics { errors: self.errors }; |
|
| 10380 | + | return diagnostics(self); |
|
| 10346 | 10381 | } |
|
| 10347 | 10382 | ||
| 10348 | 10383 | /// Analyze the module graph. This pass processes `mod` statements, creating symbols |
|
| 10349 | 10384 | /// and scopes for them, and also binds type names in each module so that cross-module |
|
| 10350 | 10385 | /// type references work regardless of declaration order. |
| 10855 | 10890 | let mut receiverClass = types::PointerClass::Unsafe; |
|
| 10856 | 10891 | let mut receiverMutable = false; |
|
| 10857 | 10892 | let mut haveReceiver = false; |
|
| 10858 | 10893 | match checker.resolver.nodeData.entries[node.id].extra { |
|
| 10859 | 10894 | case NodeExtra::TraitMethodCall { traitInfo, methodIndex } => { |
|
| 10860 | - | let method = &traitInfo.methods[methodIndex]; |
|
| 10895 | + | let method = &traitInfo.methods.data[methodIndex]; |
|
| 10861 | 10896 | set receiverClass = method.receiverClass; |
|
| 10862 | 10897 | set receiverMutable = method.mutable; |
|
| 10863 | 10898 | set haveReceiver = true; |
|
| 10864 | 10899 | } |
|
| 10865 | 10900 | case NodeExtra::GenericBoundMethodCall { |
|
| 10866 | 10901 | traitInfo, methodIndex, explicitReceiver, .. |
|
| 10867 | 10902 | } => { |
|
| 10868 | 10903 | if not explicitReceiver { |
|
| 10869 | - | let method = &traitInfo.methods[methodIndex]; |
|
| 10904 | + | let method = &traitInfo.methods.data[methodIndex]; |
|
| 10870 | 10905 | set receiverClass = method.receiverClass; |
|
| 10871 | 10906 | set receiverMutable = method.mutable; |
|
| 10872 | 10907 | set haveReceiver = true; |
|
| 10873 | 10908 | } |
|
| 10874 | 10909 | } |
| 11449 | 11484 | let diags = try resolvePackage(self, pkg.rootEntry, pkg.rootAst); |
|
| 11450 | 11485 | if not success(&diags) { |
|
| 11451 | 11486 | return diags; |
|
| 11452 | 11487 | } |
|
| 11453 | 11488 | try closeGenericFnSpecializations(self) catch { |
|
| 11454 | - | return Diagnostics { errors: self.errors }; |
|
| 11489 | + | return diagnostics(self); |
|
| 11455 | 11490 | }; |
|
| 11456 | 11491 | try materializeGenericFnTypeUses(self) catch { |
|
| 11457 | - | return Diagnostics { errors: self.errors }; |
|
| 11492 | + | return diagnostics(self); |
|
| 11458 | 11493 | }; |
|
| 11459 | 11494 | } |
|
| 11460 | 11495 | // Data roots are validated after every package and reachable generic body |
|
| 11461 | 11496 | // has had a chance to root its concrete specialization dependencies. |
|
| 11462 | 11497 | try validateGenericDataRoots(self) catch { |
|
| 11463 | - | return Diagnostics { errors: self.errors }; |
|
| 11498 | + | return diagnostics(self); |
|
| 11464 | 11499 | }; |
|
| 11465 | - | return Diagnostics { errors: self.errors }; |
|
| 11500 | + | return diagnostics(self); |
|
| 11466 | 11501 | } |
|
| 11467 | 11502 | ||
| 11468 | 11503 | /// Resolve a package. |
|
| 11469 | 11504 | fn resolvePackage(self: *mut Resolver, rootEntry: *module::ModuleEntry, node: *ast::Node) -> Diagnostics throws (ResolveError) { |
|
| 11470 | 11505 | let rootId = rootEntry.id; |
| 11481 | 11516 | else panic "resolvePackage: expected block for module root"; |
|
| 11482 | 11517 | ||
| 11483 | 11518 | // Module graph analysis phase: bind all module name symbols and scopes. |
|
| 11484 | 11519 | try resolveModuleGraph(self, &block) catch { |
|
| 11485 | 11520 | assert self.errors.len > 0, "resolvePackage: failure should have diagnostics"; |
|
| 11486 | - | return Diagnostics { errors: self.errors }; |
|
| 11521 | + | return diagnostics(self); |
|
| 11487 | 11522 | }; |
|
| 11488 | 11523 | ||
| 11489 | 11524 | // Declaration phase: bind all names and analyze top-level declarations. |
|
| 11490 | 11525 | try resolveModuleDecls(self, &block) catch { |
|
| 11491 | 11526 | assert self.errors.len > 0, "resolvePackage: failure should have diagnostics"; |
|
| 11492 | 11527 | }; |
|
| 11493 | 11528 | if self.errors.len > 0 { |
|
| 11494 | - | return Diagnostics { errors: self.errors }; |
|
| 11529 | + | return diagnostics(self); |
|
| 11495 | 11530 | } |
|
| 11496 | 11531 | ||
| 11497 | 11532 | // Definition phase: analyze function bodies and sub-module definitions. |
|
| 11498 | 11533 | try resolveModuleDefs(self, &block) catch { |
|
| 11499 | 11534 | assert self.errors.len > 0, "resolvePackage: failure should have diagnostics"; |
|
| 11500 | 11535 | }; |
|
| 11501 | 11536 | setNodeType(self, node, Type::Void); |
|
| 11502 | 11537 | ||
| 11503 | - | return Diagnostics { errors: self.errors }; |
|
| 11538 | + | return diagnostics(self); |
|
| 11504 | 11539 | } |
lib/std/lang/resolver/printer.rad
+5 -6
| 116 | 116 | } |
|
| 117 | 117 | case super::Type::Array(array) => { |
|
| 118 | 118 | io::print("["); |
|
| 119 | 119 | printTypeBody(*array.item, brief); |
|
| 120 | 120 | io::print("; "); |
|
| 121 | - | io::printU32(array.length); |
|
| 121 | + | if let length = super::concreteArrayLength(array.length) { |
|
| 122 | + | io::printU32(length); |
|
| 123 | + | } else { |
|
| 124 | + | printTypeBody(*array.length, brief); |
|
| 125 | + | } |
|
| 122 | 126 | io::print("]"); |
|
| 123 | 127 | } |
|
| 124 | - | case super::Type::GenericArray { item, .. } => { |
|
| 125 | - | io::print("["); |
|
| 126 | - | printTypeBody(*item, brief); |
|
| 127 | - | io::print("; <const>]"); |
|
| 128 | - | } |
|
| 129 | 128 | case super::Type::Optional(inner) => { |
|
| 130 | 129 | io::print("?"); |
|
| 131 | 130 | printTypeBody(*inner, brief); |
|
| 132 | 131 | } |
|
| 133 | 132 | case super::Type::Fn(fnType) => { |
lib/std/lang/resolver/tests.rad
+25 -152
| 7 | 7 | use std::lang::types; |
|
| 8 | 8 | use std::lang::parser; |
|
| 9 | 9 | use std::lang::scanner; |
|
| 10 | 10 | use std::lang::module; |
|
| 11 | 11 | use std::lang::strings; |
|
| 12 | + | use std::lang::vec; |
|
| 12 | 13 | ||
| 13 | 14 | /// Synthetic file path used for resolver tests. |
|
| 14 | 15 | constant MODULE_PATH: *[u8] = "/dev/test.rad"; |
|
| 15 | 16 | ||
| 16 | 17 | /// AST arena storage used by resolver tests. |
| 88 | 89 | fn resolveStatements( |
|
| 89 | 90 | self: *mut super::Resolver, block: ast::Block, arena: *mut ast::NodeArena |
|
| 90 | 91 | ) -> TestResult throws (super::ResolveError) { |
|
| 91 | 92 | let module = ast::synthFnModule(arena, super::ANALYZE_BLOCK_FN_NAME, block.statements); |
|
| 92 | 93 | let diagnostics = try super::resolveModuleRoot(self, module.modBody) catch { |
|
| 93 | - | return TestResult { diagnostics: super::Diagnostics { errors: self.errors }, root: module.modBody }; |
|
| 94 | + | return TestResult { |
|
| 95 | + | diagnostics: super::Diagnostics { |
|
| 96 | + | errors: vec::viewMut⟨super::Error⟩(&mut self.errors), |
|
| 97 | + | }, |
|
| 98 | + | root: module.modBody, |
|
| 99 | + | }; |
|
| 94 | 100 | }; |
|
| 95 | 101 | return TestResult { diagnostics, root: module.fnBody }; |
|
| 96 | 102 | } |
|
| 97 | 103 | ||
| 98 | 104 | /// Parse and analyze an expression string for testing. |
| 450 | 456 | fn expectArrayType(ty: super::Type, length: u32) -> super::Type |
|
| 451 | 457 | throws (testing::TestError) |
|
| 452 | 458 | { |
|
| 453 | 459 | let case super::Type::Array(info) = ty |
|
| 454 | 460 | else throw testing::TestError::Failed; |
|
| 455 | - | try testing::expect(info.length == length); |
|
| 461 | + | let actualLength = super::concreteArrayLength(info.length) |
|
| 462 | + | else throw testing::TestError::Failed; |
|
| 463 | + | try testing::expect(actualLength == length); |
|
| 456 | 464 | ||
| 457 | 465 | return *info.item; |
|
| 458 | 466 | } |
|
| 459 | 467 | ||
| 460 | 468 | /// Require a slice type and return its element type. |
| 3816 | 3824 | let arrStmt = try getBlockStmt(result.root, 1); |
|
| 3817 | 3825 | let sym = super::symbolFor(&a, arrStmt) |
|
| 3818 | 3826 | else throw testing::TestError::Failed; |
|
| 3819 | 3827 | let case super::SymbolData::Constant { type: super::Type::Array(arrType), .. } = sym.data |
|
| 3820 | 3828 | else throw testing::TestError::Failed; |
|
| 3821 | - | try testing::expect(arrType.length == 3); |
|
| 3829 | + | let actualLength = super::concreteArrayLength(arrType.length) |
|
| 3830 | + | else throw testing::TestError::Failed; |
|
| 3831 | + | try testing::expect(actualLength == 3); |
|
| 3822 | 3832 | } |
|
| 3823 | 3833 | ||
| 3824 | 3834 | /// Test that a record field can use a constant as its array length. |
|
| 3825 | 3835 | @test fn testRecordFieldWithConstArrayLength() throws (testing::TestError) { |
|
| 3826 | 3836 | let mut a = testResolver(); |
| 4264 | 4274 | let case super::ErrorKind::TypeMismatch(_) = err.kind |
|
| 4265 | 4275 | else throw testing::TestError::Failed; |
|
| 4266 | 4276 | } |
|
| 4267 | 4277 | } |
|
| 4268 | 4278 | ||
| 4269 | - | /// Test @sliceOf with 3 arguments (ptr, len, cap) succeeds. |
|
| 4270 | - | @test fn testResolveSliceOfWithCap() throws (testing::TestError) { |
|
| 4271 | - | { |
|
| 4272 | - | let mut a = testResolver(); |
|
| 4273 | - | let program = "fn f(ptr: *u8, len: u32, cap: u32) -> *[u8] { return @sliceOf(ptr, len, cap); }"; |
|
| 4274 | - | let result = try resolveProgramStr(&mut a, program); |
|
| 4275 | - | try expectNoErrors(&result); |
|
| 4276 | - | } |
|
| 4277 | - | // Mutable pointer produces mutable slice. |
|
| 4278 | - | { |
|
| 4279 | - | let mut a = testResolver(); |
|
| 4280 | - | let program = "fn f(ptr: *mut u8, len: u32, cap: u32) -> *mut [u8] { return @sliceOf(ptr, len, cap); }"; |
|
| 4281 | - | let result = try resolveProgramStr(&mut a, program); |
|
| 4282 | - | try expectNoErrors(&result); |
|
| 4283 | - | } |
|
| 4284 | - | } |
|
| 4285 | - | ||
| 4286 | - | /// Test @sliceOf with 3 arguments but wrong cap type. |
|
| 4287 | - | @test fn testResolveSliceOfCapWrongType() throws (testing::TestError) { |
|
| 4288 | - | let mut a = testResolver(); |
|
| 4289 | - | let program = "fn f(ptr: *u8, len: u32, cap: bool) -> *[u8] { return @sliceOf(ptr, len, cap); }"; |
|
| 4290 | - | let result = try resolveProgramStr(&mut a, program); |
|
| 4291 | - | let err = try expectError(&result); |
|
| 4292 | - | let case super::ErrorKind::TypeMismatch(_) = err.kind |
|
| 4293 | - | else throw testing::TestError::Failed; |
|
| 4294 | - | } |
|
| 4295 | - | ||
| 4296 | - | /// Test .cap field access on slices resolves to u32. |
|
| 4297 | - | @test fn testResolveSliceCapField() throws (testing::TestError) { |
|
| 4298 | - | let mut a = testResolver(); |
|
| 4299 | - | let program = "fn f(s: *[u8]) -> u32 { return s.cap; }"; |
|
| 4300 | - | let result = try resolveProgramStr(&mut a, program); |
|
| 4301 | - | try expectNoErrors(&result); |
|
| 4302 | - | } |
|
| 4303 | - | ||
| 4304 | - | /// Test `.append()` on immutable slice produces an error. |
|
| 4305 | - | @test fn testResolveSliceAppendImmutable() throws (testing::TestError) { |
|
| 4306 | - | let mut a = testResolver(); |
|
| 4307 | - | let program = "record A { func: fn(*mut opaque, u32, u32) -> *mut opaque, ctx: *mut opaque } fn f(s: *[i32], a: A) { s.append(1, a); }"; |
|
| 4308 | - | let result = try resolveProgramStr(&mut a, program); |
|
| 4309 | - | let err = try expectError(&result); |
|
| 4310 | - | let case super::ErrorKind::ImmutableBinding = err.kind |
|
| 4311 | - | else throw testing::TestError::Failed; |
|
| 4312 | - | } |
|
| 4313 | - | ||
| 4314 | - | /// Test `.append()` with wrong argument count produces an error. |
|
| 4315 | - | @test fn testResolveSliceAppendWrongArgCount() throws (testing::TestError) { |
|
| 4316 | - | // Too few arguments. |
|
| 4317 | - | { |
|
| 4318 | - | let mut a = testResolver(); |
|
| 4319 | - | let program = "fn f(s: *mut [i32]) { s.append(1); }"; |
|
| 4320 | - | let result = try resolveProgramStr(&mut a, program); |
|
| 4321 | - | let err = try expectError(&result); |
|
| 4322 | - | let case super::ErrorKind::FnArgCountMismatch(m) = err.kind |
|
| 4323 | - | else throw testing::TestError::Failed; |
|
| 4324 | - | try testing::expect(m.expected == 2); |
|
| 4325 | - | try testing::expect(m.actual == 1); |
|
| 4326 | - | } |
|
| 4327 | - | // Too many arguments. |
|
| 4328 | - | { |
|
| 4329 | - | let mut a = testResolver(); |
|
| 4330 | - | let program = "record A { func: fn(*mut opaque, u32, u32) -> *mut opaque, ctx: *mut opaque } fn f(s: *mut [i32], a: A) { s.append(1, a, 0); }"; |
|
| 4331 | - | let result = try resolveProgramStr(&mut a, program); |
|
| 4332 | - | let err = try expectError(&result); |
|
| 4333 | - | let case super::ErrorKind::FnArgCountMismatch(m) = err.kind |
|
| 4334 | - | else throw testing::TestError::Failed; |
|
| 4335 | - | try testing::expect(m.expected == 2); |
|
| 4336 | - | try testing::expect(m.actual == 3); |
|
| 4337 | - | } |
|
| 4338 | - | } |
|
| 4339 | - | ||
| 4340 | - | /// Test `.append()` with correct arguments succeeds. |
|
| 4341 | - | @test fn testResolveSliceAppendCorrect() throws (testing::TestError) { |
|
| 4342 | - | let mut a = testResolver(); |
|
| 4343 | - | let program = "record A { func: fn(*mut opaque, u32, u32) -> *mut opaque, ctx: *mut opaque } fn f(s: *mut [i32], a: A) { s.append(1, a); }"; |
|
| 4344 | - | let result = try resolveProgramStr(&mut a, program); |
|
| 4345 | - | try expectNoErrors(&result); |
|
| 4346 | - | } |
|
| 4347 | - | ||
| 4348 | - | /// Test `.append()` with wrong element type produces an error. |
|
| 4349 | - | @test fn testResolveSliceAppendWrongElemType() throws (testing::TestError) { |
|
| 4350 | - | let mut a = testResolver(); |
|
| 4351 | - | let program = "record A { func: fn(*mut opaque, u32, u32) -> *mut opaque, ctx: *mut opaque } fn f(s: *mut [i32], a: A) { s.append(true, a); }"; |
|
| 4352 | - | let result = try resolveProgramStr(&mut a, program); |
|
| 4353 | - | let err = try expectError(&result); |
|
| 4354 | - | let case super::ErrorKind::TypeMismatch(_) = err.kind |
|
| 4355 | - | else throw testing::TestError::Failed; |
|
| 4356 | - | } |
|
| 4357 | - | ||
| 4358 | - | /// Test `.delete()` on immutable slice produces an error. |
|
| 4359 | - | @test fn testResolveSliceDeleteImmutable() throws (testing::TestError) { |
|
| 4360 | - | let mut a = testResolver(); |
|
| 4361 | - | let program = "fn f(s: *[i32]) { s.delete(0); }"; |
|
| 4362 | - | let result = try resolveProgramStr(&mut a, program); |
|
| 4363 | - | let err = try expectError(&result); |
|
| 4364 | - | let case super::ErrorKind::ImmutableBinding = err.kind |
|
| 4365 | - | else throw testing::TestError::Failed; |
|
| 4366 | - | } |
|
| 4367 | - | ||
| 4368 | - | /// Test `.delete()` with wrong argument count produces an error. |
|
| 4369 | - | @test fn testResolveSliceDeleteWrongArgCount() throws (testing::TestError) { |
|
| 4370 | - | // No arguments. |
|
| 4371 | - | { |
|
| 4372 | - | let mut a = testResolver(); |
|
| 4373 | - | let program = "fn f(s: *mut [i32]) { s.delete(); }"; |
|
| 4374 | - | let result = try resolveProgramStr(&mut a, program); |
|
| 4375 | - | let err = try expectError(&result); |
|
| 4376 | - | let case super::ErrorKind::FnArgCountMismatch(m) = err.kind |
|
| 4377 | - | else throw testing::TestError::Failed; |
|
| 4378 | - | try testing::expect(m.expected == 1); |
|
| 4379 | - | try testing::expect(m.actual == 0); |
|
| 4380 | - | } |
|
| 4381 | - | // Too many arguments. |
|
| 4382 | - | { |
|
| 4383 | - | let mut a = testResolver(); |
|
| 4384 | - | let program = "fn f(s: *mut [i32]) { s.delete(0, 1); }"; |
|
| 4385 | - | let result = try resolveProgramStr(&mut a, program); |
|
| 4386 | - | let err = try expectError(&result); |
|
| 4387 | - | let case super::ErrorKind::FnArgCountMismatch(m) = err.kind |
|
| 4388 | - | else throw testing::TestError::Failed; |
|
| 4389 | - | try testing::expect(m.expected == 1); |
|
| 4390 | - | try testing::expect(m.actual == 2); |
|
| 4391 | - | } |
|
| 4392 | - | } |
|
| 4393 | - | ||
| 4394 | - | /// Test `.delete()` with correct arguments succeeds. |
|
| 4395 | - | @test fn testResolveSliceDeleteCorrect() throws (testing::TestError) { |
|
| 4396 | - | let mut a = testResolver(); |
|
| 4397 | - | let program = "fn f(s: *mut [i32]) { s.delete(0); }"; |
|
| 4398 | - | let result = try resolveProgramStr(&mut a, program); |
|
| 4399 | - | try expectNoErrors(&result); |
|
| 4400 | - | } |
|
| 4401 | - | ||
| 4402 | - | /// Test `.delete()` with wrong argument type produces an error. |
|
| 4403 | - | @test fn testResolveSliceDeleteWrongArgType() throws (testing::TestError) { |
|
| 4404 | - | let mut a = testResolver(); |
|
| 4405 | - | let program = "fn f(s: *mut [i32]) { s.delete(true); }"; |
|
| 4406 | - | let result = try resolveProgramStr(&mut a, program); |
|
| 4407 | - | let err = try expectError(&result); |
|
| 4408 | - | let case super::ErrorKind::TypeMismatch(_) = err.kind |
|
| 4409 | - | else throw testing::TestError::Failed; |
|
| 4410 | - | } |
|
| 4411 | - | ||
| 4412 | 4279 | /// Test `match &opt` produces immutable pointer bindings. |
|
| 4413 | 4280 | @test fn testResolveMatchRefUnionBinding() throws (testing::TestError) { |
|
| 4414 | 4281 | let mut a = testResolver(); |
|
| 4415 | 4282 | let program = "union Opt { Some(i32), None } fn f() { let opt = Opt::Some(42); match &opt { case Opt::Some(x) => { *x; } else => {} } }"; |
|
| 4416 | 4283 | let result = try resolveProgramStr(&mut a, program); |
| 5116 | 4983 | let arrStmt = try getBlockStmt(result.root, 3); |
|
| 5117 | 4984 | let sym = super::symbolFor(&a, arrStmt) |
|
| 5118 | 4985 | else throw testing::TestError::Failed; |
|
| 5119 | 4986 | let case super::SymbolData::Constant { type: super::Type::Array(arrType), .. } = sym.data |
|
| 5120 | 4987 | else throw testing::TestError::Failed; |
|
| 5121 | - | try testing::expect(arrType.length == 5); |
|
| 4988 | + | let actualLength = super::concreteArrayLength(arrType.length) |
|
| 4989 | + | else throw testing::TestError::Failed; |
|
| 4990 | + | try testing::expect(actualLength == 5); |
|
| 5122 | 4991 | } |
|
| 5123 | 4992 | ||
| 5124 | 4993 | /// Test cross-module constant expression: a constant in one module references |
|
| 5125 | 4994 | /// a constant from another module via scope access. |
|
| 5126 | 4995 | @test fn testCrossModuleConstExpr() throws (testing::TestError) { |
| 5199 | 5068 | let arrStmt = try getBlockStmt(result.root, 2); |
|
| 5200 | 5069 | let sym = super::symbolFor(&a, arrStmt) |
|
| 5201 | 5070 | else throw testing::TestError::Failed; |
|
| 5202 | 5071 | let case super::SymbolData::Constant { type: super::Type::Array(arrType), .. } = sym.data |
|
| 5203 | 5072 | else throw testing::TestError::Failed; |
|
| 5204 | - | try testing::expect(arrType.length == 4); |
|
| 5073 | + | let actualLength = super::concreteArrayLength(arrType.length) |
|
| 5074 | + | else throw testing::TestError::Failed; |
|
| 5075 | + | try testing::expect(actualLength == 4); |
|
| 5205 | 5076 | } |
|
| 5206 | 5077 | ||
| 5207 | 5078 | /// Test unsuffixed integer literals in constant expressions. |
|
| 5208 | 5079 | @test fn testConstExprUnsuffixedLiterals() throws (testing::TestError) { |
|
| 5209 | 5080 | try expectConstFold("constant A: u32 = 4 * 4;", 0, 16); |
| 5688 | 5559 | else throw testing::TestError::Failed; |
|
| 5689 | 5560 | let case super::NominalType::Record(recordType) = *nominal |
|
| 5690 | 5561 | else throw testing::TestError::Failed; |
|
| 5691 | 5562 | let case super::Type::Array(arrayType) = recordType.fields[0].fieldType |
|
| 5692 | 5563 | else throw testing::TestError::Failed; |
|
| 5693 | - | assert arrayType.length == 4; |
|
| 5564 | + | let actualLength = super::concreteArrayLength(arrayType.length) |
|
| 5565 | + | else throw testing::TestError::Failed; |
|
| 5566 | + | assert actualLength == 4; |
|
| 5694 | 5567 | assert recordType.layout.size == 4; |
|
| 5695 | 5568 | } |
|
| 5696 | 5569 | ||
| 5697 | 5570 | /// Equivalent integer expressions share a canonical specialization. |
|
| 5698 | 5571 | @test fn testGenericConstParameterCanonical() throws (testing::TestError) { |
| 5790 | 5663 | let case super::ErrorKind::UnresolvedSymbol(name) = err.kind |
|
| 5791 | 5664 | else throw testing::TestError::Failed; |
|
| 5792 | 5665 | assert mem::eq(name, "T"); |
|
| 5793 | 5666 | } |
|
| 5794 | 5667 | ||
| 5795 | - | /// Layout-dependent builtins reject symbolic generic types. |
|
| 5796 | - | @test fn testGenericParameterLayoutRejected() throws (testing::TestError) { |
|
| 5668 | + | /// Layout-dependent builtins accept symbolic generic types. |
|
| 5669 | + | @test fn testGenericParameterLayoutAccepted() throws (testing::TestError) { |
|
| 5797 | 5670 | let mut a = testResolver(); |
|
| 5798 | 5671 | let result = try resolveProgramStr( |
|
| 5799 | 5672 | &mut a, |
|
| 5800 | 5673 | "record Sized⟨T⟩ { bytes: u32 = @sizeOf(T) }", |
|
| 5801 | 5674 | ); |
|
| 5802 | - | try expectErrorKind(&result, super::ErrorKind::GenericLayoutRequired); |
|
| 5675 | + | try expectNoErrors(&result); |
|
| 5803 | 5676 | } |
|
| 5804 | 5677 | ||
| 5805 | 5678 | /// Generic data declarations cannot be used without specialization arguments. |
|
| 5806 | 5679 | @test fn testGenericArgumentsRequired() throws (testing::TestError) { |
|
| 5807 | 5680 | let mut a = testResolver(); |
lib/std/lang/scanner.rad
+1 -3
| 228 | 228 | export fn scanner(sourceLoc: SourceLoc, source: *[u8], pool: *mut strings::Pool) -> Scanner { |
|
| 229 | 229 | // Intern built-in functions and attributes. |
|
| 230 | 230 | strings::intern(pool, "@sizeOf"); |
|
| 231 | 231 | strings::intern(pool, "@alignOf"); |
|
| 232 | 232 | strings::intern(pool, "@sliceOf"); |
|
| 233 | + | strings::intern(pool, "@relocate"); |
|
| 233 | 234 | strings::intern(pool, "@default"); |
|
| 234 | 235 | strings::intern(pool, "@intrinsic"); |
|
| 235 | 236 | strings::intern(pool, "@test"); |
|
| 236 | - | // Intern built-in slice methods. |
|
| 237 | - | strings::intern(pool, "append"); |
|
| 238 | - | strings::intern(pool, "delete"); |
|
| 239 | 237 | ||
| 240 | 238 | return Scanner { sourceLoc, source, token: 0, cursor: 0, pool }; |
|
| 241 | 239 | } |
|
| 242 | 240 | ||
| 243 | 241 | /// Check if we've reached the end of input. |
lib/std/lang/slice.rad
added
+11 -0
| 1 | + | //! Typed slice construction from raw pointers. |
|
| 2 | + | ||
| 3 | + | /// Construct an immutable slice from a pointer and element count. |
|
| 4 | + | export fn fromRawParts⟨T⟩(ptr: *T, len: u32) -> *[T] { |
|
| 5 | + | return @sliceOf(ptr, len); |
|
| 6 | + | } |
|
| 7 | + | ||
| 8 | + | /// Construct a mutable slice from a pointer and element count. |
|
| 9 | + | export fn fromRawPartsMut⟨T⟩(ptr: *mut T, len: u32) -> *mut [T] { |
|
| 10 | + | return @sliceOf(ptr, len); |
|
| 11 | + | } |
lib/std/lang/vec.rad
added
+151 -0
| 1 | + | //! Typed vectors over caller-provided or allocator-grown storage. |
|
| 2 | + | ||
| 3 | + | use std::lang::alloc; |
|
| 4 | + | use std::lang::slice; |
|
| 5 | + | ||
| 6 | + | /// Typed vector metadata with initialized length and storage capacity. |
|
| 7 | + | export record Vec⟨T⟩ { |
|
| 8 | + | /// Typed slice containing the vector's storage. |
|
| 9 | + | data: *mut [T], |
|
| 10 | + | /// Number of initialized elements. |
|
| 11 | + | len: u32, |
|
| 12 | + | } |
|
| 13 | + | ||
| 14 | + | /// Initialize a vector over caller-owned storage. |
|
| 15 | + | export fn init⟨T⟩(vec: *mut Vec⟨T⟩, arena: *mut [T]) { |
|
| 16 | + | set vec.data = arena; |
|
| 17 | + | set vec.len = 0; |
|
| 18 | + | } |
|
| 19 | + | ||
| 20 | + | /// Return the number of initialized elements. |
|
| 21 | + | export fn len⟨T⟩(vec: *Vec⟨T⟩) -> u32 { |
|
| 22 | + | return vec.len; |
|
| 23 | + | } |
|
| 24 | + | ||
| 25 | + | /// Return the storage capacity in elements. |
|
| 26 | + | export fn capacity⟨T⟩(vec: *Vec⟨T⟩) -> u32 { |
|
| 27 | + | return vec.data.len; |
|
| 28 | + | } |
|
| 29 | + | ||
| 30 | + | /// Return a view containing the initialized elements. |
|
| 31 | + | export fn view⟨T⟩(vec: *Vec⟨T⟩) -> *[T] { |
|
| 32 | + | return slice::fromRawParts⟨T⟩(vec.data.ptr, vec.len); |
|
| 33 | + | } |
|
| 34 | + | ||
| 35 | + | /// Return a mutable view containing the initialized elements. |
|
| 36 | + | export fn viewMut⟨T⟩(vec: *mut Vec⟨T⟩) -> *mut [T] { |
|
| 37 | + | return slice::fromRawPartsMut⟨T⟩(vec.data.ptr, vec.len); |
|
| 38 | + | } |
|
| 39 | + | ||
| 40 | + | /// Reset a vector without clearing its storage. |
|
| 41 | + | export fn reset⟨T⟩(vec: *mut Vec⟨T⟩) { |
|
| 42 | + | set vec.len = 0; |
|
| 43 | + | } |
|
| 44 | + | ||
| 45 | + | /// Return a typed pointer to an element, or `nil` when out of bounds. |
|
| 46 | + | export fn get⟨T⟩(vec: *Vec⟨T⟩, index: u32) -> ?*T { |
|
| 47 | + | if index >= vec.len { |
|
| 48 | + | return nil; |
|
| 49 | + | } |
|
| 50 | + | ||
| 51 | + | return &vec.data[index]; |
|
| 52 | + | } |
|
| 53 | + | ||
| 54 | + | /// Append an element, returning `false` when the vector is full. |
|
| 55 | + | export fn push⟨T⟩(vec: *mut Vec⟨T⟩, value: T) -> bool { |
|
| 56 | + | if vec.len >= vec.data.len { |
|
| 57 | + | return false; |
|
| 58 | + | } |
|
| 59 | + | ||
| 60 | + | set vec.data[vec.len] = value; |
|
| 61 | + | set vec.len += 1; |
|
| 62 | + | ||
| 63 | + | return true; |
|
| 64 | + | } |
|
| 65 | + | ||
| 66 | + | /// Move bytes between equally bounded, potentially overlapping storage regions. |
|
| 67 | + | fn relocateBytes(destination: *mut [u8], source: *mut [u8]) { |
|
| 68 | + | @relocate(destination, source); |
|
| 69 | + | } |
|
| 70 | + | ||
| 71 | + | /// Allocate grown storage and move the initialized bytes into it. |
|
| 72 | + | fn growStorage( |
|
| 73 | + | data: *mut u8, |
|
| 74 | + | initializedBytes: u32, |
|
| 75 | + | capacityBytes: u32, |
|
| 76 | + | alignment: u32, |
|
| 77 | + | allocator: alloc::Allocator, |
|
| 78 | + | ) -> *mut u8 { |
|
| 79 | + | if capacityBytes == 0 { |
|
| 80 | + | return data; |
|
| 81 | + | } |
|
| 82 | + | let grown = allocator.func(allocator.ctx, capacityBytes, alignment) as *mut u8; |
|
| 83 | + | if initializedBytes > 0 { |
|
| 84 | + | relocateBytes( |
|
| 85 | + | slice::fromRawPartsMut⟨u8⟩(grown, initializedBytes), |
|
| 86 | + | slice::fromRawPartsMut⟨u8⟩(data, initializedBytes), |
|
| 87 | + | ); |
|
| 88 | + | } |
|
| 89 | + | return grown; |
|
| 90 | + | } |
|
| 91 | + | ||
| 92 | + | /// Append an element, growing the vector when it is full. |
|
| 93 | + | export fn append⟨T⟩(vec: *mut Vec⟨T⟩, value: T, allocator: alloc::Allocator) { |
|
| 94 | + | if vec.len == vec.data.len { |
|
| 95 | + | let capacity = (vec.data.len << 1) | 1; |
|
| 96 | + | let itemSize = @sizeOf(T); |
|
| 97 | + | let data = growStorage( |
|
| 98 | + | vec.data.ptr as *mut opaque as *mut u8, |
|
| 99 | + | vec.len * itemSize, |
|
| 100 | + | capacity * itemSize, |
|
| 101 | + | @alignOf(T), |
|
| 102 | + | allocator, |
|
| 103 | + | ) as *mut opaque as *mut T; |
|
| 104 | + | set vec.data = slice::fromRawPartsMut⟨T⟩(data, capacity); |
|
| 105 | + | } |
|
| 106 | + | ||
| 107 | + | set vec.data[vec.len] = value; |
|
| 108 | + | set vec.len += 1; |
|
| 109 | + | } |
|
| 110 | + | ||
| 111 | + | /// Replace an initialized element, returning `false` when out of bounds. |
|
| 112 | + | export fn put⟨T⟩(vec: *mut Vec⟨T⟩, index: u32, value: T) -> bool { |
|
| 113 | + | if index >= vec.len { |
|
| 114 | + | return false; |
|
| 115 | + | } |
|
| 116 | + | ||
| 117 | + | set vec.data[index] = value; |
|
| 118 | + | return true; |
|
| 119 | + | } |
|
| 120 | + | ||
| 121 | + | /// Remove and return an initialized element while preserving later element order. |
|
| 122 | + | export fn remove⟨T⟩(vec: *mut Vec⟨T⟩, index: u32) -> T { |
|
| 123 | + | assert index < vec.len; |
|
| 124 | + | ||
| 125 | + | let removed = vec.data[index]; |
|
| 126 | + | let tailBytes = (vec.len - index - 1) * @sizeOf(T); |
|
| 127 | + | if tailBytes > 0 { |
|
| 128 | + | relocateBytes( |
|
| 129 | + | slice::fromRawPartsMut⟨u8⟩( |
|
| 130 | + | &mut vec.data[index] as *mut opaque as *mut u8, |
|
| 131 | + | tailBytes, |
|
| 132 | + | ), |
|
| 133 | + | slice::fromRawPartsMut⟨u8⟩( |
|
| 134 | + | &mut vec.data[index + 1] as *mut opaque as *mut u8, |
|
| 135 | + | tailBytes, |
|
| 136 | + | ), |
|
| 137 | + | ); |
|
| 138 | + | } |
|
| 139 | + | ||
| 140 | + | set vec.len -= 1; |
|
| 141 | + | return removed; |
|
| 142 | + | } |
|
| 143 | + | ||
| 144 | + | /// Remove and return the last element, or `nil` when empty. |
|
| 145 | + | export fn pop⟨T⟩(vec: *mut Vec⟨T⟩) -> ?T { |
|
| 146 | + | if vec.len == 0 { |
|
| 147 | + | return nil; |
|
| 148 | + | } |
|
| 149 | + | set vec.len -= 1; |
|
| 150 | + | return vec.data[vec.len]; |
|
| 151 | + | } |
lib/std/slice.rad
added
+5 -0
| 1 | + | //! Public typed slice API. |
|
| 2 | + | //! |
|
| 3 | + | //! The implementation lives in `std::lang::slice` so language modules can |
|
| 4 | + | //! resolve it before this stable top-level facade. |
|
| 5 | + | export use std::lang::slice::*; |
lib/std/tests.rad
+146 -5
| 1 | 1 | //! Tests for formatting functions. |
|
| 2 | 2 | ||
| 3 | + | use std::lang::alloc; |
|
| 3 | 4 | use std::fmt; |
|
| 4 | 5 | use std::mem; |
|
| 5 | 6 | use std::vec; |
|
| 7 | + | use std::slice; |
|
| 6 | 8 | use std::testing; |
|
| 7 | 9 | use std::sys::unix; |
|
| 8 | 10 | ||
| 9 | 11 | /// Mixed-width value used by vector tests. |
|
| 10 | 12 | record Obj { |
| 12 | 14 | wide: u64, |
|
| 13 | 15 | /// Narrow field. |
|
| 14 | 16 | narrow: u8, |
|
| 15 | 17 | } |
|
| 16 | 18 | ||
| 19 | + | /// Zero-sized value used by vector growth and removal tests. |
|
| 20 | + | record ZeroSized {} |
|
| 21 | + | ||
| 17 | 22 | // fmt ///////////////////////////////////////////////////////////////////////// |
|
| 18 | 23 | ||
| 19 | 24 | @test fn testFormatU32Zero() throws (testing::TestError) { |
|
| 20 | 25 | let mut buffer: [u8; 11] = [0; 11]; |
|
| 21 | 26 | let result: *[u8] = fmt::formatU32(0, &mut buffer[..]); |
| 339 | 344 | try testing::expect(mem::cmp("abcd", "abc") > 0); |
|
| 340 | 345 | } |
|
| 341 | 346 | ||
| 342 | 347 | // vec ///////////////////////////////////////////////////////////////////////// |
|
| 343 | 348 | ||
| 344 | - | instantiate vec::Vec⟨i32⟩, |
|
| 345 | - | vec::init⟨i32⟩, |
|
| 349 | + | instantiate vec::init⟨i32⟩, |
|
| 346 | 350 | vec::len⟨i32⟩, |
|
| 347 | 351 | vec::capacity⟨i32⟩, |
|
| 348 | 352 | vec::reset⟨i32⟩, |
|
| 349 | 353 | vec::get⟨i32⟩, |
|
| 354 | + | vec::viewMut⟨i32⟩, |
|
| 350 | 355 | vec::push⟨i32⟩, |
|
| 351 | 356 | vec::put⟨i32⟩, |
|
| 352 | - | vec::pop⟨i32⟩; |
|
| 357 | + | vec::pop⟨i32⟩, |
|
| 358 | + | vec::append⟨i32⟩, |
|
| 359 | + | vec::remove⟨i32⟩, |
|
| 360 | + | vec::view⟨i32⟩; |
|
| 361 | + | ||
| 362 | + | instantiate vec::init⟨u8⟩, |
|
| 363 | + | vec::append⟨u8⟩, |
|
| 364 | + | vec::view⟨u8⟩; |
|
| 353 | 365 | ||
| 354 | - | instantiate vec::Vec⟨Obj⟩, |
|
| 355 | - | vec::init⟨Obj⟩, |
|
| 366 | + | instantiate vec::init⟨Obj⟩, |
|
| 356 | 367 | vec::get⟨Obj⟩, |
|
| 357 | 368 | vec::push⟨Obj⟩, |
|
| 358 | 369 | vec::put⟨Obj⟩; |
|
| 359 | 370 | ||
| 371 | + | instantiate vec::init⟨ZeroSized⟩, |
|
| 372 | + | vec::append⟨ZeroSized⟩, |
|
| 373 | + | vec::remove⟨ZeroSized⟩, |
|
| 374 | + | vec::view⟨ZeroSized⟩; |
|
| 375 | + | ||
| 360 | 376 | @test fn testVecInitialState() throws (testing::TestError) { |
|
| 361 | 377 | let mut arena: [i32; 4] = undefined; |
|
| 362 | 378 | let mut v: vec::Vec⟨i32⟩ = undefined; |
|
| 363 | 379 | vec::init⟨i32⟩(&mut v, &mut arena[..]); |
|
| 364 | 380 |
| 386 | 402 | else throw testing::TestError::Failed; |
|
| 387 | 403 | assert *replaced == 999; |
|
| 388 | 404 | assert not vec::put⟨i32⟩(&mut v, 3, 1); |
|
| 389 | 405 | } |
|
| 390 | 406 | ||
| 407 | + | @test fn testVecMutableViewAliasesStorage() throws (testing::TestError) { |
|
| 408 | + | let mut arena: [i32; 2] = undefined; |
|
| 409 | + | let mut v: vec::Vec⟨i32⟩ = undefined; |
|
| 410 | + | vec::init⟨i32⟩(&mut v, &mut arena[..]); |
|
| 411 | + | ||
| 412 | + | assert vec::push⟨i32⟩(&mut v, 10); |
|
| 413 | + | assert vec::push⟨i32⟩(&mut v, 20); |
|
| 414 | + | ||
| 415 | + | let mut view = vec::viewMut⟨i32⟩(&mut v); |
|
| 416 | + | assert view.len == 2; |
|
| 417 | + | set view[1] = 999; |
|
| 418 | + | ||
| 419 | + | let updated = vec::get⟨i32⟩(&v, 1) |
|
| 420 | + | else throw testing::TestError::Failed; |
|
| 421 | + | assert *updated == 999; |
|
| 422 | + | } |
|
| 423 | + | ||
| 391 | 424 | @test fn testVecPopReset() throws (testing::TestError) { |
|
| 392 | 425 | let mut arena: [i32; 2] = undefined; |
|
| 393 | 426 | let mut v: vec::Vec⟨i32⟩ = undefined; |
|
| 394 | 427 | vec::init⟨i32⟩(&mut v, &mut arena[..]); |
|
| 395 | 428 |
| 414 | 447 | let pair = vec::get⟨Obj⟩(&v, 0) |
|
| 415 | 448 | else throw testing::TestError::Failed; |
|
| 416 | 449 | assert pair.wide == 12; |
|
| 417 | 450 | assert pair.narrow == 2; |
|
| 418 | 451 | } |
|
| 452 | + | ||
| 453 | + | /// Storage for allocations made while testing vector growth. |
|
| 454 | + | static VEC_GROWTH_STORAGE: [u8; 256] = undefined; |
|
| 455 | + | ||
| 456 | + | @test fn testVecAppendAndRemove() throws (testing::TestError) { |
|
| 457 | + | let mut arena = alloc::new(&mut VEC_GROWTH_STORAGE[..]); |
|
| 458 | + | let allocator = alloc::arenaAllocator(&mut arena); |
|
| 459 | + | let mut storage: [i32; 2] = undefined; |
|
| 460 | + | let mut values: vec::Vec⟨i32⟩ = undefined; |
|
| 461 | + | vec::init⟨i32⟩(&mut values, &mut storage[..]); |
|
| 462 | + | ||
| 463 | + | vec::append⟨i32⟩(&mut values, 10, allocator); |
|
| 464 | + | vec::append⟨i32⟩(&mut values, 20, allocator); |
|
| 465 | + | vec::append⟨i32⟩(&mut values, 30, allocator); |
|
| 466 | + | assert vec::capacity⟨i32⟩(&values) > 2; |
|
| 467 | + | let grown = vec::view⟨i32⟩(&values); |
|
| 468 | + | assert grown.len == 3; |
|
| 469 | + | assert grown[0] == 10; |
|
| 470 | + | assert grown[1] == 20; |
|
| 471 | + | assert grown[2] == 30; |
|
| 472 | + | ||
| 473 | + | let capacity = vec::capacity⟨i32⟩(&values); |
|
| 474 | + | let first = vec::remove⟨i32⟩(&mut values, 0); |
|
| 475 | + | assert first == 10; |
|
| 476 | + | vec::append⟨i32⟩(&mut values, 40, allocator); |
|
| 477 | + | let third = vec::remove⟨i32⟩(&mut values, 1); |
|
| 478 | + | assert third == 30; |
|
| 479 | + | let middle = vec::view⟨i32⟩(&values); |
|
| 480 | + | assert middle.len == 2; |
|
| 481 | + | assert middle[0] == 20; |
|
| 482 | + | assert middle[1] == 40; |
|
| 483 | + | assert vec::capacity⟨i32⟩(&values) == capacity; |
|
| 484 | + | ||
| 485 | + | let final = vec::remove⟨i32⟩(&mut values, 1); |
|
| 486 | + | assert final == 40; |
|
| 487 | + | let last = vec::view⟨i32⟩(&values); |
|
| 488 | + | assert last.len == 1; |
|
| 489 | + | assert last[0] == 20; |
|
| 490 | + | } |
|
| 491 | + | ||
| 492 | + | @test fn testVecZeroSizedGrowthAndRemove() throws (testing::TestError) { |
|
| 493 | + | let mut arena = alloc::new(&mut VEC_GROWTH_STORAGE[..]); |
|
| 494 | + | let allocator = alloc::arenaAllocator(&mut arena); |
|
| 495 | + | let mut values: vec::Vec⟨ZeroSized⟩ = undefined; |
|
| 496 | + | vec::init⟨ZeroSized⟩(&mut values, &mut []); |
|
| 497 | + | ||
| 498 | + | vec::append⟨ZeroSized⟩(&mut values, ZeroSized {}, allocator); |
|
| 499 | + | vec::append⟨ZeroSized⟩(&mut values, ZeroSized {}, allocator); |
|
| 500 | + | vec::append⟨ZeroSized⟩(&mut values, ZeroSized {}, allocator); |
|
| 501 | + | vec::append⟨ZeroSized⟩(&mut values, ZeroSized {}, allocator); |
|
| 502 | + | let initialized = vec::view⟨ZeroSized⟩(&values); |
|
| 503 | + | assert initialized.len == 4; |
|
| 504 | + | ||
| 505 | + | let removed: ZeroSized = vec::remove⟨ZeroSized⟩(&mut values, 1); |
|
| 506 | + | assert removed == ZeroSized {}; |
|
| 507 | + | let remaining = vec::view⟨ZeroSized⟩(&values); |
|
| 508 | + | assert remaining.len == 3; |
|
| 509 | + | } |
|
| 510 | + | ||
| 511 | + | @test fn testVecAppendFromEmpty() throws (testing::TestError) { |
|
| 512 | + | let mut arena = alloc::new(&mut VEC_GROWTH_STORAGE[..]); |
|
| 513 | + | let allocator = alloc::arenaAllocator(&mut arena); |
|
| 514 | + | let mut values: vec::Vec⟨i32⟩ = undefined; |
|
| 515 | + | vec::init⟨i32⟩(&mut values, &mut []); |
|
| 516 | + | ||
| 517 | + | vec::append⟨i32⟩(&mut values, 99, allocator); |
|
| 518 | + | assert vec::capacity⟨i32⟩(&values) > 0; |
|
| 519 | + | let view = vec::view⟨i32⟩(&values); |
|
| 520 | + | assert view.len == 1; |
|
| 521 | + | assert view[0] == 99; |
|
| 522 | + | } |
|
| 523 | + | ||
| 524 | + | @test fn testVecAppendU8() throws (testing::TestError) { |
|
| 525 | + | let mut arena = alloc::new(&mut VEC_GROWTH_STORAGE[..]); |
|
| 526 | + | let allocator = alloc::arenaAllocator(&mut arena); |
|
| 527 | + | let mut storage: [u8; 1] = undefined; |
|
| 528 | + | let mut values: vec::Vec⟨u8⟩ = undefined; |
|
| 529 | + | vec::init⟨u8⟩(&mut values, &mut storage[..]); |
|
| 530 | + | ||
| 531 | + | vec::append⟨u8⟩(&mut values, 0xAB, allocator); |
|
| 532 | + | vec::append⟨u8⟩(&mut values, 0xCD, allocator); |
|
| 533 | + | let view = vec::view⟨u8⟩(&values); |
|
| 534 | + | assert view.len == 2; |
|
| 535 | + | assert view[0] == 0xAB; |
|
| 536 | + | assert view[1] == 0xCD; |
|
| 537 | + | } |
|
| 538 | + | ||
| 539 | + | // slice /////////////////////////////////////////////////////////////////////// |
|
| 540 | + | ||
| 541 | + | instantiate slice::fromRawParts⟨i32⟩, |
|
| 542 | + | slice::fromRawPartsMut⟨i32⟩; |
|
| 543 | + | ||
| 544 | + | @test fn testSliceFromRawParts() throws (testing::TestError) { |
|
| 545 | + | let mut values: [i32; 4] = [10, 20, 30, 40]; |
|
| 546 | + | let view = slice::fromRawParts⟨i32⟩(&values[1], 2); |
|
| 547 | + | assert view.len == 2; |
|
| 548 | + | assert view[0] == 20; |
|
| 549 | + | assert view[1] == 30; |
|
| 550 | + | ||
| 551 | + | let mutable = slice::fromRawPartsMut⟨i32⟩(&mut values[0], 3); |
|
| 552 | + | assert mutable.len == 3; |
|
| 553 | + | set mutable[1] = 99; |
|
| 554 | + | assert values[1] == 99; |
|
| 555 | + | assert view[0] == 99; |
|
| 556 | + | ||
| 557 | + | let empty = slice::fromRawParts⟨i32⟩(&values[0], 0); |
|
| 558 | + | assert empty.len == 0; |
|
| 559 | + | } |
lib/std/vec.rad
+5 -70
| 1 | - | //! Typed vector backed by caller-owned static storage. |
|
| 2 | - | ||
| 3 | - | /// Typed vector metadata backed by caller-owned storage. |
|
| 4 | - | export record Vec⟨T⟩ { |
|
| 5 | - | /// Typed slice containing the vector's storage. |
|
| 6 | - | data: *mut [T], |
|
| 7 | - | /// Number of initialized elements. |
|
| 8 | - | len: u32, |
|
| 9 | - | } |
|
| 10 | - | ||
| 11 | - | /// Initialize a vector over caller-owned storage. |
|
| 12 | - | export fn init⟨T⟩(vec: *mut Vec⟨T⟩, arena: *mut [T]) { |
|
| 13 | - | set vec.data = arena; |
|
| 14 | - | set vec.len = 0; |
|
| 15 | - | } |
|
| 16 | - | ||
| 17 | - | /// Return the number of initialized elements. |
|
| 18 | - | export fn len⟨T⟩(vec: *Vec⟨T⟩) -> u32 { |
|
| 19 | - | return vec.len; |
|
| 20 | - | } |
|
| 21 | - | ||
| 22 | - | /// Return the storage capacity in elements. |
|
| 23 | - | export fn capacity⟨T⟩(vec: *Vec⟨T⟩) -> u32 { |
|
| 24 | - | return vec.data.len; |
|
| 25 | - | } |
|
| 26 | - | ||
| 27 | - | /// Reset a vector without clearing its storage. |
|
| 28 | - | export fn reset⟨T⟩(vec: *mut Vec⟨T⟩) { |
|
| 29 | - | set vec.len = 0; |
|
| 30 | - | } |
|
| 31 | - | ||
| 32 | - | /// Return a typed pointer to an element, or `nil` when out of bounds. |
|
| 33 | - | export fn get⟨T⟩(vec: *Vec⟨T⟩, index: u32) -> ?*T { |
|
| 34 | - | if index >= vec.len { |
|
| 35 | - | return nil; |
|
| 36 | - | } |
|
| 37 | - | ||
| 38 | - | return &vec.data[index]; |
|
| 39 | - | } |
|
| 40 | - | ||
| 41 | - | /// Append an element, returning `false` when the vector is full. |
|
| 42 | - | export fn push⟨T⟩(vec: *mut Vec⟨T⟩, value: T) -> bool { |
|
| 43 | - | if vec.len >= vec.data.len { |
|
| 44 | - | return false; |
|
| 45 | - | } |
|
| 46 | - | ||
| 47 | - | set vec.data[vec.len] = value; |
|
| 48 | - | set vec.len += 1; |
|
| 49 | - | ||
| 50 | - | return true; |
|
| 51 | - | } |
|
| 52 | - | ||
| 53 | - | /// Replace an initialized element, returning `false` when out of bounds. |
|
| 54 | - | export fn put⟨T⟩(vec: *mut Vec⟨T⟩, index: u32, value: T) -> bool { |
|
| 55 | - | if index >= vec.len { |
|
| 56 | - | return false; |
|
| 57 | - | } |
|
| 58 | - | ||
| 59 | - | set vec.data[index] = value; |
|
| 60 | - | return true; |
|
| 61 | - | } |
|
| 62 | - | ||
| 63 | - | /// Remove and return the last element, or `nil` when empty. |
|
| 64 | - | export fn pop⟨T⟩(vec: *mut Vec⟨T⟩) -> ?T { |
|
| 65 | - | if vec.len == 0 { |
|
| 66 | - | return nil; |
|
| 67 | - | } |
|
| 68 | - | set vec.len -= 1; |
|
| 69 | - | return vec.data[vec.len]; |
|
| 70 | - | } |
|
| 1 | + | //! Public typed vector API. |
|
| 2 | + | //! |
|
| 3 | + | //! The implementation lives in `std::lang::vec` so language modules can |
|
| 4 | + | //! resolve it before this stable top-level facade. |
|
| 5 | + | export use std::lang::vec::*; |
seed/radiance.rv64
+0 -0
Binary file changed.
seed/radiance.rv64.git
+1 -1
| 1 | - | f102340ee2c496ef3ae997c4a449df1e805d63e30eef07fe7aa562bf2884eab3 |
|
| 1 | + | 3225bfc0f4e8414a142c1c31c309d6172bf96408739626c07578605ac8253188 |
std.lib
+3 -0
| 1 | 1 | lib/std.rad |
|
| 2 | 2 | lib/std/char.rad |
|
| 3 | 3 | lib/std/fmt.rad |
|
| 4 | 4 | lib/std/mem.rad |
|
| 5 | + | lib/std/slice.rad |
|
| 5 | 6 | lib/std/vec.rad |
|
| 6 | 7 | lib/std/io.rad |
|
| 7 | 8 | lib/std/intrinsics.rad |
|
| 8 | 9 | lib/std/sys.rad |
|
| 9 | 10 | lib/std/collections.rad |
| 20 | 21 | lib/std/arch/rv64/asm/scanner.rad |
|
| 21 | 22 | lib/std/arch/rv64/asm/parser.rad |
|
| 22 | 23 | lib/std/arch/rv64/asm/emit.rad |
|
| 23 | 24 | lib/std/lang.rad |
|
| 24 | 25 | lib/std/lang/alloc.rad |
|
| 26 | + | lib/std/lang/slice.rad |
|
| 27 | + | lib/std/lang/vec.rad |
|
| 25 | 28 | lib/std/lang/types.rad |
|
| 26 | 29 | lib/std/lang/strings.rad |
|
| 27 | 30 | lib/std/lang/sexpr.rad |
|
| 28 | 31 | lib/std/lang/ast.rad |
|
| 29 | 32 | lib/std/lang/ast/printer.rad |
test/tests/array.slice.full.ril
+0 -1
| 1 | 1 | fn w64 $sliceFull(w64 %0, w64 %1) { |
|
| 2 | 2 | @entry0 |
|
| 3 | 3 | reserve %2 16 8; |
|
| 4 | 4 | store w64 %1 %2 0; |
|
| 5 | 5 | store w32 4 %2 8; |
|
| 6 | - | store w32 4 %2 12; |
|
| 7 | 6 | blit %0 %2 16; |
|
| 8 | 7 | ret %0; |
|
| 9 | 8 | } |
test/tests/array.slice.openend.ril
+0 -1
| 9 | 9 | add w64 %4 %1 %3; |
|
| 10 | 10 | sub w32 %5 4 %2; |
|
| 11 | 11 | reserve %6 16 8; |
|
| 12 | 12 | store w64 %4 %6 0; |
|
| 13 | 13 | store w32 %5 %6 8; |
|
| 14 | - | store w32 %5 %6 12; |
|
| 15 | 14 | blit %0 %6 16; |
|
| 16 | 15 | ret %0; |
|
| 17 | 16 | } |
test/tests/array.slice.openstart.ril
+0 -1
| 6 | 6 | unreachable; |
|
| 7 | 7 | @guard#pass2 |
|
| 8 | 8 | reserve %3 16 8; |
|
| 9 | 9 | store w64 %1 %3 0; |
|
| 10 | 10 | store w32 %2 %3 8; |
|
| 11 | - | store w32 %2 %3 12; |
|
| 12 | 11 | blit %0 %3 16; |
|
| 13 | 12 | ret %0; |
|
| 14 | 13 | } |
test/tests/builtin.sliceof.invalid.cap.rad
deleted
+0 -10
| 1 | - | //! returns: 133 |
|
| 2 | - | //! Test @sliceOf runtime validation for len > cap. |
|
| 3 | - | ||
| 4 | - | @default fn main() -> i32 { |
|
| 5 | - | let mut arr: [i32; 4] = [10, 20, 30, 40]; |
|
| 6 | - | let ptr: *i32 = &arr[0]; |
|
| 7 | - | let slice: *[i32] = @sliceOf(ptr, 4, 3); |
|
| 8 | - | ||
| 9 | - | return slice.len as i32; |
|
| 10 | - | } |
test/tests/const.array.repeat.string.slice.ril
+2 -2
| 3 | 3 | } |
|
| 4 | 4 | ||
| 5 | 5 | data $WORDS align 8 { |
|
| 6 | 6 | sym $WORDS$literal$0; |
|
| 7 | 7 | w32 3; |
|
| 8 | - | w32 3; |
|
| 8 | + | undef * 4; |
|
| 9 | 9 | sym $WORDS$literal$0; |
|
| 10 | 10 | w32 3; |
|
| 11 | - | w32 3; |
|
| 11 | + | undef * 4; |
|
| 12 | 12 | } |
|
| 13 | 13 | ||
| 14 | 14 | fn w32 $main() { |
|
| 15 | 15 | @entry0 |
|
| 16 | 16 | copy %0 $WORDS; |
test/tests/const.array.strings.slice.ril
+3 -3
| 7 | 7 | } |
|
| 8 | 8 | ||
| 9 | 9 | data $WORDS align 8 { |
|
| 10 | 10 | sym $WORDS$literal$0; |
|
| 11 | 11 | w32 5; |
|
| 12 | - | w32 5; |
|
| 12 | + | undef * 4; |
|
| 13 | 13 | sym $WORDS$literal$1; |
|
| 14 | 14 | w32 6; |
|
| 15 | - | w32 6; |
|
| 15 | + | undef * 4; |
|
| 16 | 16 | sym $WORDS$literal$0; |
|
| 17 | 17 | w32 5; |
|
| 18 | - | w32 5; |
|
| 18 | + | undef * 4; |
|
| 19 | 19 | } |
|
| 20 | 20 | ||
| 21 | 21 | fn w32 $totalLen() { |
|
| 22 | 22 | @entry0 |
|
| 23 | 23 | copy %0 $WORDS; |
test/tests/const.record.union.ril
+3 -3
| 11 | 11 | } |
|
| 12 | 12 | ||
| 13 | 13 | data $KEYWORDS align 8 { |
|
| 14 | 14 | sym $KEYWORDS$literal$0; |
|
| 15 | 15 | w32 2; |
|
| 16 | - | w32 2; |
|
| 16 | + | undef * 4; |
|
| 17 | 17 | w8 0; |
|
| 18 | 18 | undef * 7; |
|
| 19 | 19 | sym $KEYWORDS$literal$1; |
|
| 20 | 20 | w32 3; |
|
| 21 | - | w32 3; |
|
| 21 | + | undef * 4; |
|
| 22 | 22 | w8 1; |
|
| 23 | 23 | undef * 7; |
|
| 24 | 24 | sym $KEYWORDS$literal$2; |
|
| 25 | 25 | w32 2; |
|
| 26 | - | w32 2; |
|
| 26 | + | undef * 4; |
|
| 27 | 27 | w8 2; |
|
| 28 | 28 | undef * 7; |
|
| 29 | 29 | } |
|
| 30 | 30 | ||
| 31 | 31 | fn w32 $getFirstTag() { |
test/tests/const.slice.of.slices.ril
+5 -5
| 7 | 7 | } |
|
| 8 | 8 | ||
| 9 | 9 | data $GROUPS$literal$2 align 8 { |
|
| 10 | 10 | sym $GROUPS$literal$0; |
|
| 11 | 11 | w32 2; |
|
| 12 | - | w32 2; |
|
| 12 | + | undef * 4; |
|
| 13 | 13 | sym $GROUPS$literal$1; |
|
| 14 | 14 | w32 2; |
|
| 15 | - | w32 2; |
|
| 15 | + | undef * 4; |
|
| 16 | 16 | } |
|
| 17 | 17 | ||
| 18 | 18 | data $GROUPS$literal$3 align 1 { |
|
| 19 | 19 | str "efg"; |
|
| 20 | 20 | } |
|
| 21 | 21 | ||
| 22 | 22 | data $GROUPS$literal$4 align 8 { |
|
| 23 | 23 | sym $GROUPS$literal$3; |
|
| 24 | 24 | w32 3; |
|
| 25 | - | w32 3; |
|
| 25 | + | undef * 4; |
|
| 26 | 26 | } |
|
| 27 | 27 | ||
| 28 | 28 | data $GROUPS align 8 { |
|
| 29 | 29 | sym $GROUPS$literal$2; |
|
| 30 | 30 | w32 2; |
|
| 31 | - | w32 2; |
|
| 31 | + | undef * 4; |
|
| 32 | 32 | sym $GROUPS$literal$4; |
|
| 33 | 33 | w32 1; |
|
| 34 | - | w32 1; |
|
| 34 | + | undef * 4; |
|
| 35 | 35 | } |
|
| 36 | 36 | ||
| 37 | 37 | fn w32 $totalLen() { |
|
| 38 | 38 | @entry0 |
|
| 39 | 39 | copy %0 $GROUPS; |
test/tests/const.string.ril
+1 -2
| 3 | 3 | } |
|
| 4 | 4 | ||
| 5 | 5 | data $HELLO align 8 { |
|
| 6 | 6 | sym $HELLO$literal$0; |
|
| 7 | 7 | w32 5; |
|
| 8 | - | w32 5; |
|
| 8 | + | undef * 4; |
|
| 9 | 9 | } |
|
| 10 | 10 | ||
| 11 | 11 | fn w32 $getLen() { |
|
| 12 | 12 | @entry0 |
|
| 13 | 13 | copy %0 $HELLO$literal$0; |
|
| 14 | 14 | reserve %1 16 8; |
|
| 15 | 15 | store w64 %0 %1 0; |
|
| 16 | 16 | store w32 5 %1 8; |
|
| 17 | - | store w32 5 %1 12; |
|
| 18 | 17 | load w32 %2 %1 8; |
|
| 19 | 18 | ret %2; |
|
| 20 | 19 | } |
test/tests/const.string.scoped.names.ril
+4 -6
| 3 | 3 | } |
|
| 4 | 4 | ||
| 5 | 5 | data $HELLO1 align 8 { |
|
| 6 | 6 | sym $HELLO1$literal$0; |
|
| 7 | 7 | w32 5; |
|
| 8 | - | w32 5; |
|
| 8 | + | undef * 4; |
|
| 9 | 9 | } |
|
| 10 | 10 | ||
| 11 | 11 | data $HELLO2 align 8 { |
|
| 12 | 12 | sym $HELLO1$literal$0; |
|
| 13 | 13 | w32 5; |
|
| 14 | - | w32 5; |
|
| 14 | + | undef * 4; |
|
| 15 | 15 | } |
|
| 16 | 16 | ||
| 17 | 17 | data $MSGS$literal$3 align 1 { |
|
| 18 | 18 | str "world"; |
|
| 19 | 19 | } |
|
| 20 | 20 | ||
| 21 | 21 | data $MSGS align 8 { |
|
| 22 | 22 | sym $HELLO1$literal$0; |
|
| 23 | 23 | w32 5; |
|
| 24 | - | w32 5; |
|
| 24 | + | undef * 4; |
|
| 25 | 25 | sym $MSGS$literal$3; |
|
| 26 | 26 | w32 5; |
|
| 27 | - | w32 5; |
|
| 27 | + | undef * 4; |
|
| 28 | 28 | } |
|
| 29 | 29 | ||
| 30 | 30 | fn w32 $totalLen() { |
|
| 31 | 31 | @entry0 |
|
| 32 | 32 | copy %0 $HELLO1$literal$0; |
|
| 33 | 33 | reserve %1 16 8; |
|
| 34 | 34 | store w64 %0 %1 0; |
|
| 35 | 35 | store w32 5 %1 8; |
|
| 36 | - | store w32 5 %1 12; |
|
| 37 | 36 | load w32 %2 %1 8; |
|
| 38 | 37 | copy %3 $HELLO1$literal$0; |
|
| 39 | 38 | reserve %4 16 8; |
|
| 40 | 39 | store w64 %3 %4 0; |
|
| 41 | 40 | store w32 5 %4 8; |
|
| 42 | - | store w32 5 %4 12; |
|
| 43 | 41 | load w32 %5 %4 8; |
|
| 44 | 42 | add w32 %6 %2 %5; |
|
| 45 | 43 | copy %7 $MSGS; |
|
| 46 | 44 | load w32 %8 %7 8; |
|
| 47 | 45 | add w32 %9 %6 %8; |
test/tests/field.aggregate.ril
+0 -1
| 33 | 33 | store w32 3 %0 8; |
|
| 34 | 34 | reserve %1 24 8; |
|
| 35 | 35 | reserve %2 16 8; |
|
| 36 | 36 | store w64 %0 %2 0; |
|
| 37 | 37 | store w32 3 %2 8; |
|
| 38 | - | store w32 3 %2 12; |
|
| 39 | 38 | blit %1 %2 16; |
|
| 40 | 39 | store w32 77 %1 16; |
|
| 41 | 40 | load w32 %3 %1 8; |
|
| 42 | 41 | ret %3; |
|
| 43 | 42 | } |
test/tests/generic.array.iteration.rad
added
+42 -0
| 1 | + | //! returns: 0 |
|
| 2 | + | //! Generic array iteration specializes symbolic element types and lengths. |
|
| 3 | + | ||
| 4 | + | /// Array storage whose length is derived from a constant argument. |
|
| 5 | + | record Extended⟨T, constant N: u32⟩ { |
|
| 6 | + | /// Elements stored in the derived array type. |
|
| 7 | + | items: [T; N + 1], |
|
| 8 | + | } |
|
| 9 | + | ||
| 10 | + | /// Visit every element and return the last one by index. |
|
| 11 | + | fn lastAfterVisit⟨T, constant N: u32⟩(items: [T; N]) -> T { |
|
| 12 | + | let mut visited: u32 = 0; |
|
| 13 | + | for _ in items { |
|
| 14 | + | set visited += 1; |
|
| 15 | + | } |
|
| 16 | + | assert visited == items.len; |
|
| 17 | + | return items[items.len - 1]; |
|
| 18 | + | } |
|
| 19 | + | ||
| 20 | + | fn lastByte⟨constant N: u64⟩(items: [u8; N]) -> u8 { |
|
| 21 | + | assert items.len == 3; |
|
| 22 | + | return items[items.len - 1]; |
|
| 23 | + | } |
|
| 24 | + | ||
| 25 | + | instantiate Extended⟨i32, 2⟩; |
|
| 26 | + | instantiate Extended⟨u8, 3⟩; |
|
| 27 | + | instantiate lastAfterVisit⟨i32, 3⟩; |
|
| 28 | + | instantiate lastAfterVisit⟨u8, 4⟩; |
|
| 29 | + | instantiate lastByte⟨3⟩; |
|
| 30 | + | ||
| 31 | + | /// Exercise generic iteration for distinct element types and derived lengths. |
|
| 32 | + | @default fn main() -> i32 { |
|
| 33 | + | let integers = Extended⟨i32, 2⟩ { items: [3, 5, 8] }; |
|
| 34 | + | let bytes = Extended⟨u8, 3⟩ { items: [1, 2, 3, 13] }; |
|
| 35 | + | let integer = lastAfterVisit⟨i32, 3⟩(integers.items); |
|
| 36 | + | let byte = lastAfterVisit⟨u8, 4⟩(bytes.items); |
|
| 37 | + | let bytes64: [u8; 3] = [1, 2, 3]; |
|
| 38 | + | assert bytes64.len == 3; |
|
| 39 | + | let last = lastByte⟨3⟩(bytes64); |
|
| 40 | + | assert last == bytes64[bytes64.len - 1]; |
|
| 41 | + | return integer + byte as i32 + last as i32 - 24; |
|
| 42 | + | } |
test/tests/generic.function.ril
+0 -2
| 50 | 50 | load w64 %2 %1 0; |
|
| 51 | 51 | load w32 %3 %1 8; |
|
| 52 | 52 | reserve %4 16 8; |
|
| 53 | 53 | store w64 %2 %4 0; |
|
| 54 | 54 | store w32 %3 %4 8; |
|
| 55 | - | store w32 %3 %4 12; |
|
| 56 | 55 | blit %0 %4 16; |
|
| 57 | 56 | ret %0; |
|
| 58 | 57 | } |
|
| 59 | 58 | ||
| 60 | 59 | fn w64 $"test::reslice⟨i32⟩"(w64 %0, w64 %1) { |
| 62 | 61 | load w64 %2 %1 0; |
|
| 63 | 62 | load w32 %3 %1 8; |
|
| 64 | 63 | reserve %4 16 8; |
|
| 65 | 64 | store w64 %2 %4 0; |
|
| 66 | 65 | store w32 %3 %4 8; |
|
| 67 | - | store w32 %3 %4 12; |
|
| 68 | 66 | blit %0 %4 16; |
|
| 69 | 67 | ret %0; |
|
| 70 | 68 | } |
|
| 71 | 69 | ||
| 72 | 70 | fn w64 $"test::some⟨test::Pair⟩"(w64 %0, w64 %1) { |
test/tests/literal.slice.bytes.ril
+0 -1
| 8 | 8 | @entry0 |
|
| 9 | 9 | copy %0 $byteSlice$literal$0; |
|
| 10 | 10 | reserve %1 16 8; |
|
| 11 | 11 | store w64 %0 %1 0; |
|
| 12 | 12 | store w32 3 %1 8; |
|
| 13 | - | store w32 3 %1 12; |
|
| 14 | 13 | load w32 %2 %1 8; |
|
| 15 | 14 | ret %2; |
|
| 16 | 15 | } |
test/tests/literal.slice.dedup.ril
+0 -2
| 8 | 8 | @entry0 |
|
| 9 | 9 | copy %0 $dedupSlice$literal$0; |
|
| 10 | 10 | reserve %1 16 8; |
|
| 11 | 11 | store w64 %0 %1 0; |
|
| 12 | 12 | store w32 3 %1 8; |
|
| 13 | - | store w32 3 %1 12; |
|
| 14 | 13 | copy %2 $dedupSlice$literal$0; |
|
| 15 | 14 | reserve %3 16 8; |
|
| 16 | 15 | store w64 %2 %3 0; |
|
| 17 | 16 | store w32 3 %3 8; |
|
| 18 | - | store w32 3 %3 12; |
|
| 19 | 17 | load w32 %4 %1 8; |
|
| 20 | 18 | load w32 %5 %3 8; |
|
| 21 | 19 | add w32 %6 %4 %5; |
|
| 22 | 20 | ret %6; |
|
| 23 | 21 | } |
test/tests/literal.slice.empty.ril
+0 -1
| 1 | 1 | fn w32 $emptySlice() { |
|
| 2 | 2 | @entry0 |
|
| 3 | 3 | reserve %0 16 8; |
|
| 4 | 4 | store w64 0 %0 0; |
|
| 5 | 5 | store w32 0 %0 8; |
|
| 6 | - | store w32 0 %0 12; |
|
| 7 | 6 | load w32 %1 %0 8; |
|
| 8 | 7 | ret %1; |
|
| 9 | 8 | } |
test/tests/literal.slice.multi.ril
+0 -2
| 13 | 13 | @entry0 |
|
| 14 | 14 | copy %0 $multiSlice$literal$0; |
|
| 15 | 15 | reserve %1 16 8; |
|
| 16 | 16 | store w64 %0 %1 0; |
|
| 17 | 17 | store w32 2 %1 8; |
|
| 18 | - | store w32 2 %1 12; |
|
| 19 | 18 | copy %2 $multiSlice$literal$1; |
|
| 20 | 19 | reserve %3 16 8; |
|
| 21 | 20 | store w64 %2 %3 0; |
|
| 22 | 21 | store w32 3 %3 8; |
|
| 23 | - | store w32 3 %3 12; |
|
| 24 | 22 | load w32 %4 %1 8; |
|
| 25 | 23 | load w32 %5 %3 8; |
|
| 26 | 24 | add w32 %6 %4 %5; |
|
| 27 | 25 | ret %6; |
|
| 28 | 26 | } |
test/tests/literal.slice.record.ril
+0 -1
| 9 | 9 | @entry0 |
|
| 10 | 10 | copy %0 $localSliceOfRecords$literal$0; |
|
| 11 | 11 | reserve %1 16 8; |
|
| 12 | 12 | store w64 %0 %1 0; |
|
| 13 | 13 | store w32 2 %1 8; |
|
| 14 | - | store w32 2 %1 12; |
|
| 15 | 14 | load w32 %2 %1 8; |
|
| 16 | 15 | br.ult w32 0 %2 @guard#pass1 @guard#trap2; |
|
| 17 | 16 | @guard#pass1 |
|
| 18 | 17 | load w64 %3 %1 0; |
|
| 19 | 18 | sload w32 %4 %3 0; |
test/tests/literal.slice.ril
+0 -1
| 8 | 8 | @entry0 |
|
| 9 | 9 | copy %0 $sliceLiteral$literal$0; |
|
| 10 | 10 | reserve %1 16 8; |
|
| 11 | 11 | store w64 %0 %1 0; |
|
| 12 | 12 | store w32 3 %1 8; |
|
| 13 | - | store w32 3 %1 12; |
|
| 14 | 13 | load w32 %2 %1 8; |
|
| 15 | 14 | ret %2; |
|
| 16 | 15 | } |
test/tests/literal.string.dedup.ril
+0 -2
| 6 | 6 | @entry0 |
|
| 7 | 7 | copy %0 $dedupString$literal$0; |
|
| 8 | 8 | reserve %1 16 8; |
|
| 9 | 9 | store w64 %0 %1 0; |
|
| 10 | 10 | store w32 5 %1 8; |
|
| 11 | - | store w32 5 %1 12; |
|
| 12 | 11 | copy %2 $dedupString$literal$0; |
|
| 13 | 12 | reserve %3 16 8; |
|
| 14 | 13 | store w64 %2 %3 0; |
|
| 15 | 14 | store w32 5 %3 8; |
|
| 16 | - | store w32 5 %3 12; |
|
| 17 | 15 | load w32 %4 %1 8; |
|
| 18 | 16 | load w32 %5 %3 8; |
|
| 19 | 17 | add w32 %6 %4 %5; |
|
| 20 | 18 | ret %6; |
|
| 21 | 19 | } |
test/tests/literal.string.empty.ril
+0 -1
| 6 | 6 | @entry0 |
|
| 7 | 7 | copy %0 $emptyString$literal$0; |
|
| 8 | 8 | reserve %1 16 8; |
|
| 9 | 9 | store w64 %0 %1 0; |
|
| 10 | 10 | store w32 0 %1 8; |
|
| 11 | - | store w32 0 %1 12; |
|
| 12 | 11 | load w32 %2 %1 8; |
|
| 13 | 12 | ret %2; |
|
| 14 | 13 | } |
test/tests/literal.string.fns.ril
+0 -2
| 10 | 10 | @entry0 |
|
| 11 | 11 | copy %0 $first$literal$0; |
|
| 12 | 12 | reserve %1 16 8; |
|
| 13 | 13 | store w64 %0 %1 0; |
|
| 14 | 14 | store w32 3 %1 8; |
|
| 15 | - | store w32 3 %1 12; |
|
| 16 | 15 | load w32 %2 %1 8; |
|
| 17 | 16 | ret %2; |
|
| 18 | 17 | } |
|
| 19 | 18 | ||
| 20 | 19 | fn w32 $second() { |
|
| 21 | 20 | @entry0 |
|
| 22 | 21 | copy %0 $second$literal$0; |
|
| 23 | 22 | reserve %1 16 8; |
|
| 24 | 23 | store w64 %0 %1 0; |
|
| 25 | 24 | store w32 3 %1 8; |
|
| 26 | - | store w32 3 %1 12; |
|
| 27 | 25 | load w32 %2 %1 8; |
|
| 28 | 26 | ret %2; |
|
| 29 | 27 | } |
test/tests/literal.string.multi.ril
+0 -2
| 10 | 10 | @entry0 |
|
| 11 | 11 | copy %0 $multiString$literal$0; |
|
| 12 | 12 | reserve %1 16 8; |
|
| 13 | 13 | store w64 %0 %1 0; |
|
| 14 | 14 | store w32 5 %1 8; |
|
| 15 | - | store w32 5 %1 12; |
|
| 16 | 15 | copy %2 $multiString$literal$1; |
|
| 17 | 16 | reserve %3 16 8; |
|
| 18 | 17 | store w64 %2 %3 0; |
|
| 19 | 18 | store w32 5 %3 8; |
|
| 20 | - | store w32 5 %3 12; |
|
| 21 | 19 | load w32 %4 %1 8; |
|
| 22 | 20 | load w32 %5 %3 8; |
|
| 23 | 21 | add w32 %6 %4 %5; |
|
| 24 | 22 | ret %6; |
|
| 25 | 23 | } |
test/tests/literal.string.ril
+0 -1
| 6 | 6 | @entry0 |
|
| 7 | 7 | copy %0 $stringLen$literal$0; |
|
| 8 | 8 | reserve %1 16 8; |
|
| 9 | 9 | store w64 %0 %1 0; |
|
| 10 | 10 | store w32 5 %1 8; |
|
| 11 | - | store w32 5 %1 12; |
|
| 12 | 11 | load w32 %2 %1 8; |
|
| 13 | 12 | ret %2; |
|
| 14 | 13 | } |
test/tests/lower.const.record.ident.ril
+2 -2
| 15 | 15 | } |
|
| 16 | 16 | ||
| 17 | 17 | data $ENTRIES align 8 { |
|
| 18 | 18 | sym $ENTRIES$literal$2; |
|
| 19 | 19 | w32 2; |
|
| 20 | - | w32 2; |
|
| 20 | + | undef * 4; |
|
| 21 | 21 | w8 10; |
|
| 22 | 22 | undef * 7; |
|
| 23 | 23 | sym $ENTRIES$literal$3; |
|
| 24 | 24 | w32 2; |
|
| 25 | - | w32 2; |
|
| 25 | + | undef * 4; |
|
| 26 | 26 | w8 11; |
|
| 27 | 27 | undef * 7; |
|
| 28 | 28 | } |
|
| 29 | 29 | ||
| 30 | 30 | fn w32 $main() { |
test/tests/lower.private.union.const.ril
+2 -2
| 7 | 7 | } |
|
| 8 | 8 | ||
| 9 | 9 | data $ENTRIES align 8 { |
|
| 10 | 10 | sym $ENTRIES$literal$0; |
|
| 11 | 11 | w32 1; |
|
| 12 | - | w32 1; |
|
| 12 | + | undef * 4; |
|
| 13 | 13 | w8 0; |
|
| 14 | 14 | undef * 7; |
|
| 15 | 15 | sym $ENTRIES$literal$1; |
|
| 16 | 16 | w32 1; |
|
| 17 | - | w32 1; |
|
| 17 | + | undef * 4; |
|
| 18 | 18 | w8 1; |
|
| 19 | 19 | undef * 7; |
|
| 20 | 20 | } |
|
| 21 | 21 | ||
| 22 | 22 | fn w32 $main() { |
test/tests/lower.record.scalar.record.const.ril
+2 -2
| 7 | 7 | } |
|
| 8 | 8 | ||
| 9 | 9 | data $ENTRIES align 8 { |
|
| 10 | 10 | sym $ENTRIES$literal$0; |
|
| 11 | 11 | w32 2; |
|
| 12 | - | w32 2; |
|
| 12 | + | undef * 4; |
|
| 13 | 13 | w8 10; |
|
| 14 | 14 | undef * 7; |
|
| 15 | 15 | sym $ENTRIES$literal$1; |
|
| 16 | 16 | w32 2; |
|
| 17 | - | w32 2; |
|
| 17 | + | undef * 4; |
|
| 18 | 18 | w8 11; |
|
| 19 | 19 | undef * 7; |
|
| 20 | 20 | } |
|
| 21 | 21 | ||
| 22 | 22 | fn w32 $main() { |
test/tests/opt.slice.npo.ril
+0 -12
| 22 | 22 | fn w8 $checkNil() { |
|
| 23 | 23 | @entry0 |
|
| 24 | 24 | reserve %0 16 8; |
|
| 25 | 25 | store w64 0 %0 0; |
|
| 26 | 26 | store w32 0 %0 8; |
|
| 27 | - | store w32 0 %0 12; |
|
| 28 | 27 | load w64 %1 %0 0; |
|
| 29 | 28 | eq w64 %2 %1 0; |
|
| 30 | 29 | br.ne w32 %2 0 @assert.ok2 @assert.fail1; |
|
| 31 | 30 | @assert.fail1 |
|
| 32 | 31 | unreachable; |
| 41 | 40 | store w8 2 %0 1; |
|
| 42 | 41 | store w8 3 %0 2; |
|
| 43 | 42 | reserve %1 16 8; |
|
| 44 | 43 | store w64 %0 %1 0; |
|
| 45 | 44 | store w32 3 %1 8; |
|
| 46 | - | store w32 3 %1 12; |
|
| 47 | 45 | reserve %2 16 8; |
|
| 48 | 46 | blit %2 %1 16; |
|
| 49 | 47 | load w64 %3 %2 0; |
|
| 50 | 48 | ne w64 %4 %3 0; |
|
| 51 | 49 | br.ne w32 %4 0 @assert.ok2 @assert.fail1; |
| 62 | 60 | store w8 20 %0 1; |
|
| 63 | 61 | store w8 30 %0 2; |
|
| 64 | 62 | reserve %1 16 8; |
|
| 65 | 63 | store w64 %0 %1 0; |
|
| 66 | 64 | store w32 3 %1 8; |
|
| 67 | - | store w32 3 %1 12; |
|
| 68 | 65 | reserve %2 16 8; |
|
| 69 | 66 | blit %2 %1 16; |
|
| 70 | 67 | reserve %3 16 8; |
|
| 71 | 68 | blit %3 %2 16; |
|
| 72 | 69 | load w64 %4 %3 0; |
| 107 | 104 | unreachable; |
|
| 108 | 105 | @merge13 |
|
| 109 | 106 | reserve %13 16 8; |
|
| 110 | 107 | store w64 0 %13 0; |
|
| 111 | 108 | store w32 0 %13 8; |
|
| 112 | - | store w32 0 %13 12; |
|
| 113 | 109 | reserve %14 16 8; |
|
| 114 | 110 | blit %14 %13 16; |
|
| 115 | 111 | load w64 %15 %14 0; |
|
| 116 | 112 | br.ne w32 %15 0 @then14 @else15; |
|
| 117 | 113 | @then14 |
| 129 | 125 | store w8 20 %0 1; |
|
| 130 | 126 | store w8 30 %0 2; |
|
| 131 | 127 | reserve %1 16 8; |
|
| 132 | 128 | store w64 %0 %1 0; |
|
| 133 | 129 | store w32 3 %1 8; |
|
| 134 | - | store w32 3 %1 12; |
|
| 135 | 130 | reserve %2 16 8; |
|
| 136 | 131 | blit %2 %1 16; |
|
| 137 | 132 | reserve %3 16 8; |
|
| 138 | 133 | blit %3 %2 16; |
|
| 139 | 134 | load w64 %4 %3 0; |
| 154 | 149 | fn w64 $returnNil(w64 %0) { |
|
| 155 | 150 | @entry0 |
|
| 156 | 151 | reserve %1 16 8; |
|
| 157 | 152 | store w64 0 %1 0; |
|
| 158 | 153 | store w32 0 %1 8; |
|
| 159 | - | store w32 0 %1 12; |
|
| 160 | 154 | blit %0 %1 16; |
|
| 161 | 155 | ret %0; |
|
| 162 | 156 | } |
|
| 163 | 157 | ||
| 164 | 158 | fn w64 $returnSome(w64 %0) { |
| 167 | 161 | store w8 42 %1 0; |
|
| 168 | 162 | store w8 99 %1 1; |
|
| 169 | 163 | reserve %2 16 8; |
|
| 170 | 164 | store w64 %1 %2 0; |
|
| 171 | 165 | store w32 2 %2 8; |
|
| 172 | - | store w32 2 %2 12; |
|
| 173 | 166 | blit %0 %2 16; |
|
| 174 | 167 | ret %0; |
|
| 175 | 168 | } |
|
| 176 | 169 | ||
| 177 | 170 | fn w8 $checkReturn() { |
| 222 | 215 | store w8 5 %0 0; |
|
| 223 | 216 | store w8 6 %0 1; |
|
| 224 | 217 | reserve %1 16 8; |
|
| 225 | 218 | store w64 %0 %1 0; |
|
| 226 | 219 | store w32 2 %1 8; |
|
| 227 | - | store w32 2 %1 12; |
|
| 228 | 220 | reserve %2 16 8; |
|
| 229 | 221 | blit %2 %1 16; |
|
| 230 | 222 | reserve %3 16 8; |
|
| 231 | 223 | blit %3 %2 16; |
|
| 232 | 224 | jmp @arm1; |
| 241 | 233 | jmp @merge6; |
|
| 242 | 234 | @merge6 |
|
| 243 | 235 | reserve %5 16 8; |
|
| 244 | 236 | store w64 0 %5 0; |
|
| 245 | 237 | store w32 0 %5 8; |
|
| 246 | - | store w32 0 %5 12; |
|
| 247 | 238 | reserve %6 16 8; |
|
| 248 | 239 | blit %6 %5 16; |
|
| 249 | 240 | jmp @arm7; |
|
| 250 | 241 | @arm7 |
|
| 251 | 242 | load w64 %7 %6 0; |
| 263 | 254 | fn w8 $checkEq() { |
|
| 264 | 255 | @entry0 |
|
| 265 | 256 | reserve %0 16 8; |
|
| 266 | 257 | store w64 0 %0 0; |
|
| 267 | 258 | store w32 0 %0 8; |
|
| 268 | - | store w32 0 %0 12; |
|
| 269 | 259 | reserve %1 16 8; |
|
| 270 | 260 | store w64 0 %1 0; |
|
| 271 | 261 | store w32 0 %1 8; |
|
| 272 | - | store w32 0 %1 12; |
|
| 273 | 262 | load w64 %2 %0 0; |
|
| 274 | 263 | load w64 %3 %1 0; |
|
| 275 | 264 | eq w64 %4 %2 %3; |
|
| 276 | 265 | load w32 %5 %0 8; |
|
| 277 | 266 | load w32 %6 %1 8; |
| 285 | 274 | store w8 1 %9 0; |
|
| 286 | 275 | store w8 2 %9 1; |
|
| 287 | 276 | reserve %10 16 8; |
|
| 288 | 277 | store w64 %9 %10 0; |
|
| 289 | 278 | store w32 2 %10 8; |
|
| 290 | - | store w32 2 %10 12; |
|
| 291 | 279 | reserve %11 16 8; |
|
| 292 | 280 | blit %11 %10 16; |
|
| 293 | 281 | load w64 %12 %11 0; |
|
| 294 | 282 | load w64 %13 %0 0; |
|
| 295 | 283 | eq w64 %14 %12 %13; |
test/tests/ptr.deref.ril
+0 -2
| 52 | 52 | call w32 %4 $derefArrayIndex(%3); |
|
| 53 | 53 | copy %5 $main$literal$0; |
|
| 54 | 54 | reserve %6 16 8; |
|
| 55 | 55 | store w64 %5 %6 0; |
|
| 56 | 56 | store w32 3 %6 8; |
|
| 57 | - | store w32 3 %6 12; |
|
| 58 | 57 | call w32 %7 $derefSliceIndex(%6); |
|
| 59 | 58 | add w32 %8 %1 %2; |
|
| 60 | 59 | add w32 %9 %8 %4; |
|
| 61 | 60 | add w32 %10 %9 %7; |
|
| 62 | 61 | ret %10; |
|
| 63 | 62 | } |
|
| 64 | - |
test/tests/reference.array.repeat.ril
+0 -1
| 6 | 6 | @entry0 |
|
| 7 | 7 | copy %1 $repeatedSlice$literal$0; |
|
| 8 | 8 | reserve %2 16 8; |
|
| 9 | 9 | store w64 %1 %2 0; |
|
| 10 | 10 | store w32 3 %2 8; |
|
| 11 | - | store w32 3 %2 12; |
|
| 12 | 11 | blit %0 %2 16; |
|
| 13 | 12 | ret %0; |
|
| 14 | 13 | } |
test/tests/relocate.bounds.rad
added
+10 -0
| 1 | + | //! returns: 133 |
|
| 2 | + | //! Test that relocation traps when the destination is shorter than the source. |
|
| 3 | + | ||
| 4 | + | @default fn main() -> i32 { |
|
| 5 | + | let mut bytes: [u8; 4] = [1, 2, 3, 4]; |
|
| 6 | + | let destination: *mut [u8] = &mut bytes[0..1]; |
|
| 7 | + | let source: *mut [u8] = &mut bytes[1..3]; |
|
| 8 | + | @relocate(destination, source); |
|
| 9 | + | return 0; |
|
| 10 | + | } |
test/tests/relocate.rad
added
+37 -0
| 1 | + | //! returns: 0 |
|
| 2 | + | //! Test overlap-safe relocation between mutable byte slices. |
|
| 3 | + | ||
| 4 | + | @default fn main() -> i32 { |
|
| 5 | + | let mut bytes: [u8; 6] = [1, 2, 3, 4, 5, 6]; |
|
| 6 | + | ||
| 7 | + | let rightDestination: *mut [u8] = &mut bytes[1..5]; |
|
| 8 | + | let rightSource: *mut [u8] = &mut bytes[0..4]; |
|
| 9 | + | @relocate(rightDestination, rightSource); |
|
| 10 | + | ||
| 11 | + | assert bytes[0] == 1; |
|
| 12 | + | assert bytes[1] == 1; |
|
| 13 | + | assert bytes[2] == 2; |
|
| 14 | + | assert bytes[3] == 3; |
|
| 15 | + | assert bytes[4] == 4; |
|
| 16 | + | assert bytes[5] == 6; |
|
| 17 | + | ||
| 18 | + | let leftDestination: *mut [u8] = &mut bytes[0..4]; |
|
| 19 | + | let leftSource: *mut [u8] = &mut bytes[1..5]; |
|
| 20 | + | @relocate(leftDestination, leftSource); |
|
| 21 | + | ||
| 22 | + | assert bytes[0] == 1; |
|
| 23 | + | assert bytes[1] == 2; |
|
| 24 | + | assert bytes[2] == 3; |
|
| 25 | + | assert bytes[3] == 4; |
|
| 26 | + | assert bytes[4] == 4; |
|
| 27 | + | assert bytes[5] == 6; |
|
| 28 | + | ||
| 29 | + | let emptyDestination: *mut [u8] = &mut bytes[0..0]; |
|
| 30 | + | let emptySource: *mut [u8] = &mut bytes[6..6]; |
|
| 31 | + | @relocate(emptyDestination, emptySource); |
|
| 32 | + | ||
| 33 | + | assert bytes[0] == 1; |
|
| 34 | + | assert bytes[5] == 6; |
|
| 35 | + | ||
| 36 | + | return 0; |
|
| 37 | + | } |
test/tests/slice.append.rad
deleted
+0 -191
| 1 | - | //! returns: 0 |
|
| 2 | - | //! Test slice .append() method with inline allocator. |
|
| 3 | - | ||
| 4 | - | /// Simple bump allocator for testing. |
|
| 5 | - | record Arena { |
|
| 6 | - | data: *mut [u8], |
|
| 7 | - | offset: u32, |
|
| 8 | - | } |
|
| 9 | - | ||
| 10 | - | fn newArena(data: *mut [u8]) -> Arena { |
|
| 11 | - | return Arena { data, offset: 0 }; |
|
| 12 | - | } |
|
| 13 | - | ||
| 14 | - | fn arenaAlloc(arena: *mut Arena, size: u32, al: u32) -> *mut opaque { |
|
| 15 | - | let aligned = (arena.offset + al - 1) / al * al; |
|
| 16 | - | let newOffset = aligned + size; |
|
| 17 | - | ||
| 18 | - | assert newOffset <= arena.data.len as u32; |
|
| 19 | - | ||
| 20 | - | let base: *mut u8 = &mut arena.data[aligned]; |
|
| 21 | - | set arena.offset = newOffset; |
|
| 22 | - | ||
| 23 | - | return base as *mut opaque; |
|
| 24 | - | } |
|
| 25 | - | ||
| 26 | - | /// Allocator record matching the compiler's expected layout. |
|
| 27 | - | record Allocator { |
|
| 28 | - | func: fn(*mut opaque, u32, u32) -> *mut opaque, |
|
| 29 | - | ctx: *mut opaque, |
|
| 30 | - | } |
|
| 31 | - | ||
| 32 | - | fn arenaAllocFn(ctx: *mut opaque, size: u32, al: u32) -> *mut opaque { |
|
| 33 | - | let arena = ctx as *mut Arena; |
|
| 34 | - | return arenaAlloc(arena, size, al); |
|
| 35 | - | } |
|
| 36 | - | ||
| 37 | - | fn arenaAllocator(arena: *mut Arena) -> Allocator { |
|
| 38 | - | return Allocator { |
|
| 39 | - | func: arenaAllocFn, |
|
| 40 | - | ctx: arena as *mut opaque, |
|
| 41 | - | }; |
|
| 42 | - | } |
|
| 43 | - | ||
| 44 | - | static BUF: [u8; 4096] = undefined; |
|
| 45 | - | ||
| 46 | - | @default fn main() -> i32 { |
|
| 47 | - | let mut arena = newArena(&mut BUF[..]); |
|
| 48 | - | let a = arenaAllocator(&mut arena); |
|
| 49 | - | ||
| 50 | - | // Allocate initial capacity of 4. |
|
| 51 | - | let ptr = arenaAlloc(&mut arena, @sizeOf(i32) * 4, @alignOf(i32)); |
|
| 52 | - | let mut nums = @sliceOf(ptr as *mut i32, 0, 4); |
|
| 53 | - | ||
| 54 | - | // Append within capacity. |
|
| 55 | - | nums.append(10, a); |
|
| 56 | - | nums.append(20, a); |
|
| 57 | - | nums.append(30, a); |
|
| 58 | - | ||
| 59 | - | if nums.len <> 3 { |
|
| 60 | - | return 1; |
|
| 61 | - | } |
|
| 62 | - | if nums.cap <> 4 { |
|
| 63 | - | return 2; |
|
| 64 | - | } |
|
| 65 | - | if nums[0] <> 10 { |
|
| 66 | - | return 3; |
|
| 67 | - | } |
|
| 68 | - | if nums[1] <> 20 { |
|
| 69 | - | return 4; |
|
| 70 | - | } |
|
| 71 | - | if nums[2] <> 30 { |
|
| 72 | - | return 5; |
|
| 73 | - | } |
|
| 74 | - | ||
| 75 | - | // Append to fill capacity. |
|
| 76 | - | nums.append(40, a); |
|
| 77 | - | ||
| 78 | - | if nums.len <> 4 { |
|
| 79 | - | return 6; |
|
| 80 | - | } |
|
| 81 | - | if nums.cap <> 4 { |
|
| 82 | - | return 7; |
|
| 83 | - | } |
|
| 84 | - | ||
| 85 | - | // Append past capacity -- triggers growth. |
|
| 86 | - | nums.append(50, a); |
|
| 87 | - | ||
| 88 | - | if nums.len <> 5 { |
|
| 89 | - | return 8; |
|
| 90 | - | } |
|
| 91 | - | // Cap should have grown (cap * 2 | 1 = 4 * 2 | 1 = 9). |
|
| 92 | - | if nums.cap <> 9 { |
|
| 93 | - | return 9; |
|
| 94 | - | } |
|
| 95 | - | if nums[4] <> 50 { |
|
| 96 | - | return 10; |
|
| 97 | - | } |
|
| 98 | - | ||
| 99 | - | // Verify old elements survived the copy. |
|
| 100 | - | if nums[0] <> 10 { |
|
| 101 | - | return 11; |
|
| 102 | - | } |
|
| 103 | - | if nums[3] <> 40 { |
|
| 104 | - | return 12; |
|
| 105 | - | } |
|
| 106 | - | ||
| 107 | - | // Append from empty (cap == 0 triggers growth with cap = 1). |
|
| 108 | - | let mut empty = @sliceOf(ptr as *mut i32, 0, 0); |
|
| 109 | - | empty.append(99, a); |
|
| 110 | - | ||
| 111 | - | if empty.len <> 1 { |
|
| 112 | - | return 13; |
|
| 113 | - | } |
|
| 114 | - | if empty.cap <> 1 { |
|
| 115 | - | return 14; |
|
| 116 | - | } |
|
| 117 | - | if empty[0] <> 99 { |
|
| 118 | - | return 15; |
|
| 119 | - | } |
|
| 120 | - | ||
| 121 | - | // Sum all elements in nums. |
|
| 122 | - | let mut sum: i32 = 0; |
|
| 123 | - | for n in nums { |
|
| 124 | - | set sum += n; |
|
| 125 | - | } |
|
| 126 | - | if sum <> 150 { |
|
| 127 | - | return 16; |
|
| 128 | - | } |
|
| 129 | - | ||
| 130 | - | // Test append with u8 elements (stride = 1). |
|
| 131 | - | let bytePtr = arenaAlloc(&mut arena, 2, 1); |
|
| 132 | - | let mut bytes = @sliceOf(bytePtr as *mut u8, 0, 2); |
|
| 133 | - | bytes.append(0xAB, a); |
|
| 134 | - | bytes.append(0xCD, a); |
|
| 135 | - | ||
| 136 | - | if bytes.len <> 2 { |
|
| 137 | - | return 17; |
|
| 138 | - | } |
|
| 139 | - | if bytes[0] <> 0xAB { |
|
| 140 | - | return 18; |
|
| 141 | - | } |
|
| 142 | - | if bytes[1] <> 0xCD { |
|
| 143 | - | return 19; |
|
| 144 | - | } |
|
| 145 | - | ||
| 146 | - | // Trigger growth on u8 slice. |
|
| 147 | - | bytes.append(0xEF, a); |
|
| 148 | - | ||
| 149 | - | if bytes.len <> 3 { |
|
| 150 | - | return 20; |
|
| 151 | - | } |
|
| 152 | - | if bytes.cap <> 5 { |
|
| 153 | - | return 21; |
|
| 154 | - | } |
|
| 155 | - | if bytes[2] <> 0xEF { |
|
| 156 | - | return 22; |
|
| 157 | - | } |
|
| 158 | - | // Verify old u8 elements survived. |
|
| 159 | - | if bytes[0] <> 0xAB { |
|
| 160 | - | return 23; |
|
| 161 | - | } |
|
| 162 | - | ||
| 163 | - | // Test that .append() returns the slice, allowing rebinding. |
|
| 164 | - | let ptr2 = arenaAlloc(&mut arena, @sizeOf(i32) * 2, @alignOf(i32)); |
|
| 165 | - | let mut vals = @sliceOf(ptr2 as *mut i32, 0, 2); |
|
| 166 | - | ||
| 167 | - | // Append within capacity, rebind via return value. |
|
| 168 | - | set vals = vals.append(42, a); |
|
| 169 | - | assert vals.len == 1; |
|
| 170 | - | assert vals[0] == 42; |
|
| 171 | - | ||
| 172 | - | set vals = vals.append(43, a); |
|
| 173 | - | assert vals.len == 2; |
|
| 174 | - | ||
| 175 | - | // Append past capacity -- triggers growth and returns updated slice. |
|
| 176 | - | let oldPtr = &vals[0] as *opaque; |
|
| 177 | - | set vals = vals.append(44, a); |
|
| 178 | - | assert vals.len == 3; |
|
| 179 | - | assert vals.cap == 5; |
|
| 180 | - | ||
| 181 | - | // After growth, the data pointer should have changed. |
|
| 182 | - | let newPtr = &vals[0] as *opaque; |
|
| 183 | - | assert oldPtr <> newPtr; |
|
| 184 | - | ||
| 185 | - | // Verify all elements survived. |
|
| 186 | - | assert vals[0] == 42; |
|
| 187 | - | assert vals[1] == 43; |
|
| 188 | - | assert vals[2] == 44; |
|
| 189 | - | ||
| 190 | - | return 0; |
|
| 191 | - | } |
test/tests/slice.append.ril
deleted
+0 -789
| 1 | - | data mut $BUF align 1 { |
|
| 2 | - | undef * 4096; |
|
| 3 | - | } |
|
| 4 | - | ||
| 5 | - | fn w64 $newArena(w64 %0, w64 %1) { |
|
| 6 | - | @entry0 |
|
| 7 | - | reserve %2 24 8; |
|
| 8 | - | blit %2 %1 16; |
|
| 9 | - | store w32 0 %2 16; |
|
| 10 | - | blit %0 %2 24; |
|
| 11 | - | ret %0; |
|
| 12 | - | } |
|
| 13 | - | ||
| 14 | - | fn w64 $arenaAlloc(w64 %0, w32 %1, w32 %2) { |
|
| 15 | - | @entry0 |
|
| 16 | - | load w32 %3 %0 16; |
|
| 17 | - | add w32 %4 %3 %2; |
|
| 18 | - | sub w32 %5 %4 1; |
|
| 19 | - | udiv w32 %6 %5 %2; |
|
| 20 | - | mul w32 %7 %6 %2; |
|
| 21 | - | add w32 %8 %7 %1; |
|
| 22 | - | load w32 %9 %0 8; |
|
| 23 | - | br.ult w32 %9 %8 @assert.fail1 @assert.ok2; |
|
| 24 | - | @assert.fail1 |
|
| 25 | - | unreachable; |
|
| 26 | - | @assert.ok2 |
|
| 27 | - | load w32 %10 %0 8; |
|
| 28 | - | br.ult w32 %7 %10 @guard#pass3 @guard#trap4; |
|
| 29 | - | @guard#pass3 |
|
| 30 | - | load w64 %11 %0 0; |
|
| 31 | - | add w64 %12 %11 %7; |
|
| 32 | - | store w32 %8 %0 16; |
|
| 33 | - | ret %12; |
|
| 34 | - | @guard#trap4 |
|
| 35 | - | ebreak; |
|
| 36 | - | unreachable; |
|
| 37 | - | } |
|
| 38 | - | ||
| 39 | - | fn w64 $arenaAllocFn(w64 %0, w32 %1, w32 %2) { |
|
| 40 | - | @entry0 |
|
| 41 | - | call w64 %3 $arenaAlloc(%0, %1, %2); |
|
| 42 | - | ret %3; |
|
| 43 | - | } |
|
| 44 | - | ||
| 45 | - | fn w64 $arenaAllocator(w64 %0, w64 %1) { |
|
| 46 | - | @entry0 |
|
| 47 | - | reserve %2 16 8; |
|
| 48 | - | copy %3 $arenaAllocFn; |
|
| 49 | - | store w64 %3 %2 0; |
|
| 50 | - | store w64 %1 %2 8; |
|
| 51 | - | blit %0 %2 16; |
|
| 52 | - | ret %0; |
|
| 53 | - | } |
|
| 54 | - | ||
| 55 | - | fn w32 $main() { |
|
| 56 | - | @entry0 |
|
| 57 | - | copy %0 $BUF; |
|
| 58 | - | reserve %1 16 8; |
|
| 59 | - | store w64 %0 %1 0; |
|
| 60 | - | store w32 4096 %1 8; |
|
| 61 | - | store w32 4096 %1 12; |
|
| 62 | - | reserve %2 24 8; |
|
| 63 | - | call w64 %3 $newArena(%2, %1); |
|
| 64 | - | reserve %4 16 8; |
|
| 65 | - | call w64 %5 $arenaAllocator(%4, %3); |
|
| 66 | - | mul w32 %6 4 4; |
|
| 67 | - | call w64 %7 $arenaAlloc(%3, %6, 4); |
|
| 68 | - | reserve %8 16 8; |
|
| 69 | - | store w64 %7 %8 0; |
|
| 70 | - | store w32 0 %8 8; |
|
| 71 | - | store w32 4 %8 12; |
|
| 72 | - | load w32 %9 %8 8; |
|
| 73 | - | load w32 %10 %8 12; |
|
| 74 | - | br.ult w32 %9 %10 @append.store1 @append.grow2; |
|
| 75 | - | @append.store1 |
|
| 76 | - | load w64 %24 %8 0; |
|
| 77 | - | mul w64 %25 %9 4; |
|
| 78 | - | add w64 %26 %24 %25; |
|
| 79 | - | store w32 10 %26 0; |
|
| 80 | - | add w32 %27 %9 1; |
|
| 81 | - | store w32 %27 %8 8; |
|
| 82 | - | load w32 %32 %8 8; |
|
| 83 | - | load w32 %33 %8 12; |
|
| 84 | - | br.ult w32 %32 %33 @append.store6 @append.grow7; |
|
| 85 | - | @append.grow2 |
|
| 86 | - | shl w32 %11 %10 1; |
|
| 87 | - | or w32 %12 %11 1; |
|
| 88 | - | load w64 %13 %5 0; |
|
| 89 | - | load w64 %14 %5 8; |
|
| 90 | - | mul w32 %15 %12 4; |
|
| 91 | - | call w64 %16 %13(%14, %15, 4); |
|
| 92 | - | load w64 %17 %8 0; |
|
| 93 | - | mul w32 %18 %9 4; |
|
| 94 | - | jmp @append3(0); |
|
| 95 | - | @append3(w32 %19) |
|
| 96 | - | br.ult w32 %19 %18 @append4 @append5; |
|
| 97 | - | @append4 |
|
| 98 | - | add w64 %20 %17 %19; |
|
| 99 | - | load w8 %21 %20 0; |
|
| 100 | - | add w64 %22 %16 %19; |
|
| 101 | - | store w8 %21 %22 0; |
|
| 102 | - | add w32 %23 %19 1; |
|
| 103 | - | jmp @append3(%23); |
|
| 104 | - | @append5 |
|
| 105 | - | store w64 %16 %8 0; |
|
| 106 | - | store w32 %12 %8 12; |
|
| 107 | - | jmp @append.store1; |
|
| 108 | - | @append.store6 |
|
| 109 | - | load w64 %47 %8 0; |
|
| 110 | - | mul w64 %48 %32 4; |
|
| 111 | - | add w64 %49 %47 %48; |
|
| 112 | - | store w32 20 %49 0; |
|
| 113 | - | add w32 %50 %32 1; |
|
| 114 | - | store w32 %50 %8 8; |
|
| 115 | - | load w32 %55 %8 8; |
|
| 116 | - | load w32 %56 %8 12; |
|
| 117 | - | br.ult w32 %55 %56 @append.store11 @append.grow12; |
|
| 118 | - | @append.grow7 |
|
| 119 | - | shl w32 %34 %33 1; |
|
| 120 | - | or w32 %35 %34 1; |
|
| 121 | - | load w64 %36 %5 0; |
|
| 122 | - | load w64 %37 %5 8; |
|
| 123 | - | mul w32 %38 %35 4; |
|
| 124 | - | call w64 %39 %36(%37, %38, 4); |
|
| 125 | - | load w64 %40 %8 0; |
|
| 126 | - | mul w32 %41 %32 4; |
|
| 127 | - | jmp @append8(0); |
|
| 128 | - | @append8(w32 %42) |
|
| 129 | - | br.ult w32 %42 %41 @append9 @append10; |
|
| 130 | - | @append9 |
|
| 131 | - | add w64 %43 %40 %42; |
|
| 132 | - | load w8 %44 %43 0; |
|
| 133 | - | add w64 %45 %39 %42; |
|
| 134 | - | store w8 %44 %45 0; |
|
| 135 | - | add w32 %46 %42 1; |
|
| 136 | - | jmp @append8(%46); |
|
| 137 | - | @append10 |
|
| 138 | - | store w64 %39 %8 0; |
|
| 139 | - | store w32 %35 %8 12; |
|
| 140 | - | jmp @append.store6; |
|
| 141 | - | @append.store11 |
|
| 142 | - | load w64 %70 %8 0; |
|
| 143 | - | mul w64 %71 %55 4; |
|
| 144 | - | add w64 %72 %70 %71; |
|
| 145 | - | store w32 30 %72 0; |
|
| 146 | - | add w32 %73 %55 1; |
|
| 147 | - | store w32 %73 %8 8; |
|
| 148 | - | load w32 %76 %8 8; |
|
| 149 | - | br.ne w32 %76 3 @then16 @merge17; |
|
| 150 | - | @append.grow12 |
|
| 151 | - | shl w32 %57 %56 1; |
|
| 152 | - | or w32 %58 %57 1; |
|
| 153 | - | load w64 %59 %5 0; |
|
| 154 | - | load w64 %60 %5 8; |
|
| 155 | - | mul w32 %61 %58 4; |
|
| 156 | - | call w64 %62 %59(%60, %61, 4); |
|
| 157 | - | load w64 %63 %8 0; |
|
| 158 | - | mul w32 %64 %55 4; |
|
| 159 | - | jmp @append13(0); |
|
| 160 | - | @append13(w32 %65) |
|
| 161 | - | br.ult w32 %65 %64 @append14 @append15; |
|
| 162 | - | @append14 |
|
| 163 | - | add w64 %66 %63 %65; |
|
| 164 | - | load w8 %67 %66 0; |
|
| 165 | - | add w64 %68 %62 %65; |
|
| 166 | - | store w8 %67 %68 0; |
|
| 167 | - | add w32 %69 %65 1; |
|
| 168 | - | jmp @append13(%69); |
|
| 169 | - | @append15 |
|
| 170 | - | store w64 %62 %8 0; |
|
| 171 | - | store w32 %58 %8 12; |
|
| 172 | - | jmp @append.store11; |
|
| 173 | - | @then16 |
|
| 174 | - | ret 1; |
|
| 175 | - | @merge17 |
|
| 176 | - | load w32 %77 %8 12; |
|
| 177 | - | br.ne w32 %77 4 @then18 @merge19; |
|
| 178 | - | @then18 |
|
| 179 | - | ret 2; |
|
| 180 | - | @merge19 |
|
| 181 | - | load w32 %78 %8 8; |
|
| 182 | - | br.ult w32 0 %78 @guard#pass22 @guard#trap23; |
|
| 183 | - | @then20 |
|
| 184 | - | ret 3; |
|
| 185 | - | @merge21 |
|
| 186 | - | load w32 %81 %8 8; |
|
| 187 | - | br.ult w32 1 %81 @guard#pass26 @guard#trap27; |
|
| 188 | - | @guard#pass22 |
|
| 189 | - | load w64 %79 %8 0; |
|
| 190 | - | sload w32 %80 %79 0; |
|
| 191 | - | br.ne w32 %80 10 @then20 @merge21; |
|
| 192 | - | @guard#trap23 |
|
| 193 | - | ebreak; |
|
| 194 | - | unreachable; |
|
| 195 | - | @then24 |
|
| 196 | - | ret 4; |
|
| 197 | - | @merge25 |
|
| 198 | - | load w32 %86 %8 8; |
|
| 199 | - | br.ult w32 2 %86 @guard#pass30 @guard#trap31; |
|
| 200 | - | @guard#pass26 |
|
| 201 | - | load w64 %82 %8 0; |
|
| 202 | - | mul w64 %83 1 4; |
|
| 203 | - | add w64 %84 %82 %83; |
|
| 204 | - | sload w32 %85 %84 0; |
|
| 205 | - | br.ne w32 %85 20 @then24 @merge25; |
|
| 206 | - | @guard#trap27 |
|
| 207 | - | ebreak; |
|
| 208 | - | unreachable; |
|
| 209 | - | @then28 |
|
| 210 | - | ret 5; |
|
| 211 | - | @merge29 |
|
| 212 | - | load w32 %93 %8 8; |
|
| 213 | - | load w32 %94 %8 12; |
|
| 214 | - | br.ult w32 %93 %94 @append.store32 @append.grow33; |
|
| 215 | - | @guard#pass30 |
|
| 216 | - | load w64 %87 %8 0; |
|
| 217 | - | mul w64 %88 2 4; |
|
| 218 | - | add w64 %89 %87 %88; |
|
| 219 | - | sload w32 %90 %89 0; |
|
| 220 | - | br.ne w32 %90 30 @then28 @merge29; |
|
| 221 | - | @guard#trap31 |
|
| 222 | - | ebreak; |
|
| 223 | - | unreachable; |
|
| 224 | - | @append.store32 |
|
| 225 | - | load w64 %108 %8 0; |
|
| 226 | - | mul w64 %109 %93 4; |
|
| 227 | - | add w64 %110 %108 %109; |
|
| 228 | - | store w32 40 %110 0; |
|
| 229 | - | add w32 %111 %93 1; |
|
| 230 | - | store w32 %111 %8 8; |
|
| 231 | - | load w32 %114 %8 8; |
|
| 232 | - | br.ne w32 %114 4 @then37 @merge38; |
|
| 233 | - | @append.grow33 |
|
| 234 | - | shl w32 %95 %94 1; |
|
| 235 | - | or w32 %96 %95 1; |
|
| 236 | - | load w64 %97 %5 0; |
|
| 237 | - | load w64 %98 %5 8; |
|
| 238 | - | mul w32 %99 %96 4; |
|
| 239 | - | call w64 %100 %97(%98, %99, 4); |
|
| 240 | - | load w64 %101 %8 0; |
|
| 241 | - | mul w32 %102 %93 4; |
|
| 242 | - | jmp @append34(0); |
|
| 243 | - | @append34(w32 %103) |
|
| 244 | - | br.ult w32 %103 %102 @append35 @append36; |
|
| 245 | - | @append35 |
|
| 246 | - | add w64 %104 %101 %103; |
|
| 247 | - | load w8 %105 %104 0; |
|
| 248 | - | add w64 %106 %100 %103; |
|
| 249 | - | store w8 %105 %106 0; |
|
| 250 | - | add w32 %107 %103 1; |
|
| 251 | - | jmp @append34(%107); |
|
| 252 | - | @append36 |
|
| 253 | - | store w64 %100 %8 0; |
|
| 254 | - | store w32 %96 %8 12; |
|
| 255 | - | jmp @append.store32; |
|
| 256 | - | @then37 |
|
| 257 | - | ret 6; |
|
| 258 | - | @merge38 |
|
| 259 | - | load w32 %115 %8 12; |
|
| 260 | - | br.ne w32 %115 4 @then39 @merge40; |
|
| 261 | - | @then39 |
|
| 262 | - | ret 7; |
|
| 263 | - | @merge40 |
|
| 264 | - | load w32 %118 %8 8; |
|
| 265 | - | load w32 %119 %8 12; |
|
| 266 | - | br.ult w32 %118 %119 @append.store41 @append.grow42; |
|
| 267 | - | @append.store41 |
|
| 268 | - | load w64 %133 %8 0; |
|
| 269 | - | mul w64 %134 %118 4; |
|
| 270 | - | add w64 %135 %133 %134; |
|
| 271 | - | store w32 50 %135 0; |
|
| 272 | - | add w32 %136 %118 1; |
|
| 273 | - | store w32 %136 %8 8; |
|
| 274 | - | load w32 %139 %8 8; |
|
| 275 | - | br.ne w32 %139 5 @then46 @merge47; |
|
| 276 | - | @append.grow42 |
|
| 277 | - | shl w32 %120 %119 1; |
|
| 278 | - | or w32 %121 %120 1; |
|
| 279 | - | load w64 %122 %5 0; |
|
| 280 | - | load w64 %123 %5 8; |
|
| 281 | - | mul w32 %124 %121 4; |
|
| 282 | - | call w64 %125 %122(%123, %124, 4); |
|
| 283 | - | load w64 %126 %8 0; |
|
| 284 | - | mul w32 %127 %118 4; |
|
| 285 | - | jmp @append43(0); |
|
| 286 | - | @append43(w32 %128) |
|
| 287 | - | br.ult w32 %128 %127 @append44 @append45; |
|
| 288 | - | @append44 |
|
| 289 | - | add w64 %129 %126 %128; |
|
| 290 | - | load w8 %130 %129 0; |
|
| 291 | - | add w64 %131 %125 %128; |
|
| 292 | - | store w8 %130 %131 0; |
|
| 293 | - | add w32 %132 %128 1; |
|
| 294 | - | jmp @append43(%132); |
|
| 295 | - | @append45 |
|
| 296 | - | store w64 %125 %8 0; |
|
| 297 | - | store w32 %121 %8 12; |
|
| 298 | - | jmp @append.store41; |
|
| 299 | - | @then46 |
|
| 300 | - | ret 8; |
|
| 301 | - | @merge47 |
|
| 302 | - | load w32 %140 %8 12; |
|
| 303 | - | br.ne w32 %140 9 @then48 @merge49; |
|
| 304 | - | @then48 |
|
| 305 | - | ret 9; |
|
| 306 | - | @merge49 |
|
| 307 | - | load w32 %141 %8 8; |
|
| 308 | - | br.ult w32 4 %141 @guard#pass52 @guard#trap53; |
|
| 309 | - | @then50 |
|
| 310 | - | ret 10; |
|
| 311 | - | @merge51 |
|
| 312 | - | load w32 %146 %8 8; |
|
| 313 | - | br.ult w32 0 %146 @guard#pass56 @guard#trap57; |
|
| 314 | - | @guard#pass52 |
|
| 315 | - | load w64 %142 %8 0; |
|
| 316 | - | mul w64 %143 4 4; |
|
| 317 | - | add w64 %144 %142 %143; |
|
| 318 | - | sload w32 %145 %144 0; |
|
| 319 | - | br.ne w32 %145 50 @then50 @merge51; |
|
| 320 | - | @guard#trap53 |
|
| 321 | - | ebreak; |
|
| 322 | - | unreachable; |
|
| 323 | - | @then54 |
|
| 324 | - | ret 11; |
|
| 325 | - | @merge55 |
|
| 326 | - | load w32 %149 %8 8; |
|
| 327 | - | br.ult w32 3 %149 @guard#pass60 @guard#trap61; |
|
| 328 | - | @guard#pass56 |
|
| 329 | - | load w64 %147 %8 0; |
|
| 330 | - | sload w32 %148 %147 0; |
|
| 331 | - | br.ne w32 %148 10 @then54 @merge55; |
|
| 332 | - | @guard#trap57 |
|
| 333 | - | ebreak; |
|
| 334 | - | unreachable; |
|
| 335 | - | @then58 |
|
| 336 | - | ret 12; |
|
| 337 | - | @merge59 |
|
| 338 | - | reserve %164 16 8; |
|
| 339 | - | store w64 %7 %164 0; |
|
| 340 | - | store w32 0 %164 8; |
|
| 341 | - | store w32 0 %164 12; |
|
| 342 | - | load w32 %167 %164 8; |
|
| 343 | - | load w32 %168 %164 12; |
|
| 344 | - | br.ult w32 %167 %168 @append.store62 @append.grow63; |
|
| 345 | - | @guard#pass60 |
|
| 346 | - | load w64 %150 %8 0; |
|
| 347 | - | mul w64 %151 3 4; |
|
| 348 | - | add w64 %152 %150 %151; |
|
| 349 | - | sload w32 %153 %152 0; |
|
| 350 | - | br.ne w32 %153 40 @then58 @merge59; |
|
| 351 | - | @guard#trap61 |
|
| 352 | - | ebreak; |
|
| 353 | - | unreachable; |
|
| 354 | - | @append.store62 |
|
| 355 | - | load w64 %182 %164 0; |
|
| 356 | - | mul w64 %183 %167 4; |
|
| 357 | - | add w64 %184 %182 %183; |
|
| 358 | - | store w32 99 %184 0; |
|
| 359 | - | add w32 %185 %167 1; |
|
| 360 | - | store w32 %185 %164 8; |
|
| 361 | - | load w32 %188 %164 8; |
|
| 362 | - | br.ne w32 %188 1 @then67 @merge68; |
|
| 363 | - | @append.grow63 |
|
| 364 | - | shl w32 %169 %168 1; |
|
| 365 | - | or w32 %170 %169 1; |
|
| 366 | - | load w64 %171 %5 0; |
|
| 367 | - | load w64 %172 %5 8; |
|
| 368 | - | mul w32 %173 %170 4; |
|
| 369 | - | call w64 %174 %171(%172, %173, 4); |
|
| 370 | - | load w64 %175 %164 0; |
|
| 371 | - | mul w32 %176 %167 4; |
|
| 372 | - | jmp @append64(0); |
|
| 373 | - | @append64(w32 %177) |
|
| 374 | - | br.ult w32 %177 %176 @append65 @append66; |
|
| 375 | - | @append65 |
|
| 376 | - | add w64 %178 %175 %177; |
|
| 377 | - | load w8 %179 %178 0; |
|
| 378 | - | add w64 %180 %174 %177; |
|
| 379 | - | store w8 %179 %180 0; |
|
| 380 | - | add w32 %181 %177 1; |
|
| 381 | - | jmp @append64(%181); |
|
| 382 | - | @append66 |
|
| 383 | - | store w64 %174 %164 0; |
|
| 384 | - | store w32 %170 %164 12; |
|
| 385 | - | jmp @append.store62; |
|
| 386 | - | @then67 |
|
| 387 | - | ret 13; |
|
| 388 | - | @merge68 |
|
| 389 | - | load w32 %189 %164 12; |
|
| 390 | - | br.ne w32 %189 1 @then69 @merge70; |
|
| 391 | - | @then69 |
|
| 392 | - | ret 14; |
|
| 393 | - | @merge70 |
|
| 394 | - | load w32 %190 %164 8; |
|
| 395 | - | br.ult w32 0 %190 @guard#pass73 @guard#trap74; |
|
| 396 | - | @then71 |
|
| 397 | - | ret 15; |
|
| 398 | - | @merge72 |
|
| 399 | - | load w32 %195 %8 8; |
|
| 400 | - | load w64 %196 %8 0; |
|
| 401 | - | jmp @loop75(0, 0); |
|
| 402 | - | @guard#pass73 |
|
| 403 | - | load w64 %191 %164 0; |
|
| 404 | - | sload w32 %192 %191 0; |
|
| 405 | - | br.ne w32 %192 99 @then71 @merge72; |
|
| 406 | - | @guard#trap74 |
|
| 407 | - | ebreak; |
|
| 408 | - | unreachable; |
|
| 409 | - | @loop75(w32 %197, w32 %201) |
|
| 410 | - | br.slt w32 %197 %195 @body76 @merge77; |
|
| 411 | - | @body76 |
|
| 412 | - | mul w64 %198 %197 4; |
|
| 413 | - | add w64 %199 %196 %198; |
|
| 414 | - | sload w32 %200 %199 0; |
|
| 415 | - | add w32 %202 %201 %200; |
|
| 416 | - | add w32 %203 %197 1; |
|
| 417 | - | jmp @loop75(%203, %202); |
|
| 418 | - | @merge77 |
|
| 419 | - | br.ne w32 %201 150 @then78 @merge79; |
|
| 420 | - | @then78 |
|
| 421 | - | ret 16; |
|
| 422 | - | @merge79 |
|
| 423 | - | call w64 %217 $arenaAlloc(%3, 2, 1); |
|
| 424 | - | reserve %218 16 8; |
|
| 425 | - | store w64 %217 %218 0; |
|
| 426 | - | store w32 0 %218 8; |
|
| 427 | - | store w32 2 %218 12; |
|
| 428 | - | load w32 %222 %218 8; |
|
| 429 | - | load w32 %223 %218 12; |
|
| 430 | - | br.ult w32 %222 %223 @append.store80 @append.grow81; |
|
| 431 | - | @append.store80 |
|
| 432 | - | load w64 %237 %218 0; |
|
| 433 | - | add w64 %238 %237 %222; |
|
| 434 | - | store w8 171 %238 0; |
|
| 435 | - | add w32 %239 %222 1; |
|
| 436 | - | store w32 %239 %218 8; |
|
| 437 | - | load w32 %244 %218 8; |
|
| 438 | - | load w32 %245 %218 12; |
|
| 439 | - | br.ult w32 %244 %245 @append.store85 @append.grow86; |
|
| 440 | - | @append.grow81 |
|
| 441 | - | shl w32 %224 %223 1; |
|
| 442 | - | or w32 %225 %224 1; |
|
| 443 | - | load w64 %226 %5 0; |
|
| 444 | - | load w64 %227 %5 8; |
|
| 445 | - | mul w32 %228 %225 1; |
|
| 446 | - | call w64 %229 %226(%227, %228, 1); |
|
| 447 | - | load w64 %230 %218 0; |
|
| 448 | - | mul w32 %231 %222 1; |
|
| 449 | - | jmp @append82(0); |
|
| 450 | - | @append82(w32 %232) |
|
| 451 | - | br.ult w32 %232 %231 @append83 @append84; |
|
| 452 | - | @append83 |
|
| 453 | - | add w64 %233 %230 %232; |
|
| 454 | - | load w8 %234 %233 0; |
|
| 455 | - | add w64 %235 %229 %232; |
|
| 456 | - | store w8 %234 %235 0; |
|
| 457 | - | add w32 %236 %232 1; |
|
| 458 | - | jmp @append82(%236); |
|
| 459 | - | @append84 |
|
| 460 | - | store w64 %229 %218 0; |
|
| 461 | - | store w32 %225 %218 12; |
|
| 462 | - | jmp @append.store80; |
|
| 463 | - | @append.store85 |
|
| 464 | - | load w64 %259 %218 0; |
|
| 465 | - | add w64 %260 %259 %244; |
|
| 466 | - | store w8 205 %260 0; |
|
| 467 | - | add w32 %261 %244 1; |
|
| 468 | - | store w32 %261 %218 8; |
|
| 469 | - | load w32 %264 %218 8; |
|
| 470 | - | br.ne w32 %264 2 @then90 @merge91; |
|
| 471 | - | @append.grow86 |
|
| 472 | - | shl w32 %246 %245 1; |
|
| 473 | - | or w32 %247 %246 1; |
|
| 474 | - | load w64 %248 %5 0; |
|
| 475 | - | load w64 %249 %5 8; |
|
| 476 | - | mul w32 %250 %247 1; |
|
| 477 | - | call w64 %251 %248(%249, %250, 1); |
|
| 478 | - | load w64 %252 %218 0; |
|
| 479 | - | mul w32 %253 %244 1; |
|
| 480 | - | jmp @append87(0); |
|
| 481 | - | @append87(w32 %254) |
|
| 482 | - | br.ult w32 %254 %253 @append88 @append89; |
|
| 483 | - | @append88 |
|
| 484 | - | add w64 %255 %252 %254; |
|
| 485 | - | load w8 %256 %255 0; |
|
| 486 | - | add w64 %257 %251 %254; |
|
| 487 | - | store w8 %256 %257 0; |
|
| 488 | - | add w32 %258 %254 1; |
|
| 489 | - | jmp @append87(%258); |
|
| 490 | - | @append89 |
|
| 491 | - | store w64 %251 %218 0; |
|
| 492 | - | store w32 %247 %218 12; |
|
| 493 | - | jmp @append.store85; |
|
| 494 | - | @then90 |
|
| 495 | - | ret 17; |
|
| 496 | - | @merge91 |
|
| 497 | - | load w32 %265 %218 8; |
|
| 498 | - | br.ult w32 0 %265 @guard#pass94 @guard#trap95; |
|
| 499 | - | @then92 |
|
| 500 | - | ret 18; |
|
| 501 | - | @merge93 |
|
| 502 | - | load w32 %268 %218 8; |
|
| 503 | - | br.ult w32 1 %268 @guard#pass98 @guard#trap99; |
|
| 504 | - | @guard#pass94 |
|
| 505 | - | load w64 %266 %218 0; |
|
| 506 | - | load w8 %267 %266 0; |
|
| 507 | - | br.ne w8 %267 171 @then92 @merge93; |
|
| 508 | - | @guard#trap95 |
|
| 509 | - | ebreak; |
|
| 510 | - | unreachable; |
|
| 511 | - | @then96 |
|
| 512 | - | ret 19; |
|
| 513 | - | @merge97 |
|
| 514 | - | load w32 %274 %218 8; |
|
| 515 | - | load w32 %275 %218 12; |
|
| 516 | - | br.ult w32 %274 %275 @append.store100 @append.grow101; |
|
| 517 | - | @guard#pass98 |
|
| 518 | - | load w64 %269 %218 0; |
|
| 519 | - | add w64 %270 %269 1; |
|
| 520 | - | load w8 %271 %270 0; |
|
| 521 | - | br.ne w8 %271 205 @then96 @merge97; |
|
| 522 | - | @guard#trap99 |
|
| 523 | - | ebreak; |
|
| 524 | - | unreachable; |
|
| 525 | - | @append.store100 |
|
| 526 | - | load w64 %289 %218 0; |
|
| 527 | - | add w64 %290 %289 %274; |
|
| 528 | - | store w8 239 %290 0; |
|
| 529 | - | add w32 %291 %274 1; |
|
| 530 | - | store w32 %291 %218 8; |
|
| 531 | - | load w32 %294 %218 8; |
|
| 532 | - | br.ne w32 %294 3 @then105 @merge106; |
|
| 533 | - | @append.grow101 |
|
| 534 | - | shl w32 %276 %275 1; |
|
| 535 | - | or w32 %277 %276 1; |
|
| 536 | - | load w64 %278 %5 0; |
|
| 537 | - | load w64 %279 %5 8; |
|
| 538 | - | mul w32 %280 %277 1; |
|
| 539 | - | call w64 %281 %278(%279, %280, 1); |
|
| 540 | - | load w64 %282 %218 0; |
|
| 541 | - | mul w32 %283 %274 1; |
|
| 542 | - | jmp @append102(0); |
|
| 543 | - | @append102(w32 %284) |
|
| 544 | - | br.ult w32 %284 %283 @append103 @append104; |
|
| 545 | - | @append103 |
|
| 546 | - | add w64 %285 %282 %284; |
|
| 547 | - | load w8 %286 %285 0; |
|
| 548 | - | add w64 %287 %281 %284; |
|
| 549 | - | store w8 %286 %287 0; |
|
| 550 | - | add w32 %288 %284 1; |
|
| 551 | - | jmp @append102(%288); |
|
| 552 | - | @append104 |
|
| 553 | - | store w64 %281 %218 0; |
|
| 554 | - | store w32 %277 %218 12; |
|
| 555 | - | jmp @append.store100; |
|
| 556 | - | @then105 |
|
| 557 | - | ret 20; |
|
| 558 | - | @merge106 |
|
| 559 | - | load w32 %295 %218 12; |
|
| 560 | - | br.ne w32 %295 5 @then107 @merge108; |
|
| 561 | - | @then107 |
|
| 562 | - | ret 21; |
|
| 563 | - | @merge108 |
|
| 564 | - | load w32 %296 %218 8; |
|
| 565 | - | br.ult w32 2 %296 @guard#pass111 @guard#trap112; |
|
| 566 | - | @then109 |
|
| 567 | - | ret 22; |
|
| 568 | - | @merge110 |
|
| 569 | - | load w32 %300 %218 8; |
|
| 570 | - | br.ult w32 0 %300 @guard#pass115 @guard#trap116; |
|
| 571 | - | @guard#pass111 |
|
| 572 | - | load w64 %297 %218 0; |
|
| 573 | - | add w64 %298 %297 2; |
|
| 574 | - | load w8 %299 %298 0; |
|
| 575 | - | br.ne w8 %299 239 @then109 @merge110; |
|
| 576 | - | @guard#trap112 |
|
| 577 | - | ebreak; |
|
| 578 | - | unreachable; |
|
| 579 | - | @then113 |
|
| 580 | - | ret 23; |
|
| 581 | - | @merge114 |
|
| 582 | - | mul w32 %309 4 2; |
|
| 583 | - | call w64 %310 $arenaAlloc(%3, %309, 4); |
|
| 584 | - | reserve %311 16 8; |
|
| 585 | - | store w64 %310 %311 0; |
|
| 586 | - | store w32 0 %311 8; |
|
| 587 | - | store w32 2 %311 12; |
|
| 588 | - | load w32 %314 %311 8; |
|
| 589 | - | load w32 %315 %311 12; |
|
| 590 | - | br.ult w32 %314 %315 @append.store117 @append.grow118; |
|
| 591 | - | @guard#pass115 |
|
| 592 | - | load w64 %301 %218 0; |
|
| 593 | - | load w8 %302 %301 0; |
|
| 594 | - | br.ne w8 %302 171 @then113 @merge114; |
|
| 595 | - | @guard#trap116 |
|
| 596 | - | ebreak; |
|
| 597 | - | unreachable; |
|
| 598 | - | @append.store117 |
|
| 599 | - | load w64 %329 %311 0; |
|
| 600 | - | mul w64 %330 %314 4; |
|
| 601 | - | add w64 %331 %329 %330; |
|
| 602 | - | store w32 42 %331 0; |
|
| 603 | - | add w32 %332 %314 1; |
|
| 604 | - | store w32 %332 %311 8; |
|
| 605 | - | blit %311 %311 16; |
|
| 606 | - | load w32 %335 %311 8; |
|
| 607 | - | br.eq w32 %335 1 @assert.ok123 @assert.fail122; |
|
| 608 | - | @append.grow118 |
|
| 609 | - | shl w32 %316 %315 1; |
|
| 610 | - | or w32 %317 %316 1; |
|
| 611 | - | load w64 %318 %5 0; |
|
| 612 | - | load w64 %319 %5 8; |
|
| 613 | - | mul w32 %320 %317 4; |
|
| 614 | - | call w64 %321 %318(%319, %320, 4); |
|
| 615 | - | load w64 %322 %311 0; |
|
| 616 | - | mul w32 %323 %314 4; |
|
| 617 | - | jmp @append119(0); |
|
| 618 | - | @append119(w32 %324) |
|
| 619 | - | br.ult w32 %324 %323 @append120 @append121; |
|
| 620 | - | @append120 |
|
| 621 | - | add w64 %325 %322 %324; |
|
| 622 | - | load w8 %326 %325 0; |
|
| 623 | - | add w64 %327 %321 %324; |
|
| 624 | - | store w8 %326 %327 0; |
|
| 625 | - | add w32 %328 %324 1; |
|
| 626 | - | jmp @append119(%328); |
|
| 627 | - | @append121 |
|
| 628 | - | store w64 %321 %311 0; |
|
| 629 | - | store w32 %317 %311 12; |
|
| 630 | - | jmp @append.store117; |
|
| 631 | - | @assert.fail122 |
|
| 632 | - | unreachable; |
|
| 633 | - | @assert.ok123 |
|
| 634 | - | load w32 %336 %311 8; |
|
| 635 | - | br.ult w32 0 %336 @guard#pass126 @guard#trap127; |
|
| 636 | - | @assert.fail124 |
|
| 637 | - | unreachable; |
|
| 638 | - | @assert.ok125 |
|
| 639 | - | load w32 %341 %311 8; |
|
| 640 | - | load w32 %342 %311 12; |
|
| 641 | - | br.ult w32 %341 %342 @append.store128 @append.grow129; |
|
| 642 | - | @guard#pass126 |
|
| 643 | - | load w64 %337 %311 0; |
|
| 644 | - | sload w32 %338 %337 0; |
|
| 645 | - | br.eq w32 %338 42 @assert.ok125 @assert.fail124; |
|
| 646 | - | @guard#trap127 |
|
| 647 | - | ebreak; |
|
| 648 | - | unreachable; |
|
| 649 | - | @append.store128 |
|
| 650 | - | load w64 %356 %311 0; |
|
| 651 | - | mul w64 %357 %341 4; |
|
| 652 | - | add w64 %358 %356 %357; |
|
| 653 | - | store w32 43 %358 0; |
|
| 654 | - | add w32 %359 %341 1; |
|
| 655 | - | store w32 %359 %311 8; |
|
| 656 | - | blit %311 %311 16; |
|
| 657 | - | load w32 %362 %311 8; |
|
| 658 | - | br.eq w32 %362 2 @assert.ok134 @assert.fail133; |
|
| 659 | - | @append.grow129 |
|
| 660 | - | shl w32 %343 %342 1; |
|
| 661 | - | or w32 %344 %343 1; |
|
| 662 | - | load w64 %345 %5 0; |
|
| 663 | - | load w64 %346 %5 8; |
|
| 664 | - | mul w32 %347 %344 4; |
|
| 665 | - | call w64 %348 %345(%346, %347, 4); |
|
| 666 | - | load w64 %349 %311 0; |
|
| 667 | - | mul w32 %350 %341 4; |
|
| 668 | - | jmp @append130(0); |
|
| 669 | - | @append130(w32 %351) |
|
| 670 | - | br.ult w32 %351 %350 @append131 @append132; |
|
| 671 | - | @append131 |
|
| 672 | - | add w64 %352 %349 %351; |
|
| 673 | - | load w8 %353 %352 0; |
|
| 674 | - | add w64 %354 %348 %351; |
|
| 675 | - | store w8 %353 %354 0; |
|
| 676 | - | add w32 %355 %351 1; |
|
| 677 | - | jmp @append130(%355); |
|
| 678 | - | @append132 |
|
| 679 | - | store w64 %348 %311 0; |
|
| 680 | - | store w32 %344 %311 12; |
|
| 681 | - | jmp @append.store128; |
|
| 682 | - | @assert.fail133 |
|
| 683 | - | unreachable; |
|
| 684 | - | @assert.ok134 |
|
| 685 | - | load w32 %363 %311 8; |
|
| 686 | - | br.ult w32 0 %363 @guard#pass135 @guard#trap136; |
|
| 687 | - | @guard#pass135 |
|
| 688 | - | load w64 %364 %311 0; |
|
| 689 | - | load w32 %367 %311 8; |
|
| 690 | - | load w32 %368 %311 12; |
|
| 691 | - | br.ult w32 %367 %368 @append.store137 @append.grow138; |
|
| 692 | - | @guard#trap136 |
|
| 693 | - | ebreak; |
|
| 694 | - | unreachable; |
|
| 695 | - | @append.store137 |
|
| 696 | - | load w64 %382 %311 0; |
|
| 697 | - | mul w64 %383 %367 4; |
|
| 698 | - | add w64 %384 %382 %383; |
|
| 699 | - | store w32 44 %384 0; |
|
| 700 | - | add w32 %385 %367 1; |
|
| 701 | - | store w32 %385 %311 8; |
|
| 702 | - | blit %311 %311 16; |
|
| 703 | - | load w32 %388 %311 8; |
|
| 704 | - | br.eq w32 %388 3 @assert.ok143 @assert.fail142; |
|
| 705 | - | @append.grow138 |
|
| 706 | - | shl w32 %369 %368 1; |
|
| 707 | - | or w32 %370 %369 1; |
|
| 708 | - | load w64 %371 %5 0; |
|
| 709 | - | load w64 %372 %5 8; |
|
| 710 | - | mul w32 %373 %370 4; |
|
| 711 | - | call w64 %374 %371(%372, %373, 4); |
|
| 712 | - | load w64 %375 %311 0; |
|
| 713 | - | mul w32 %376 %367 4; |
|
| 714 | - | jmp @append139(0); |
|
| 715 | - | @append139(w32 %377) |
|
| 716 | - | br.ult w32 %377 %376 @append140 @append141; |
|
| 717 | - | @append140 |
|
| 718 | - | add w64 %378 %375 %377; |
|
| 719 | - | load w8 %379 %378 0; |
|
| 720 | - | add w64 %380 %374 %377; |
|
| 721 | - | store w8 %379 %380 0; |
|
| 722 | - | add w32 %381 %377 1; |
|
| 723 | - | jmp @append139(%381); |
|
| 724 | - | @append141 |
|
| 725 | - | store w64 %374 %311 0; |
|
| 726 | - | store w32 %370 %311 12; |
|
| 727 | - | jmp @append.store137; |
|
| 728 | - | @assert.fail142 |
|
| 729 | - | unreachable; |
|
| 730 | - | @assert.ok143 |
|
| 731 | - | load w32 %389 %311 12; |
|
| 732 | - | br.eq w32 %389 5 @assert.ok145 @assert.fail144; |
|
| 733 | - | @assert.fail144 |
|
| 734 | - | unreachable; |
|
| 735 | - | @assert.ok145 |
|
| 736 | - | load w32 %390 %311 8; |
|
| 737 | - | br.ult w32 0 %390 @guard#pass146 @guard#trap147; |
|
| 738 | - | @guard#pass146 |
|
| 739 | - | load w64 %391 %311 0; |
|
| 740 | - | br.ne w64 %364 %391 @assert.ok149 @assert.fail148; |
|
| 741 | - | @guard#trap147 |
|
| 742 | - | ebreak; |
|
| 743 | - | unreachable; |
|
| 744 | - | @assert.fail148 |
|
| 745 | - | unreachable; |
|
| 746 | - | @assert.ok149 |
|
| 747 | - | load w32 %394 %311 8; |
|
| 748 | - | br.ult w32 0 %394 @guard#pass152 @guard#trap153; |
|
| 749 | - | @assert.fail150 |
|
| 750 | - | unreachable; |
|
| 751 | - | @assert.ok151 |
|
| 752 | - | load w32 %397 %311 8; |
|
| 753 | - | br.ult w32 1 %397 @guard#pass156 @guard#trap157; |
|
| 754 | - | @guard#pass152 |
|
| 755 | - | load w64 %395 %311 0; |
|
| 756 | - | sload w32 %396 %395 0; |
|
| 757 | - | br.eq w32 %396 42 @assert.ok151 @assert.fail150; |
|
| 758 | - | @guard#trap153 |
|
| 759 | - | ebreak; |
|
| 760 | - | unreachable; |
|
| 761 | - | @assert.fail154 |
|
| 762 | - | unreachable; |
|
| 763 | - | @assert.ok155 |
|
| 764 | - | load w32 %402 %311 8; |
|
| 765 | - | br.ult w32 2 %402 @guard#pass160 @guard#trap161; |
|
| 766 | - | @guard#pass156 |
|
| 767 | - | load w64 %398 %311 0; |
|
| 768 | - | mul w64 %399 1 4; |
|
| 769 | - | add w64 %400 %398 %399; |
|
| 770 | - | sload w32 %401 %400 0; |
|
| 771 | - | br.eq w32 %401 43 @assert.ok155 @assert.fail154; |
|
| 772 | - | @guard#trap157 |
|
| 773 | - | ebreak; |
|
| 774 | - | unreachable; |
|
| 775 | - | @assert.fail158 |
|
| 776 | - | unreachable; |
|
| 777 | - | @assert.ok159 |
|
| 778 | - | ret 0; |
|
| 779 | - | @guard#pass160 |
|
| 780 | - | load w64 %403 %311 0; |
|
| 781 | - | mul w64 %404 2 4; |
|
| 782 | - | add w64 %405 %403 %404; |
|
| 783 | - | sload w32 %406 %405 0; |
|
| 784 | - | br.eq w32 %406 44 @assert.ok159 @assert.fail158; |
|
| 785 | - | @guard#trap161 |
|
| 786 | - | ebreak; |
|
| 787 | - | unreachable; |
|
| 788 | - | } |
|
| 789 | - |
test/tests/slice.basic.rad
+0 -9
| 1 | 1 | /// Returns the length field from a slice header. |
|
| 2 | 2 | fn sliceLen(s: *[i32]) -> u32 { |
|
| 3 | 3 | return s.len; |
|
| 4 | 4 | } |
|
| 5 | 5 | ||
| 6 | - | /// Returns the capacity field from a slice header. |
|
| 7 | - | fn sliceCap(s: *[i32]) -> u32 { |
|
| 8 | - | return s.cap; |
|
| 9 | - | } |
|
| 10 | - | ||
| 11 | 6 | /// Returns the pointer field from a slice header. |
|
| 12 | 7 | fn slicePtr(s: *[i32]) -> *i32 { |
|
| 13 | 8 | return s.ptr; |
|
| 14 | 9 | } |
|
| 15 | 10 |
| 22 | 17 | /// Builds a slice header from a pointer and length. |
|
| 23 | 18 | fn sliceOf(ptr: *i32, len: u32) -> *[i32] { |
|
| 24 | 19 | return @sliceOf(ptr, len); |
|
| 25 | 20 | } |
|
| 26 | 21 | ||
| 27 | - | /// Builds a slice header from pointer, length, and capacity. |
|
| 28 | - | fn sliceOfWithCap(ptr: *i32, len: u32, cap: u32) -> *[i32] { |
|
| 29 | - | return @sliceOf(ptr, len, cap); |
|
| 30 | - | } |
test/tests/slice.basic.ril
+0 -21
| 2 | 2 | @entry0 |
|
| 3 | 3 | load w32 %1 %0 8; |
|
| 4 | 4 | ret %1; |
|
| 5 | 5 | } |
|
| 6 | 6 | ||
| 7 | - | fn w32 $sliceCap(w64 %0) { |
|
| 8 | - | @entry0 |
|
| 9 | - | load w32 %1 %0 12; |
|
| 10 | - | ret %1; |
|
| 11 | - | } |
|
| 12 | - | ||
| 13 | 7 | fn w64 $slicePtr(w64 %0) { |
|
| 14 | 8 | @entry0 |
|
| 15 | 9 | load w64 %1 %0 0; |
|
| 16 | 10 | ret %1; |
|
| 17 | 11 | } |
| 27 | 21 | fn w64 $sliceOf(w64 %0, w64 %1, w32 %2) { |
|
| 28 | 22 | @entry0 |
|
| 29 | 23 | reserve %3 16 8; |
|
| 30 | 24 | store w64 %1 %3 0; |
|
| 31 | 25 | store w32 %2 %3 8; |
|
| 32 | - | store w32 %2 %3 12; |
|
| 33 | 26 | blit %0 %3 16; |
|
| 34 | 27 | ret %0; |
|
| 35 | 28 | } |
|
| 36 | 29 | ||
| 37 | - | fn w64 $sliceOfWithCap(w64 %0, w64 %1, w32 %2, w32 %3) { |
|
| 38 | - | @entry0 |
|
| 39 | - | br.ult w32 %3 %2 @guard#trap1 @guard#pass2; |
|
| 40 | - | @guard#trap1 |
|
| 41 | - | ebreak; |
|
| 42 | - | unreachable; |
|
| 43 | - | @guard#pass2 |
|
| 44 | - | reserve %4 16 8; |
|
| 45 | - | store w64 %1 %4 0; |
|
| 46 | - | store w32 %2 %4 8; |
|
| 47 | - | store w32 %3 %4 12; |
|
| 48 | - | blit %0 %4 16; |
|
| 49 | - | ret %0; |
|
| 50 | - | } |
test/tests/slice.cap.rad
deleted
+0 -53
| 1 | - | //! returns: 0 |
|
| 2 | - | //! Test slice capacity field and @sliceOf builtin. |
|
| 3 | - | ||
| 4 | - | @default fn main() -> i32 { |
|
| 5 | - | // Test that regular slices have cap == len. |
|
| 6 | - | let mut arr: [i32; 4] = [10, 20, 30, 40]; |
|
| 7 | - | let s = &mut arr[..]; |
|
| 8 | - | ||
| 9 | - | if s.cap <> 4 { |
|
| 10 | - | return 1; |
|
| 11 | - | } |
|
| 12 | - | if s.len <> s.cap { |
|
| 13 | - | return 2; |
|
| 14 | - | } |
|
| 15 | - | ||
| 16 | - | // Test @sliceOf with explicit capacity. |
|
| 17 | - | let ptr = &mut arr[0]; |
|
| 18 | - | let s2 = @sliceOf(ptr, 2, 4); |
|
| 19 | - | ||
| 20 | - | if s2.len <> 2 { |
|
| 21 | - | return 3; |
|
| 22 | - | } |
|
| 23 | - | if s2.cap <> 4 { |
|
| 24 | - | return 4; |
|
| 25 | - | } |
|
| 26 | - | if s2[0] <> 10 { |
|
| 27 | - | return 5; |
|
| 28 | - | } |
|
| 29 | - | if s2[1] <> 20 { |
|
| 30 | - | return 6; |
|
| 31 | - | } |
|
| 32 | - | ||
| 33 | - | // Test @sliceOf with zero length. |
|
| 34 | - | let s3 = @sliceOf(ptr, 0, 4); |
|
| 35 | - | ||
| 36 | - | if s3.len <> 0 { |
|
| 37 | - | return 7; |
|
| 38 | - | } |
|
| 39 | - | if s3.cap <> 4 { |
|
| 40 | - | return 8; |
|
| 41 | - | } |
|
| 42 | - | ||
| 43 | - | // Test @sliceOf still works and has cap == len. |
|
| 44 | - | let s4 = @sliceOf(ptr, 3); |
|
| 45 | - | ||
| 46 | - | if s4.len <> 3 { |
|
| 47 | - | return 9; |
|
| 48 | - | } |
|
| 49 | - | if s4.cap <> 3 { |
|
| 50 | - | return 10; |
|
| 51 | - | } |
|
| 52 | - | return 0; |
|
| 53 | - | } |
test/tests/slice.delete.rad
deleted
+0 -61
| 1 | - | //! returns: 0 |
|
| 2 | - | //! Test slice .delete() method. |
|
| 3 | - | ||
| 4 | - | @default fn main() -> i32 { |
|
| 5 | - | let mut arr: [i32; 5] = [10, 20, 30, 40, 50]; |
|
| 6 | - | let mut s = &mut arr[..]; |
|
| 7 | - | ||
| 8 | - | // Delete middle element (index 2: value 30). |
|
| 9 | - | s.delete(2); |
|
| 10 | - | ||
| 11 | - | if s.len <> 4 { |
|
| 12 | - | return 1; |
|
| 13 | - | } |
|
| 14 | - | if s[0] <> 10 { |
|
| 15 | - | return 2; |
|
| 16 | - | } |
|
| 17 | - | if s[1] <> 20 { |
|
| 18 | - | return 3; |
|
| 19 | - | } |
|
| 20 | - | if s[2] <> 40 { |
|
| 21 | - | return 4; |
|
| 22 | - | } |
|
| 23 | - | if s[3] <> 50 { |
|
| 24 | - | return 5; |
|
| 25 | - | } |
|
| 26 | - | ||
| 27 | - | // Delete first element (index 0: value 10). |
|
| 28 | - | s.delete(0); |
|
| 29 | - | ||
| 30 | - | if s.len <> 3 { |
|
| 31 | - | return 6; |
|
| 32 | - | } |
|
| 33 | - | if s[0] <> 20 { |
|
| 34 | - | return 7; |
|
| 35 | - | } |
|
| 36 | - | if s[1] <> 40 { |
|
| 37 | - | return 8; |
|
| 38 | - | } |
|
| 39 | - | if s[2] <> 50 { |
|
| 40 | - | return 9; |
|
| 41 | - | } |
|
| 42 | - | ||
| 43 | - | // Delete last element (index 2: value 50). |
|
| 44 | - | s.delete(2); |
|
| 45 | - | ||
| 46 | - | if s.len <> 2 { |
|
| 47 | - | return 10; |
|
| 48 | - | } |
|
| 49 | - | if s[0] <> 20 { |
|
| 50 | - | return 11; |
|
| 51 | - | } |
|
| 52 | - | if s[1] <> 40 { |
|
| 53 | - | return 12; |
|
| 54 | - | } |
|
| 55 | - | ||
| 56 | - | // Cap should be unchanged. |
|
| 57 | - | if s.cap <> 5 { |
|
| 58 | - | return 13; |
|
| 59 | - | } |
|
| 60 | - | return 0; |
|
| 61 | - | } |
test/tests/slice.delete.ril
deleted
+0 -231
| 1 | - | fn w32 $main() { |
|
| 2 | - | @entry0 |
|
| 3 | - | reserve %0 20 4; |
|
| 4 | - | store w32 10 %0 0; |
|
| 5 | - | store w32 20 %0 4; |
|
| 6 | - | store w32 30 %0 8; |
|
| 7 | - | store w32 40 %0 12; |
|
| 8 | - | store w32 50 %0 16; |
|
| 9 | - | reserve %1 16 8; |
|
| 10 | - | store w64 %0 %1 0; |
|
| 11 | - | store w32 5 %1 8; |
|
| 12 | - | store w32 5 %1 12; |
|
| 13 | - | load w32 %2 %1 8; |
|
| 14 | - | br.ult w32 2 %2 @guard#pass1 @guard#trap2; |
|
| 15 | - | @guard#pass1 |
|
| 16 | - | load w64 %3 %1 0; |
|
| 17 | - | mul w64 %4 2 4; |
|
| 18 | - | add w64 %5 %3 %4; |
|
| 19 | - | add w64 %6 %5 4; |
|
| 20 | - | sub w32 %7 %2 2; |
|
| 21 | - | sub w32 %8 %7 1; |
|
| 22 | - | mul w32 %9 %8 4; |
|
| 23 | - | jmp @delete3(0); |
|
| 24 | - | @guard#trap2 |
|
| 25 | - | ebreak; |
|
| 26 | - | unreachable; |
|
| 27 | - | @delete3(w32 %10) |
|
| 28 | - | br.ult w32 %10 %9 @delete4 @delete5; |
|
| 29 | - | @delete4 |
|
| 30 | - | add w64 %11 %6 %10; |
|
| 31 | - | load w8 %12 %11 0; |
|
| 32 | - | add w64 %13 %5 %10; |
|
| 33 | - | store w8 %12 %13 0; |
|
| 34 | - | add w32 %14 %10 1; |
|
| 35 | - | jmp @delete3(%14); |
|
| 36 | - | @delete5 |
|
| 37 | - | sub w32 %15 %2 1; |
|
| 38 | - | store w32 %15 %1 8; |
|
| 39 | - | load w32 %17 %1 8; |
|
| 40 | - | br.ne w32 %17 4 @then6 @merge7; |
|
| 41 | - | @then6 |
|
| 42 | - | ret 1; |
|
| 43 | - | @merge7 |
|
| 44 | - | load w32 %18 %1 8; |
|
| 45 | - | br.ult w32 0 %18 @guard#pass10 @guard#trap11; |
|
| 46 | - | @then8 |
|
| 47 | - | ret 2; |
|
| 48 | - | @merge9 |
|
| 49 | - | load w32 %21 %1 8; |
|
| 50 | - | br.ult w32 1 %21 @guard#pass14 @guard#trap15; |
|
| 51 | - | @guard#pass10 |
|
| 52 | - | load w64 %19 %1 0; |
|
| 53 | - | sload w32 %20 %19 0; |
|
| 54 | - | br.ne w32 %20 10 @then8 @merge9; |
|
| 55 | - | @guard#trap11 |
|
| 56 | - | ebreak; |
|
| 57 | - | unreachable; |
|
| 58 | - | @then12 |
|
| 59 | - | ret 3; |
|
| 60 | - | @merge13 |
|
| 61 | - | load w32 %26 %1 8; |
|
| 62 | - | br.ult w32 2 %26 @guard#pass18 @guard#trap19; |
|
| 63 | - | @guard#pass14 |
|
| 64 | - | load w64 %22 %1 0; |
|
| 65 | - | mul w64 %23 1 4; |
|
| 66 | - | add w64 %24 %22 %23; |
|
| 67 | - | sload w32 %25 %24 0; |
|
| 68 | - | br.ne w32 %25 20 @then12 @merge13; |
|
| 69 | - | @guard#trap15 |
|
| 70 | - | ebreak; |
|
| 71 | - | unreachable; |
|
| 72 | - | @then16 |
|
| 73 | - | ret 4; |
|
| 74 | - | @merge17 |
|
| 75 | - | load w32 %31 %1 8; |
|
| 76 | - | br.ult w32 3 %31 @guard#pass22 @guard#trap23; |
|
| 77 | - | @guard#pass18 |
|
| 78 | - | load w64 %27 %1 0; |
|
| 79 | - | mul w64 %28 2 4; |
|
| 80 | - | add w64 %29 %27 %28; |
|
| 81 | - | sload w32 %30 %29 0; |
|
| 82 | - | br.ne w32 %30 40 @then16 @merge17; |
|
| 83 | - | @guard#trap19 |
|
| 84 | - | ebreak; |
|
| 85 | - | unreachable; |
|
| 86 | - | @then20 |
|
| 87 | - | ret 5; |
|
| 88 | - | @merge21 |
|
| 89 | - | load w32 %36 %1 8; |
|
| 90 | - | br.ult w32 0 %36 @guard#pass24 @guard#trap25; |
|
| 91 | - | @guard#pass22 |
|
| 92 | - | load w64 %32 %1 0; |
|
| 93 | - | mul w64 %33 3 4; |
|
| 94 | - | add w64 %34 %32 %33; |
|
| 95 | - | sload w32 %35 %34 0; |
|
| 96 | - | br.ne w32 %35 50 @then20 @merge21; |
|
| 97 | - | @guard#trap23 |
|
| 98 | - | ebreak; |
|
| 99 | - | unreachable; |
|
| 100 | - | @guard#pass24 |
|
| 101 | - | load w64 %37 %1 0; |
|
| 102 | - | add w64 %38 %37 4; |
|
| 103 | - | sub w32 %39 %36 0; |
|
| 104 | - | sub w32 %40 %39 1; |
|
| 105 | - | mul w32 %41 %40 4; |
|
| 106 | - | jmp @delete26(0); |
|
| 107 | - | @guard#trap25 |
|
| 108 | - | ebreak; |
|
| 109 | - | unreachable; |
|
| 110 | - | @delete26(w32 %42) |
|
| 111 | - | br.ult w32 %42 %41 @delete27 @delete28; |
|
| 112 | - | @delete27 |
|
| 113 | - | add w64 %43 %38 %42; |
|
| 114 | - | load w8 %44 %43 0; |
|
| 115 | - | add w64 %45 %37 %42; |
|
| 116 | - | store w8 %44 %45 0; |
|
| 117 | - | add w32 %46 %42 1; |
|
| 118 | - | jmp @delete26(%46); |
|
| 119 | - | @delete28 |
|
| 120 | - | sub w32 %47 %36 1; |
|
| 121 | - | store w32 %47 %1 8; |
|
| 122 | - | load w32 %49 %1 8; |
|
| 123 | - | br.ne w32 %49 3 @then29 @merge30; |
|
| 124 | - | @then29 |
|
| 125 | - | ret 6; |
|
| 126 | - | @merge30 |
|
| 127 | - | load w32 %50 %1 8; |
|
| 128 | - | br.ult w32 0 %50 @guard#pass33 @guard#trap34; |
|
| 129 | - | @then31 |
|
| 130 | - | ret 7; |
|
| 131 | - | @merge32 |
|
| 132 | - | load w32 %53 %1 8; |
|
| 133 | - | br.ult w32 1 %53 @guard#pass37 @guard#trap38; |
|
| 134 | - | @guard#pass33 |
|
| 135 | - | load w64 %51 %1 0; |
|
| 136 | - | sload w32 %52 %51 0; |
|
| 137 | - | br.ne w32 %52 20 @then31 @merge32; |
|
| 138 | - | @guard#trap34 |
|
| 139 | - | ebreak; |
|
| 140 | - | unreachable; |
|
| 141 | - | @then35 |
|
| 142 | - | ret 8; |
|
| 143 | - | @merge36 |
|
| 144 | - | load w32 %58 %1 8; |
|
| 145 | - | br.ult w32 2 %58 @guard#pass41 @guard#trap42; |
|
| 146 | - | @guard#pass37 |
|
| 147 | - | load w64 %54 %1 0; |
|
| 148 | - | mul w64 %55 1 4; |
|
| 149 | - | add w64 %56 %54 %55; |
|
| 150 | - | sload w32 %57 %56 0; |
|
| 151 | - | br.ne w32 %57 40 @then35 @merge36; |
|
| 152 | - | @guard#trap38 |
|
| 153 | - | ebreak; |
|
| 154 | - | unreachable; |
|
| 155 | - | @then39 |
|
| 156 | - | ret 9; |
|
| 157 | - | @merge40 |
|
| 158 | - | load w32 %63 %1 8; |
|
| 159 | - | br.ult w32 2 %63 @guard#pass43 @guard#trap44; |
|
| 160 | - | @guard#pass41 |
|
| 161 | - | load w64 %59 %1 0; |
|
| 162 | - | mul w64 %60 2 4; |
|
| 163 | - | add w64 %61 %59 %60; |
|
| 164 | - | sload w32 %62 %61 0; |
|
| 165 | - | br.ne w32 %62 50 @then39 @merge40; |
|
| 166 | - | @guard#trap42 |
|
| 167 | - | ebreak; |
|
| 168 | - | unreachable; |
|
| 169 | - | @guard#pass43 |
|
| 170 | - | load w64 %64 %1 0; |
|
| 171 | - | mul w64 %65 2 4; |
|
| 172 | - | add w64 %66 %64 %65; |
|
| 173 | - | add w64 %67 %66 4; |
|
| 174 | - | sub w32 %68 %63 2; |
|
| 175 | - | sub w32 %69 %68 1; |
|
| 176 | - | mul w32 %70 %69 4; |
|
| 177 | - | jmp @delete45(0); |
|
| 178 | - | @guard#trap44 |
|
| 179 | - | ebreak; |
|
| 180 | - | unreachable; |
|
| 181 | - | @delete45(w32 %71) |
|
| 182 | - | br.ult w32 %71 %70 @delete46 @delete47; |
|
| 183 | - | @delete46 |
|
| 184 | - | add w64 %72 %67 %71; |
|
| 185 | - | load w8 %73 %72 0; |
|
| 186 | - | add w64 %74 %66 %71; |
|
| 187 | - | store w8 %73 %74 0; |
|
| 188 | - | add w32 %75 %71 1; |
|
| 189 | - | jmp @delete45(%75); |
|
| 190 | - | @delete47 |
|
| 191 | - | sub w32 %76 %63 1; |
|
| 192 | - | store w32 %76 %1 8; |
|
| 193 | - | load w32 %78 %1 8; |
|
| 194 | - | br.ne w32 %78 2 @then48 @merge49; |
|
| 195 | - | @then48 |
|
| 196 | - | ret 10; |
|
| 197 | - | @merge49 |
|
| 198 | - | load w32 %79 %1 8; |
|
| 199 | - | br.ult w32 0 %79 @guard#pass52 @guard#trap53; |
|
| 200 | - | @then50 |
|
| 201 | - | ret 11; |
|
| 202 | - | @merge51 |
|
| 203 | - | load w32 %82 %1 8; |
|
| 204 | - | br.ult w32 1 %82 @guard#pass56 @guard#trap57; |
|
| 205 | - | @guard#pass52 |
|
| 206 | - | load w64 %80 %1 0; |
|
| 207 | - | sload w32 %81 %80 0; |
|
| 208 | - | br.ne w32 %81 20 @then50 @merge51; |
|
| 209 | - | @guard#trap53 |
|
| 210 | - | ebreak; |
|
| 211 | - | unreachable; |
|
| 212 | - | @then54 |
|
| 213 | - | ret 12; |
|
| 214 | - | @merge55 |
|
| 215 | - | load w32 %87 %1 12; |
|
| 216 | - | br.ne w32 %87 5 @then58 @merge59; |
|
| 217 | - | @guard#pass56 |
|
| 218 | - | load w64 %83 %1 0; |
|
| 219 | - | mul w64 %84 1 4; |
|
| 220 | - | add w64 %85 %83 %84; |
|
| 221 | - | sload w32 %86 %85 0; |
|
| 222 | - | br.ne w32 %86 40 @then54 @merge55; |
|
| 223 | - | @guard#trap57 |
|
| 224 | - | ebreak; |
|
| 225 | - | unreachable; |
|
| 226 | - | @then58 |
|
| 227 | - | ret 13; |
|
| 228 | - | @merge59 |
|
| 229 | - | ret 0; |
|
| 230 | - | } |
|
| 231 | - |
test/tests/slice.range.ril
+0 -5
| 21 | 21 | add w64 %7 %4 %6; |
|
| 22 | 22 | sub w32 %8 %3 %2; |
|
| 23 | 23 | reserve %9 16 8; |
|
| 24 | 24 | store w64 %7 %9 0; |
|
| 25 | 25 | store w32 %8 %9 8; |
|
| 26 | - | store w32 %8 %9 12; |
|
| 27 | 26 | blit %0 %9 16; |
|
| 28 | 27 | ret %0; |
|
| 29 | 28 | } |
|
| 30 | 29 | ||
| 31 | 30 | fn w64 $sliceRangeOpenEnd(w64 %0, w64 %1, w32 %2) { |
| 41 | 40 | add w64 %6 %3 %5; |
|
| 42 | 41 | sub w32 %7 %4 %2; |
|
| 43 | 42 | reserve %8 16 8; |
|
| 44 | 43 | store w64 %6 %8 0; |
|
| 45 | 44 | store w32 %7 %8 8; |
|
| 46 | - | store w32 %7 %8 12; |
|
| 47 | 45 | blit %0 %8 16; |
|
| 48 | 46 | ret %0; |
|
| 49 | 47 | } |
|
| 50 | 48 | ||
| 51 | 49 | fn w64 $sliceRangeOpenStart(w64 %0, w64 %1, w32 %2) { |
| 58 | 56 | unreachable; |
|
| 59 | 57 | @guard#pass2 |
|
| 60 | 58 | reserve %5 16 8; |
|
| 61 | 59 | store w64 %3 %5 0; |
|
| 62 | 60 | store w32 %2 %5 8; |
|
| 63 | - | store w32 %2 %5 12; |
|
| 64 | 61 | blit %0 %5 16; |
|
| 65 | 62 | ret %0; |
|
| 66 | 63 | } |
|
| 67 | 64 | ||
| 68 | 65 | fn w64 $sliceRangeFull(w64 %0, w64 %1) { |
| 70 | 67 | load w64 %2 %1 0; |
|
| 71 | 68 | load w32 %3 %1 8; |
|
| 72 | 69 | reserve %4 16 8; |
|
| 73 | 70 | store w64 %2 %4 0; |
|
| 74 | 71 | store w32 %3 %4 8; |
|
| 75 | - | store w32 %3 %4 12; |
|
| 76 | 72 | blit %0 %4 16; |
|
| 77 | 73 | ret %0; |
|
| 78 | 74 | } |
|
| 79 | 75 | ||
| 80 | 76 | fn w64 $sliceArray(w64 %0, w64 %1) { |
| 83 | 79 | add w64 %3 %1 %2; |
|
| 84 | 80 | sub w32 %4 3 1; |
|
| 85 | 81 | reserve %5 16 8; |
|
| 86 | 82 | store w64 %3 %5 0; |
|
| 87 | 83 | store w32 %4 %5 8; |
|
| 88 | - | store w32 %4 %5 12; |
|
| 89 | 84 | blit %0 %5 16; |
|
| 90 | 85 | ret %0; |
|
| 91 | 86 | } |
test/tests/slice.runtime.i32.ril
+0 -3
| 3 | 3 | reserve %2 4 4; |
|
| 4 | 4 | store w32 %1 %2 0; |
|
| 5 | 5 | reserve %3 16 8; |
|
| 6 | 6 | store w64 %2 %3 0; |
|
| 7 | 7 | store w32 1 %3 8; |
|
| 8 | - | store w32 1 %3 12; |
|
| 9 | 8 | blit %0 %3 16; |
|
| 10 | 9 | ret %0; |
|
| 11 | 10 | } |
|
| 12 | 11 | ||
| 13 | 12 | fn w64 $sliceWithVars(w64 %0, w32 %1, w32 %2) { |
| 16 | 15 | store w32 %1 %3 0; |
|
| 17 | 16 | store w32 %2 %3 4; |
|
| 18 | 17 | reserve %4 16 8; |
|
| 19 | 18 | store w64 %3 %4 0; |
|
| 20 | 19 | store w32 2 %4 8; |
|
| 21 | - | store w32 2 %4 12; |
|
| 22 | 20 | blit %0 %4 16; |
|
| 23 | 21 | ret %0; |
|
| 24 | 22 | } |
|
| 25 | 23 | ||
| 26 | 24 | fn w64 $sliceWithMixed(w64 %0, w32 %1) { |
| 30 | 28 | store w32 42 %2 4; |
|
| 31 | 29 | store w32 %1 %2 8; |
|
| 32 | 30 | reserve %3 16 8; |
|
| 33 | 31 | store w64 %2 %3 0; |
|
| 34 | 32 | store w32 3 %3 8; |
|
| 35 | - | store w32 3 %3 12; |
|
| 36 | 33 | blit %0 %3 16; |
|
| 37 | 34 | ret %0; |
|
| 38 | 35 | } |
test/tests/slice.runtime.literal.ril
+0 -2
| 3 | 3 | reserve %2 1 1; |
|
| 4 | 4 | store w8 %1 %2 0; |
|
| 5 | 5 | reserve %3 16 8; |
|
| 6 | 6 | store w64 %2 %3 0; |
|
| 7 | 7 | store w32 1 %3 8; |
|
| 8 | - | store w32 1 %3 12; |
|
| 9 | 8 | blit %0 %3 16; |
|
| 10 | 9 | ret %0; |
|
| 11 | 10 | } |
|
| 12 | 11 | ||
| 13 | 12 | fn w64 $sliceWithVars(w64 %0, w8 %1, w8 %2) { |
| 16 | 15 | store w8 %1 %3 0; |
|
| 17 | 16 | store w8 %2 %3 1; |
|
| 18 | 17 | reserve %4 16 8; |
|
| 19 | 18 | store w64 %3 %4 0; |
|
| 20 | 19 | store w32 2 %4 8; |
|
| 21 | - | store w32 2 %4 12; |
|
| 22 | 20 | blit %0 %4 16; |
|
| 23 | 21 | ret %0; |
|
| 24 | 22 | } |
test/tests/trait.supertrait.ril
+0 -3
| 129 | 129 | load w64 %8 %7 8; |
|
| 130 | 130 | copy %9 $main$literal$0; |
|
| 131 | 131 | reserve %10 16 8; |
|
| 132 | 132 | store w64 %9 %10 0; |
|
| 133 | 133 | store w32 3 %10 8; |
|
| 134 | - | store w32 3 %10 12; |
|
| 135 | 134 | call w32 %11 %8(%6, %10); |
|
| 136 | 135 | br.eq w32 %11 3 @assert.ok2 @assert.fail1; |
|
| 137 | 136 | @assert.fail1 |
|
| 138 | 137 | unreachable; |
|
| 139 | 138 | @assert.ok2 |
| 147 | 146 | load w64 %15 %5 8; |
|
| 148 | 147 | load w64 %16 %15 0; |
|
| 149 | 148 | reserve %17 16 8; |
|
| 150 | 149 | store w64 %13 %17 0; |
|
| 151 | 150 | store w32 8 %17 8; |
|
| 152 | - | store w32 8 %17 12; |
|
| 153 | 151 | call w32 %18 %16(%14, %17); |
|
| 154 | 152 | br.eq w32 %18 5 @assert.ok6 @assert.fail5; |
|
| 155 | 153 | @assert.fail5 |
|
| 156 | 154 | unreachable; |
|
| 157 | 155 | @assert.ok6 |
| 179 | 177 | @assert.fail13 |
|
| 180 | 178 | unreachable; |
|
| 181 | 179 | @assert.ok14 |
|
| 182 | 180 | ret 0; |
|
| 183 | 181 | } |
|
| 184 | - |
test/tests/vec.generic.rad
added
+43 -0
| 1 | + | //! returns: 0 |
|
| 2 | + | ||
| 3 | + | use std::lang::alloc; |
|
| 4 | + | use std::vec; |
|
| 5 | + | ||
| 6 | + | /// Fixed storage for vector growth allocations. |
|
| 7 | + | static VEC_ARENA_STORAGE: [u8; 64] = undefined; |
|
| 8 | + | ||
| 9 | + | /// Initial vector storage whose capacity is deliberately exceeded. |
|
| 10 | + | static VEC_INITIAL_STORAGE: [i32; 2] = undefined; |
|
| 11 | + | ||
| 12 | + | instantiate vec::init⟨i32⟩, |
|
| 13 | + | vec::append⟨i32⟩, |
|
| 14 | + | vec::view⟨i32⟩, |
|
| 15 | + | vec::remove⟨i32⟩; |
|
| 16 | + | ||
| 17 | + | /// Exercise public vector specializations from outside the standard package. |
|
| 18 | + | @default fn main() -> i32 { |
|
| 19 | + | let mut arena = alloc::new(&mut VEC_ARENA_STORAGE[..]); |
|
| 20 | + | let allocator = alloc::arenaAllocator(&mut arena); |
|
| 21 | + | let mut values: vec::Vec⟨i32⟩ = undefined; |
|
| 22 | + | vec::init⟨i32⟩(&mut values, &mut VEC_INITIAL_STORAGE[..]); |
|
| 23 | + | ||
| 24 | + | vec::append⟨i32⟩(&mut values, 10, allocator); |
|
| 25 | + | vec::append⟨i32⟩(&mut values, 20, allocator); |
|
| 26 | + | vec::append⟨i32⟩(&mut values, 30, allocator); |
|
| 27 | + | ||
| 28 | + | let initialized = vec::view⟨i32⟩(&values); |
|
| 29 | + | assert initialized.len == 3; |
|
| 30 | + | assert initialized[0] == 10; |
|
| 31 | + | assert initialized[1] == 20; |
|
| 32 | + | assert initialized[2] == 30; |
|
| 33 | + | ||
| 34 | + | let removed = vec::remove⟨i32⟩(&mut values, 1); |
|
| 35 | + | assert removed == 20; |
|
| 36 | + | ||
| 37 | + | let remaining = vec::view⟨i32⟩(&values); |
|
| 38 | + | assert remaining.len == 2; |
|
| 39 | + | assert remaining[0] == 10; |
|
| 40 | + | assert remaining[1] == 30; |
|
| 41 | + | ||
| 42 | + | return 0; |
|
| 43 | + | } |