blob ee4591ef (142280B) - Raw
1 const std = @import("std"); 2 const mem = std.mem; 3 const Allocator = std.mem.Allocator; 4 const Value = @import("value.zig").Value; 5 const Type = @import("type.zig").Type; 6 const TypedValue = @import("TypedValue.zig"); 7 const assert = std.debug.assert; 8 const zir = @import("zir.zig"); 9 const Module = @import("Module.zig"); 10 const ast = std.zig.ast; 11 const trace = @import("tracy.zig").trace; 12 const Scope = Module.Scope; 13 const InnerError = Module.InnerError; 14 15 pub const ResultLoc = union(enum) { 16 /// The expression is the right-hand side of assignment to `_`. Only the side-effects of the 17 /// expression should be generated. The result instruction from the expression must 18 /// be ignored. 19 discard, 20 /// The expression has an inferred type, and it will be evaluated as an rvalue. 21 none, 22 /// The expression must generate a pointer rather than a value. For example, the left hand side 23 /// of an assignment uses this kind of result location. 24 ref, 25 /// The expression will be coerced into this type, but it will be evaluated as an rvalue. 26 ty: *zir.Inst, 27 /// The expression must store its result into this typed pointer. The result instruction 28 /// from the expression must be ignored. 29 ptr: *zir.Inst, 30 /// The expression must store its result into this allocation, which has an inferred type. 31 /// The result instruction from the expression must be ignored. 32 inferred_ptr: *zir.Inst.Tag.alloc_inferred.Type(), 33 /// The expression must store its result into this pointer, which is a typed pointer that 34 /// has been bitcasted to whatever the expression's type is. 35 /// The result instruction from the expression must be ignored. 36 bitcasted_ptr: *zir.Inst.UnOp, 37 /// There is a pointer for the expression to store its result into, however, its type 38 /// is inferred based on peer type resolution for a `zir.Inst.Block`. 39 /// The result instruction from the expression must be ignored. 40 block_ptr: *Module.Scope.GenZIR, 41 }; 42 43 pub fn typeExpr(mod: *Module, scope: *Scope, type_node: *ast.Node) InnerError!*zir.Inst { 44 const type_src = scope.tree().token_locs[type_node.firstToken()].start; 45 const type_type = try addZIRInstConst(mod, scope, type_src, .{ 46 .ty = Type.initTag(.type), 47 .val = Value.initTag(.type_type), 48 }); 49 const type_rl: ResultLoc = .{ .ty = type_type }; 50 return expr(mod, scope, type_rl, type_node); 51 } 52 53 fn lvalExpr(mod: *Module, scope: *Scope, node: *ast.Node) InnerError!*zir.Inst { 54 switch (node.tag) { 55 .Root => unreachable, 56 .Use => unreachable, 57 .TestDecl => unreachable, 58 .DocComment => unreachable, 59 .VarDecl => unreachable, 60 .SwitchCase => unreachable, 61 .SwitchElse => unreachable, 62 .Else => unreachable, 63 .Payload => unreachable, 64 .PointerPayload => unreachable, 65 .PointerIndexPayload => unreachable, 66 .ErrorTag => unreachable, 67 .FieldInitializer => unreachable, 68 .ContainerField => unreachable, 69 70 .Assign, 71 .AssignBitAnd, 72 .AssignBitOr, 73 .AssignBitShiftLeft, 74 .AssignBitShiftRight, 75 .AssignBitXor, 76 .AssignDiv, 77 .AssignSub, 78 .AssignSubWrap, 79 .AssignMod, 80 .AssignAdd, 81 .AssignAddWrap, 82 .AssignMul, 83 .AssignMulWrap, 84 .Add, 85 .AddWrap, 86 .Sub, 87 .SubWrap, 88 .Mul, 89 .MulWrap, 90 .Div, 91 .Mod, 92 .BitAnd, 93 .BitOr, 94 .BitShiftLeft, 95 .BitShiftRight, 96 .BitXor, 97 .BangEqual, 98 .EqualEqual, 99 .GreaterThan, 100 .GreaterOrEqual, 101 .LessThan, 102 .LessOrEqual, 103 .ArrayCat, 104 .ArrayMult, 105 .BoolAnd, 106 .BoolOr, 107 .Asm, 108 .StringLiteral, 109 .IntegerLiteral, 110 .Call, 111 .Unreachable, 112 .Return, 113 .If, 114 .While, 115 .BoolNot, 116 .AddressOf, 117 .FloatLiteral, 118 .UndefinedLiteral, 119 .BoolLiteral, 120 .NullLiteral, 121 .OptionalType, 122 .Block, 123 .LabeledBlock, 124 .Break, 125 .PtrType, 126 .ArrayType, 127 .ArrayTypeSentinel, 128 .EnumLiteral, 129 .MultilineStringLiteral, 130 .CharLiteral, 131 .Defer, 132 .Catch, 133 .ErrorUnion, 134 .MergeErrorSets, 135 .Range, 136 .Await, 137 .BitNot, 138 .Negation, 139 .NegationWrap, 140 .Resume, 141 .Try, 142 .SliceType, 143 .Slice, 144 .ArrayInitializer, 145 .ArrayInitializerDot, 146 .StructInitializer, 147 .StructInitializerDot, 148 .Switch, 149 .For, 150 .Suspend, 151 .Continue, 152 .AnyType, 153 .ErrorType, 154 .FnProto, 155 .AnyFrameType, 156 .ErrorSetDecl, 157 .ContainerDecl, 158 .Comptime, 159 .Nosuspend, 160 => return mod.failNode(scope, node, "invalid left-hand side to assignment", .{}), 161 162 // @field can be assigned to 163 .BuiltinCall => { 164 const call = node.castTag(.BuiltinCall).?; 165 const tree = scope.tree(); 166 const builtin_name = tree.tokenSlice(call.builtin_token); 167 168 if (!mem.eql(u8, builtin_name, "@field")) { 169 return mod.failNode(scope, node, "invalid left-hand side to assignment", .{}); 170 } 171 }, 172 173 // can be assigned to 174 .UnwrapOptional, 175 .Deref, 176 .Period, 177 .ArrayAccess, 178 .Identifier, 179 .GroupedExpression, 180 .OrElse, 181 => {}, 182 } 183 return expr(mod, scope, .ref, node); 184 } 185 186 /// Turn Zig AST into untyped ZIR istructions. 187 /// When `rl` is discard, ptr, inferred_ptr, bitcasted_ptr, or inferred_ptr, the 188 /// result instruction can be used to inspect whether it is isNoReturn() but that is it, 189 /// it must otherwise not be used. 190 pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerError!*zir.Inst { 191 switch (node.tag) { 192 .Root => unreachable, // Top-level declaration. 193 .Use => unreachable, // Top-level declaration. 194 .TestDecl => unreachable, // Top-level declaration. 195 .DocComment => unreachable, // Top-level declaration. 196 .VarDecl => unreachable, // Handled in `blockExpr`. 197 .SwitchCase => unreachable, // Handled in `switchExpr`. 198 .SwitchElse => unreachable, // Handled in `switchExpr`. 199 .Range => unreachable, // Handled in `switchExpr`. 200 .Else => unreachable, // Handled explicitly the control flow expression functions. 201 .Payload => unreachable, // Handled explicitly. 202 .PointerPayload => unreachable, // Handled explicitly. 203 .PointerIndexPayload => unreachable, // Handled explicitly. 204 .ErrorTag => unreachable, // Handled explicitly. 205 .FieldInitializer => unreachable, // Handled explicitly. 206 .ContainerField => unreachable, // Handled explicitly. 207 208 .Assign => return rvalueVoid(mod, scope, rl, node, try assign(mod, scope, node.castTag(.Assign).?)), 209 .AssignBitAnd => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignBitAnd).?, .bit_and)), 210 .AssignBitOr => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignBitOr).?, .bit_or)), 211 .AssignBitShiftLeft => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignBitShiftLeft).?, .shl)), 212 .AssignBitShiftRight => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignBitShiftRight).?, .shr)), 213 .AssignBitXor => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignBitXor).?, .xor)), 214 .AssignDiv => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignDiv).?, .div)), 215 .AssignSub => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignSub).?, .sub)), 216 .AssignSubWrap => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignSubWrap).?, .subwrap)), 217 .AssignMod => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignMod).?, .mod_rem)), 218 .AssignAdd => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignAdd).?, .add)), 219 .AssignAddWrap => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignAddWrap).?, .addwrap)), 220 .AssignMul => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignMul).?, .mul)), 221 .AssignMulWrap => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignMulWrap).?, .mulwrap)), 222 223 .Add => return simpleBinOp(mod, scope, rl, node.castTag(.Add).?, .add), 224 .AddWrap => return simpleBinOp(mod, scope, rl, node.castTag(.AddWrap).?, .addwrap), 225 .Sub => return simpleBinOp(mod, scope, rl, node.castTag(.Sub).?, .sub), 226 .SubWrap => return simpleBinOp(mod, scope, rl, node.castTag(.SubWrap).?, .subwrap), 227 .Mul => return simpleBinOp(mod, scope, rl, node.castTag(.Mul).?, .mul), 228 .MulWrap => return simpleBinOp(mod, scope, rl, node.castTag(.MulWrap).?, .mulwrap), 229 .Div => return simpleBinOp(mod, scope, rl, node.castTag(.Div).?, .div), 230 .Mod => return simpleBinOp(mod, scope, rl, node.castTag(.Mod).?, .mod_rem), 231 .BitAnd => return simpleBinOp(mod, scope, rl, node.castTag(.BitAnd).?, .bit_and), 232 .BitOr => return simpleBinOp(mod, scope, rl, node.castTag(.BitOr).?, .bit_or), 233 .BitShiftLeft => return simpleBinOp(mod, scope, rl, node.castTag(.BitShiftLeft).?, .shl), 234 .BitShiftRight => return simpleBinOp(mod, scope, rl, node.castTag(.BitShiftRight).?, .shr), 235 .BitXor => return simpleBinOp(mod, scope, rl, node.castTag(.BitXor).?, .xor), 236 237 .BangEqual => return simpleBinOp(mod, scope, rl, node.castTag(.BangEqual).?, .cmp_neq), 238 .EqualEqual => return simpleBinOp(mod, scope, rl, node.castTag(.EqualEqual).?, .cmp_eq), 239 .GreaterThan => return simpleBinOp(mod, scope, rl, node.castTag(.GreaterThan).?, .cmp_gt), 240 .GreaterOrEqual => return simpleBinOp(mod, scope, rl, node.castTag(.GreaterOrEqual).?, .cmp_gte), 241 .LessThan => return simpleBinOp(mod, scope, rl, node.castTag(.LessThan).?, .cmp_lt), 242 .LessOrEqual => return simpleBinOp(mod, scope, rl, node.castTag(.LessOrEqual).?, .cmp_lte), 243 244 .ArrayCat => return simpleBinOp(mod, scope, rl, node.castTag(.ArrayCat).?, .array_cat), 245 .ArrayMult => return simpleBinOp(mod, scope, rl, node.castTag(.ArrayMult).?, .array_mul), 246 247 .BoolAnd => return boolBinOp(mod, scope, rl, node.castTag(.BoolAnd).?), 248 .BoolOr => return boolBinOp(mod, scope, rl, node.castTag(.BoolOr).?), 249 250 .BoolNot => return rvalue(mod, scope, rl, try boolNot(mod, scope, node.castTag(.BoolNot).?)), 251 .BitNot => return rvalue(mod, scope, rl, try bitNot(mod, scope, node.castTag(.BitNot).?)), 252 .Negation => return rvalue(mod, scope, rl, try negation(mod, scope, node.castTag(.Negation).?, .sub)), 253 .NegationWrap => return rvalue(mod, scope, rl, try negation(mod, scope, node.castTag(.NegationWrap).?, .subwrap)), 254 255 .Identifier => return try identifier(mod, scope, rl, node.castTag(.Identifier).?), 256 .Asm => return rvalue(mod, scope, rl, try assembly(mod, scope, node.castTag(.Asm).?)), 257 .StringLiteral => return rvalue(mod, scope, rl, try stringLiteral(mod, scope, node.castTag(.StringLiteral).?)), 258 .IntegerLiteral => return rvalue(mod, scope, rl, try integerLiteral(mod, scope, node.castTag(.IntegerLiteral).?)), 259 .BuiltinCall => return builtinCall(mod, scope, rl, node.castTag(.BuiltinCall).?), 260 .Call => return callExpr(mod, scope, rl, node.castTag(.Call).?), 261 .Unreachable => return unreach(mod, scope, node.castTag(.Unreachable).?), 262 .Return => return ret(mod, scope, node.castTag(.Return).?), 263 .If => return ifExpr(mod, scope, rl, node.castTag(.If).?), 264 .While => return whileExpr(mod, scope, rl, node.castTag(.While).?), 265 .Period => return field(mod, scope, rl, node.castTag(.Period).?), 266 .Deref => return rvalue(mod, scope, rl, try deref(mod, scope, node.castTag(.Deref).?)), 267 .AddressOf => return rvalue(mod, scope, rl, try addressOf(mod, scope, node.castTag(.AddressOf).?)), 268 .FloatLiteral => return rvalue(mod, scope, rl, try floatLiteral(mod, scope, node.castTag(.FloatLiteral).?)), 269 .UndefinedLiteral => return rvalue(mod, scope, rl, try undefLiteral(mod, scope, node.castTag(.UndefinedLiteral).?)), 270 .BoolLiteral => return rvalue(mod, scope, rl, try boolLiteral(mod, scope, node.castTag(.BoolLiteral).?)), 271 .NullLiteral => return rvalue(mod, scope, rl, try nullLiteral(mod, scope, node.castTag(.NullLiteral).?)), 272 .OptionalType => return rvalue(mod, scope, rl, try optionalType(mod, scope, node.castTag(.OptionalType).?)), 273 .UnwrapOptional => return unwrapOptional(mod, scope, rl, node.castTag(.UnwrapOptional).?), 274 .Block => return rvalueVoid(mod, scope, rl, node, try blockExpr(mod, scope, node.castTag(.Block).?)), 275 .LabeledBlock => return labeledBlockExpr(mod, scope, rl, node.castTag(.LabeledBlock).?, .block), 276 .Break => return rvalue(mod, scope, rl, try breakExpr(mod, scope, node.castTag(.Break).?)), 277 .Continue => return rvalue(mod, scope, rl, try continueExpr(mod, scope, node.castTag(.Continue).?)), 278 .PtrType => return rvalue(mod, scope, rl, try ptrType(mod, scope, node.castTag(.PtrType).?)), 279 .GroupedExpression => return expr(mod, scope, rl, node.castTag(.GroupedExpression).?.expr), 280 .ArrayType => return rvalue(mod, scope, rl, try arrayType(mod, scope, node.castTag(.ArrayType).?)), 281 .ArrayTypeSentinel => return rvalue(mod, scope, rl, try arrayTypeSentinel(mod, scope, node.castTag(.ArrayTypeSentinel).?)), 282 .EnumLiteral => return rvalue(mod, scope, rl, try enumLiteral(mod, scope, node.castTag(.EnumLiteral).?)), 283 .MultilineStringLiteral => return rvalue(mod, scope, rl, try multilineStrLiteral(mod, scope, node.castTag(.MultilineStringLiteral).?)), 284 .CharLiteral => return rvalue(mod, scope, rl, try charLiteral(mod, scope, node.castTag(.CharLiteral).?)), 285 .SliceType => return rvalue(mod, scope, rl, try sliceType(mod, scope, node.castTag(.SliceType).?)), 286 .ErrorUnion => return rvalue(mod, scope, rl, try typeInixOp(mod, scope, node.castTag(.ErrorUnion).?, .error_union_type)), 287 .MergeErrorSets => return rvalue(mod, scope, rl, try typeInixOp(mod, scope, node.castTag(.MergeErrorSets).?, .merge_error_sets)), 288 .AnyFrameType => return rvalue(mod, scope, rl, try anyFrameType(mod, scope, node.castTag(.AnyFrameType).?)), 289 .ErrorSetDecl => return rvalue(mod, scope, rl, try errorSetDecl(mod, scope, node.castTag(.ErrorSetDecl).?)), 290 .ErrorType => return rvalue(mod, scope, rl, try errorType(mod, scope, node.castTag(.ErrorType).?)), 291 .For => return forExpr(mod, scope, rl, node.castTag(.For).?), 292 .ArrayAccess => return arrayAccess(mod, scope, rl, node.castTag(.ArrayAccess).?), 293 .Slice => return rvalue(mod, scope, rl, try sliceExpr(mod, scope, node.castTag(.Slice).?)), 294 .Catch => return catchExpr(mod, scope, rl, node.castTag(.Catch).?), 295 .Comptime => return comptimeKeyword(mod, scope, rl, node.castTag(.Comptime).?), 296 .OrElse => return orelseExpr(mod, scope, rl, node.castTag(.OrElse).?), 297 .Switch => return switchExpr(mod, scope, rl, node.castTag(.Switch).?), 298 .ContainerDecl => return containerDecl(mod, scope, rl, node.castTag(.ContainerDecl).?), 299 300 .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}), 301 .Await => return mod.failNode(scope, node, "TODO implement astgen.expr for .Await", .{}), 302 .Resume => return mod.failNode(scope, node, "TODO implement astgen.expr for .Resume", .{}), 303 .Try => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}), 304 .ArrayInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayInitializer", .{}), 305 .ArrayInitializerDot => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayInitializerDot", .{}), 306 .StructInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .StructInitializer", .{}), 307 .StructInitializerDot => return mod.failNode(scope, node, "TODO implement astgen.expr for .StructInitializerDot", .{}), 308 .Suspend => return mod.failNode(scope, node, "TODO implement astgen.expr for .Suspend", .{}), 309 .AnyType => return mod.failNode(scope, node, "TODO implement astgen.expr for .AnyType", .{}), 310 .FnProto => return mod.failNode(scope, node, "TODO implement astgen.expr for .FnProto", .{}), 311 .Nosuspend => return mod.failNode(scope, node, "TODO implement astgen.expr for .Nosuspend", .{}), 312 } 313 } 314 315 fn comptimeKeyword(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Comptime) InnerError!*zir.Inst { 316 const tracy = trace(@src()); 317 defer tracy.end(); 318 319 return comptimeExpr(mod, scope, rl, node.expr); 320 } 321 322 pub fn comptimeExpr(mod: *Module, parent_scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerError!*zir.Inst { 323 const tree = parent_scope.tree(); 324 const src = tree.token_locs[node.firstToken()].start; 325 326 // Optimization for labeled blocks: don't need to have 2 layers of blocks, we can reuse the existing one. 327 if (node.castTag(.LabeledBlock)) |block_node| { 328 return labeledBlockExpr(mod, parent_scope, rl, block_node, .block_comptime); 329 } 330 331 // Make a scope to collect generated instructions in the sub-expression. 332 var block_scope: Scope.GenZIR = .{ 333 .parent = parent_scope, 334 .decl = parent_scope.ownerDecl().?, 335 .arena = parent_scope.arena(), 336 .instructions = .{}, 337 }; 338 defer block_scope.instructions.deinit(mod.gpa); 339 340 // No need to capture the result here because block_comptime_flat implies that the final 341 // instruction is the block's result value. 342 _ = try expr(mod, &block_scope.base, rl, node); 343 344 const block = try addZIRInstBlock(mod, parent_scope, src, .block_comptime_flat, .{ 345 .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items), 346 }); 347 348 return &block.base; 349 } 350 351 fn breakExpr(mod: *Module, parent_scope: *Scope, node: *ast.Node.ControlFlowExpression) InnerError!*zir.Inst { 352 if (true) { 353 @panic("TODO reimplement this"); 354 } 355 const tree = parent_scope.tree(); 356 const src = tree.token_locs[node.ltoken].start; 357 358 // Look for the label in the scope. 359 var scope = parent_scope; 360 while (true) { 361 switch (scope.tag) { 362 .gen_zir => { 363 const gen_zir = scope.cast(Scope.GenZIR).?; 364 365 const block_inst = blk: { 366 if (node.getLabel()) |break_label| { 367 if (gen_zir.label) |*label| { 368 if (try tokenIdentEql(mod, parent_scope, label.token, break_label)) { 369 label.used = true; 370 break :blk label.block_inst; 371 } 372 } 373 } else if (gen_zir.break_block) |inst| { 374 break :blk inst; 375 } 376 scope = gen_zir.parent; 377 continue; 378 }; 379 380 if (node.getRHS()) |rhs| { 381 // Most result location types can be forwarded directly; however 382 // if we need to write to a pointer which has an inferred type, 383 // proper type inference requires peer type resolution on the block's 384 // break operand expressions. 385 const branch_rl: ResultLoc = switch (gen_zir.break_result_loc) { 386 .discard, .none, .ty, .ptr, .ref => gen_zir.break_result_loc, 387 .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block_inst }, 388 }; 389 const operand = try expr(mod, parent_scope, branch_rl, rhs); 390 return try addZIRInst(mod, parent_scope, src, zir.Inst.Break, .{ 391 .block = block_inst, 392 .operand = operand, 393 }, .{}); 394 } else { 395 return try addZIRInst(mod, parent_scope, src, zir.Inst.BreakVoid, .{ 396 .block = block_inst, 397 }, .{}); 398 } 399 }, 400 .local_val => scope = scope.cast(Scope.LocalVal).?.parent, 401 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, 402 else => if (node.getLabel()) |break_label| { 403 const label_name = try mod.identifierTokenString(parent_scope, break_label); 404 return mod.failTok(parent_scope, break_label, "label not found: '{s}'", .{label_name}); 405 } else { 406 return mod.failTok(parent_scope, src, "break expression outside loop", .{}); 407 }, 408 } 409 } 410 } 411 412 fn continueExpr(mod: *Module, parent_scope: *Scope, node: *ast.Node.ControlFlowExpression) InnerError!*zir.Inst { 413 const tree = parent_scope.tree(); 414 const src = tree.token_locs[node.ltoken].start; 415 416 // Look for the label in the scope. 417 var scope = parent_scope; 418 while (true) { 419 switch (scope.tag) { 420 .gen_zir => { 421 const gen_zir = scope.cast(Scope.GenZIR).?; 422 const continue_block = gen_zir.continue_block orelse { 423 scope = gen_zir.parent; 424 continue; 425 }; 426 if (node.getLabel()) |break_label| blk: { 427 if (gen_zir.label) |*label| { 428 if (try tokenIdentEql(mod, parent_scope, label.token, break_label)) { 429 label.used = true; 430 break :blk; 431 } 432 } 433 // found continue but either it has a different label, or no label 434 scope = gen_zir.parent; 435 continue; 436 } 437 438 return addZIRInst(mod, parent_scope, src, zir.Inst.BreakVoid, .{ 439 .block = continue_block, 440 }, .{}); 441 }, 442 .local_val => scope = scope.cast(Scope.LocalVal).?.parent, 443 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, 444 else => if (node.getLabel()) |break_label| { 445 const label_name = try mod.identifierTokenString(parent_scope, break_label); 446 return mod.failTok(parent_scope, break_label, "label not found: '{s}'", .{label_name}); 447 } else { 448 return mod.failTok(parent_scope, src, "continue expression outside loop", .{}); 449 }, 450 } 451 } 452 } 453 454 pub fn blockExpr(mod: *Module, parent_scope: *Scope, block_node: *ast.Node.Block) InnerError!void { 455 const tracy = trace(@src()); 456 defer tracy.end(); 457 458 try blockExprStmts(mod, parent_scope, &block_node.base, block_node.statements()); 459 } 460 461 fn checkLabelRedefinition(mod: *Module, parent_scope: *Scope, label: ast.TokenIndex) !void { 462 // Look for the label in the scope. 463 var scope = parent_scope; 464 while (true) { 465 switch (scope.tag) { 466 .gen_zir => { 467 const gen_zir = scope.cast(Scope.GenZIR).?; 468 if (gen_zir.label) |prev_label| { 469 if (try tokenIdentEql(mod, parent_scope, label, prev_label.token)) { 470 const tree = parent_scope.tree(); 471 const label_src = tree.token_locs[label].start; 472 const prev_label_src = tree.token_locs[prev_label.token].start; 473 474 const label_name = try mod.identifierTokenString(parent_scope, label); 475 const msg = msg: { 476 const msg = try mod.errMsg( 477 parent_scope, 478 label_src, 479 "redefinition of label '{s}'", 480 .{label_name}, 481 ); 482 errdefer msg.destroy(mod.gpa); 483 try mod.errNote( 484 parent_scope, 485 prev_label_src, 486 msg, 487 "previous definition is here", 488 .{}, 489 ); 490 break :msg msg; 491 }; 492 return mod.failWithOwnedErrorMsg(parent_scope, msg); 493 } 494 } 495 scope = gen_zir.parent; 496 }, 497 .local_val => scope = scope.cast(Scope.LocalVal).?.parent, 498 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, 499 else => return, 500 } 501 } 502 } 503 504 fn labeledBlockExpr( 505 mod: *Module, 506 parent_scope: *Scope, 507 rl: ResultLoc, 508 block_node: *ast.Node.LabeledBlock, 509 zir_tag: zir.Inst.Tag, 510 ) InnerError!*zir.Inst { 511 const tracy = trace(@src()); 512 defer tracy.end(); 513 514 assert(zir_tag == .block or zir_tag == .block_comptime); 515 516 const tree = parent_scope.tree(); 517 const src = tree.token_locs[block_node.lbrace].start; 518 519 try checkLabelRedefinition(mod, parent_scope, block_node.label); 520 521 // Create the Block ZIR instruction so that we can put it into the GenZIR struct 522 // so that break statements can reference it. 523 const gen_zir = parent_scope.getGenZIR(); 524 const block_inst = try gen_zir.arena.create(zir.Inst.Block); 525 block_inst.* = .{ 526 .base = .{ 527 .tag = zir_tag, 528 .src = src, 529 }, 530 .positionals = .{ 531 .body = .{ .instructions = undefined }, 532 }, 533 .kw_args = .{}, 534 }; 535 536 var block_scope: Scope.GenZIR = .{ 537 .parent = parent_scope, 538 .decl = parent_scope.ownerDecl().?, 539 .arena = gen_zir.arena, 540 .instructions = .{}, 541 .break_result_loc = rl, 542 // TODO @as here is working around a stage1 miscompilation bug :( 543 .label = @as(?Scope.GenZIR.Label, Scope.GenZIR.Label{ 544 .token = block_node.label, 545 .block_inst = block_inst, 546 }), 547 }; 548 defer block_scope.instructions.deinit(mod.gpa); 549 550 try blockExprStmts(mod, &block_scope.base, &block_node.base, block_node.statements()); 551 if (!block_scope.label.?.used) { 552 return mod.fail(parent_scope, tree.token_locs[block_node.label].start, "unused block label", .{}); 553 } 554 555 block_inst.positionals.body.instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items); 556 try gen_zir.instructions.append(mod.gpa, &block_inst.base); 557 558 return &block_inst.base; 559 } 560 561 fn blockExprStmts(mod: *Module, parent_scope: *Scope, node: *ast.Node, statements: []*ast.Node) !void { 562 const tree = parent_scope.tree(); 563 564 var block_arena = std.heap.ArenaAllocator.init(mod.gpa); 565 defer block_arena.deinit(); 566 567 var scope = parent_scope; 568 for (statements) |statement| { 569 const src = tree.token_locs[statement.firstToken()].start; 570 _ = try addZIRNoOp(mod, scope, src, .dbg_stmt); 571 switch (statement.tag) { 572 .VarDecl => { 573 const var_decl_node = statement.castTag(.VarDecl).?; 574 scope = try varDecl(mod, scope, var_decl_node, &block_arena.allocator); 575 }, 576 .Assign => try assign(mod, scope, statement.castTag(.Assign).?), 577 .AssignBitAnd => try assignOp(mod, scope, statement.castTag(.AssignBitAnd).?, .bit_and), 578 .AssignBitOr => try assignOp(mod, scope, statement.castTag(.AssignBitOr).?, .bit_or), 579 .AssignBitShiftLeft => try assignOp(mod, scope, statement.castTag(.AssignBitShiftLeft).?, .shl), 580 .AssignBitShiftRight => try assignOp(mod, scope, statement.castTag(.AssignBitShiftRight).?, .shr), 581 .AssignBitXor => try assignOp(mod, scope, statement.castTag(.AssignBitXor).?, .xor), 582 .AssignDiv => try assignOp(mod, scope, statement.castTag(.AssignDiv).?, .div), 583 .AssignSub => try assignOp(mod, scope, statement.castTag(.AssignSub).?, .sub), 584 .AssignSubWrap => try assignOp(mod, scope, statement.castTag(.AssignSubWrap).?, .subwrap), 585 .AssignMod => try assignOp(mod, scope, statement.castTag(.AssignMod).?, .mod_rem), 586 .AssignAdd => try assignOp(mod, scope, statement.castTag(.AssignAdd).?, .add), 587 .AssignAddWrap => try assignOp(mod, scope, statement.castTag(.AssignAddWrap).?, .addwrap), 588 .AssignMul => try assignOp(mod, scope, statement.castTag(.AssignMul).?, .mul), 589 .AssignMulWrap => try assignOp(mod, scope, statement.castTag(.AssignMulWrap).?, .mulwrap), 590 591 else => { 592 const possibly_unused_result = try expr(mod, scope, .none, statement); 593 if (!possibly_unused_result.tag.isNoReturn()) { 594 _ = try addZIRUnOp(mod, scope, src, .ensure_result_used, possibly_unused_result); 595 } 596 }, 597 } 598 } 599 } 600 601 fn varDecl( 602 mod: *Module, 603 scope: *Scope, 604 node: *ast.Node.VarDecl, 605 block_arena: *Allocator, 606 ) InnerError!*Scope { 607 if (node.getComptimeToken()) |comptime_token| { 608 return mod.failTok(scope, comptime_token, "TODO implement comptime locals", .{}); 609 } 610 if (node.getAlignNode()) |align_node| { 611 return mod.failNode(scope, align_node, "TODO implement alignment on locals", .{}); 612 } 613 const tree = scope.tree(); 614 const name_src = tree.token_locs[node.name_token].start; 615 const ident_name = try mod.identifierTokenString(scope, node.name_token); 616 617 // Local variables shadowing detection, including function parameters. 618 { 619 var s = scope; 620 while (true) switch (s.tag) { 621 .local_val => { 622 const local_val = s.cast(Scope.LocalVal).?; 623 if (mem.eql(u8, local_val.name, ident_name)) { 624 const msg = msg: { 625 const msg = try mod.errMsg(scope, name_src, "redefinition of '{s}'", .{ 626 ident_name, 627 }); 628 errdefer msg.destroy(mod.gpa); 629 try mod.errNote(scope, local_val.inst.src, msg, "previous definition is here", .{}); 630 break :msg msg; 631 }; 632 return mod.failWithOwnedErrorMsg(scope, msg); 633 } 634 s = local_val.parent; 635 }, 636 .local_ptr => { 637 const local_ptr = s.cast(Scope.LocalPtr).?; 638 if (mem.eql(u8, local_ptr.name, ident_name)) { 639 const msg = msg: { 640 const msg = try mod.errMsg(scope, name_src, "redefinition of '{s}'", .{ 641 ident_name, 642 }); 643 errdefer msg.destroy(mod.gpa); 644 try mod.errNote(scope, local_ptr.ptr.src, msg, "previous definition is here", .{}); 645 break :msg msg; 646 }; 647 return mod.failWithOwnedErrorMsg(scope, msg); 648 } 649 s = local_ptr.parent; 650 }, 651 .gen_zir => s = s.cast(Scope.GenZIR).?.parent, 652 else => break, 653 }; 654 } 655 656 // Namespace vars shadowing detection 657 if (mod.lookupDeclName(scope, ident_name)) |_| { 658 // TODO add note for other definition 659 return mod.fail(scope, name_src, "redefinition of '{s}'", .{ident_name}); 660 } 661 const init_node = node.getInitNode() orelse 662 return mod.fail(scope, name_src, "variables must be initialized", .{}); 663 664 switch (tree.token_ids[node.mut_token]) { 665 .Keyword_const => { 666 // Depending on the type of AST the initialization expression is, we may need an lvalue 667 // or an rvalue as a result location. If it is an rvalue, we can use the instruction as 668 // the variable, no memory location needed. 669 if (!nodeMayNeedMemoryLocation(init_node, scope)) { 670 const result_loc: ResultLoc = if (node.getTypeNode()) |type_node| 671 .{ .ty = try typeExpr(mod, scope, type_node) } 672 else 673 .none; 674 const init_inst = try expr(mod, scope, result_loc, init_node); 675 const sub_scope = try block_arena.create(Scope.LocalVal); 676 sub_scope.* = .{ 677 .parent = scope, 678 .gen_zir = scope.getGenZIR(), 679 .name = ident_name, 680 .inst = init_inst, 681 }; 682 return &sub_scope.base; 683 } 684 685 var resolve_inferred_alloc: ?*zir.Inst = null; 686 const result_loc = r: { 687 if (node.getTypeNode()) |type_node| { 688 const type_inst = try typeExpr(mod, scope, type_node); 689 const alloc = try addZIRUnOp(mod, scope, name_src, .alloc, type_inst); 690 break :r ResultLoc{ .ptr = alloc }; 691 } else { 692 const alloc = try addZIRNoOpT(mod, scope, name_src, .alloc_inferred); 693 resolve_inferred_alloc = &alloc.base; 694 break :r ResultLoc{ .inferred_ptr = alloc }; 695 } 696 }; 697 const init_inst = try expr(mod, scope, result_loc, init_node); 698 if (resolve_inferred_alloc) |inst| { 699 _ = try addZIRUnOp(mod, scope, name_src, .resolve_inferred_alloc, inst); 700 } 701 const sub_scope = try block_arena.create(Scope.LocalVal); 702 sub_scope.* = .{ 703 .parent = scope, 704 .gen_zir = scope.getGenZIR(), 705 .name = ident_name, 706 .inst = init_inst, 707 }; 708 return &sub_scope.base; 709 }, 710 .Keyword_var => { 711 var resolve_inferred_alloc: ?*zir.Inst = null; 712 const var_data: struct { result_loc: ResultLoc, alloc: *zir.Inst } = if (node.getTypeNode()) |type_node| a: { 713 const type_inst = try typeExpr(mod, scope, type_node); 714 const alloc = try addZIRUnOp(mod, scope, name_src, .alloc_mut, type_inst); 715 break :a .{ .alloc = alloc, .result_loc = .{ .ptr = alloc } }; 716 } else a: { 717 const alloc = try addZIRNoOpT(mod, scope, name_src, .alloc_inferred_mut); 718 resolve_inferred_alloc = &alloc.base; 719 break :a .{ .alloc = &alloc.base, .result_loc = .{ .inferred_ptr = alloc } }; 720 }; 721 const init_inst = try expr(mod, scope, var_data.result_loc, init_node); 722 if (resolve_inferred_alloc) |inst| { 723 _ = try addZIRUnOp(mod, scope, name_src, .resolve_inferred_alloc, inst); 724 } 725 const sub_scope = try block_arena.create(Scope.LocalPtr); 726 sub_scope.* = .{ 727 .parent = scope, 728 .gen_zir = scope.getGenZIR(), 729 .name = ident_name, 730 .ptr = var_data.alloc, 731 }; 732 return &sub_scope.base; 733 }, 734 else => unreachable, 735 } 736 } 737 738 fn assign(mod: *Module, scope: *Scope, infix_node: *ast.Node.SimpleInfixOp) InnerError!void { 739 if (infix_node.lhs.castTag(.Identifier)) |ident| { 740 // This intentionally does not support @"_" syntax. 741 const ident_name = scope.tree().tokenSlice(ident.token); 742 if (mem.eql(u8, ident_name, "_")) { 743 _ = try expr(mod, scope, .discard, infix_node.rhs); 744 return; 745 } 746 } 747 const lvalue = try lvalExpr(mod, scope, infix_node.lhs); 748 _ = try expr(mod, scope, .{ .ptr = lvalue }, infix_node.rhs); 749 } 750 751 fn assignOp( 752 mod: *Module, 753 scope: *Scope, 754 infix_node: *ast.Node.SimpleInfixOp, 755 op_inst_tag: zir.Inst.Tag, 756 ) InnerError!void { 757 const lhs_ptr = try lvalExpr(mod, scope, infix_node.lhs); 758 const lhs = try addZIRUnOp(mod, scope, lhs_ptr.src, .deref, lhs_ptr); 759 const lhs_type = try addZIRUnOp(mod, scope, lhs_ptr.src, .typeof, lhs); 760 const rhs = try expr(mod, scope, .{ .ty = lhs_type }, infix_node.rhs); 761 762 const tree = scope.tree(); 763 const src = tree.token_locs[infix_node.op_token].start; 764 765 const result = try addZIRBinOp(mod, scope, src, op_inst_tag, lhs, rhs); 766 _ = try addZIRBinOp(mod, scope, src, .store, lhs_ptr, result); 767 } 768 769 fn boolNot(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst { 770 const tree = scope.tree(); 771 const src = tree.token_locs[node.op_token].start; 772 const bool_type = try addZIRInstConst(mod, scope, src, .{ 773 .ty = Type.initTag(.type), 774 .val = Value.initTag(.bool_type), 775 }); 776 const operand = try expr(mod, scope, .{ .ty = bool_type }, node.rhs); 777 return addZIRUnOp(mod, scope, src, .bool_not, operand); 778 } 779 780 fn bitNot(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst { 781 const tree = scope.tree(); 782 const src = tree.token_locs[node.op_token].start; 783 const operand = try expr(mod, scope, .none, node.rhs); 784 return addZIRUnOp(mod, scope, src, .bit_not, operand); 785 } 786 787 fn negation(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp, op_inst_tag: zir.Inst.Tag) InnerError!*zir.Inst { 788 const tree = scope.tree(); 789 const src = tree.token_locs[node.op_token].start; 790 791 const lhs = try addZIRInstConst(mod, scope, src, .{ 792 .ty = Type.initTag(.comptime_int), 793 .val = Value.initTag(.zero), 794 }); 795 const rhs = try expr(mod, scope, .none, node.rhs); 796 797 return addZIRBinOp(mod, scope, src, op_inst_tag, lhs, rhs); 798 } 799 800 fn addressOf(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst { 801 return expr(mod, scope, .ref, node.rhs); 802 } 803 804 fn optionalType(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst { 805 const tree = scope.tree(); 806 const src = tree.token_locs[node.op_token].start; 807 const operand = try typeExpr(mod, scope, node.rhs); 808 return addZIRUnOp(mod, scope, src, .optional_type, operand); 809 } 810 811 fn sliceType(mod: *Module, scope: *Scope, node: *ast.Node.SliceType) InnerError!*zir.Inst { 812 const tree = scope.tree(); 813 const src = tree.token_locs[node.op_token].start; 814 return ptrSliceType(mod, scope, src, &node.ptr_info, node.rhs, .Slice); 815 } 816 817 fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir.Inst { 818 const tree = scope.tree(); 819 const src = tree.token_locs[node.op_token].start; 820 return ptrSliceType(mod, scope, src, &node.ptr_info, node.rhs, switch (tree.token_ids[node.op_token]) { 821 .Asterisk, .AsteriskAsterisk => .One, 822 // TODO stage1 type inference bug 823 .LBracket => @as(std.builtin.TypeInfo.Pointer.Size, switch (tree.token_ids[node.op_token + 2]) { 824 .Identifier => .C, 825 else => .Many, 826 }), 827 else => unreachable, 828 }); 829 } 830 831 fn ptrSliceType(mod: *Module, scope: *Scope, src: usize, ptr_info: *ast.PtrInfo, rhs: *ast.Node, size: std.builtin.TypeInfo.Pointer.Size) InnerError!*zir.Inst { 832 const simple = ptr_info.allowzero_token == null and 833 ptr_info.align_info == null and 834 ptr_info.volatile_token == null and 835 ptr_info.sentinel == null; 836 837 if (simple) { 838 const child_type = try typeExpr(mod, scope, rhs); 839 const mutable = ptr_info.const_token == null; 840 // TODO stage1 type inference bug 841 const T = zir.Inst.Tag; 842 return addZIRUnOp(mod, scope, src, switch (size) { 843 .One => if (mutable) T.single_mut_ptr_type else T.single_const_ptr_type, 844 .Many => if (mutable) T.many_mut_ptr_type else T.many_const_ptr_type, 845 .C => if (mutable) T.c_mut_ptr_type else T.c_const_ptr_type, 846 .Slice => if (mutable) T.mut_slice_type else T.const_slice_type, 847 }, child_type); 848 } 849 850 var kw_args: std.meta.fieldInfo(zir.Inst.PtrType, .kw_args).field_type = .{}; 851 kw_args.size = size; 852 kw_args.@"allowzero" = ptr_info.allowzero_token != null; 853 if (ptr_info.align_info) |some| { 854 kw_args.@"align" = try expr(mod, scope, .none, some.node); 855 if (some.bit_range) |bit_range| { 856 kw_args.align_bit_start = try expr(mod, scope, .none, bit_range.start); 857 kw_args.align_bit_end = try expr(mod, scope, .none, bit_range.end); 858 } 859 } 860 kw_args.mutable = ptr_info.const_token == null; 861 kw_args.@"volatile" = ptr_info.volatile_token != null; 862 if (ptr_info.sentinel) |some| { 863 kw_args.sentinel = try expr(mod, scope, .none, some); 864 } 865 866 const child_type = try typeExpr(mod, scope, rhs); 867 if (kw_args.sentinel) |some| { 868 kw_args.sentinel = try addZIRBinOp(mod, scope, some.src, .as, child_type, some); 869 } 870 871 return addZIRInst(mod, scope, src, zir.Inst.PtrType, .{ .child_type = child_type }, kw_args); 872 } 873 874 fn arrayType(mod: *Module, scope: *Scope, node: *ast.Node.ArrayType) !*zir.Inst { 875 const tree = scope.tree(); 876 const src = tree.token_locs[node.op_token].start; 877 const usize_type = try addZIRInstConst(mod, scope, src, .{ 878 .ty = Type.initTag(.type), 879 .val = Value.initTag(.usize_type), 880 }); 881 882 // TODO check for [_]T 883 const len = try expr(mod, scope, .{ .ty = usize_type }, node.len_expr); 884 const elem_type = try typeExpr(mod, scope, node.rhs); 885 886 return addZIRBinOp(mod, scope, src, .array_type, len, elem_type); 887 } 888 889 fn arrayTypeSentinel(mod: *Module, scope: *Scope, node: *ast.Node.ArrayTypeSentinel) !*zir.Inst { 890 const tree = scope.tree(); 891 const src = tree.token_locs[node.op_token].start; 892 const usize_type = try addZIRInstConst(mod, scope, src, .{ 893 .ty = Type.initTag(.type), 894 .val = Value.initTag(.usize_type), 895 }); 896 897 // TODO check for [_]T 898 const len = try expr(mod, scope, .{ .ty = usize_type }, node.len_expr); 899 const sentinel_uncasted = try expr(mod, scope, .none, node.sentinel); 900 const elem_type = try typeExpr(mod, scope, node.rhs); 901 const sentinel = try addZIRBinOp(mod, scope, src, .as, elem_type, sentinel_uncasted); 902 903 return addZIRInst(mod, scope, src, zir.Inst.ArrayTypeSentinel, .{ 904 .len = len, 905 .sentinel = sentinel, 906 .elem_type = elem_type, 907 }, .{}); 908 } 909 910 fn anyFrameType(mod: *Module, scope: *Scope, node: *ast.Node.AnyFrameType) InnerError!*zir.Inst { 911 const tree = scope.tree(); 912 const src = tree.token_locs[node.anyframe_token].start; 913 if (node.result) |some| { 914 const return_type = try typeExpr(mod, scope, some.return_type); 915 return addZIRUnOp(mod, scope, src, .anyframe_type, return_type); 916 } else { 917 return addZIRInstConst(mod, scope, src, .{ 918 .ty = Type.initTag(.type), 919 .val = Value.initTag(.anyframe_type), 920 }); 921 } 922 } 923 924 fn typeInixOp(mod: *Module, scope: *Scope, node: *ast.Node.SimpleInfixOp, op_inst_tag: zir.Inst.Tag) InnerError!*zir.Inst { 925 const tree = scope.tree(); 926 const src = tree.token_locs[node.op_token].start; 927 const error_set = try typeExpr(mod, scope, node.lhs); 928 const payload = try typeExpr(mod, scope, node.rhs); 929 return addZIRBinOp(mod, scope, src, op_inst_tag, error_set, payload); 930 } 931 932 fn enumLiteral(mod: *Module, scope: *Scope, node: *ast.Node.EnumLiteral) !*zir.Inst { 933 const tree = scope.tree(); 934 const src = tree.token_locs[node.name].start; 935 const name = try mod.identifierTokenString(scope, node.name); 936 937 return addZIRInst(mod, scope, src, zir.Inst.EnumLiteral, .{ .name = name }, .{}); 938 } 939 940 fn unwrapOptional(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleSuffixOp) InnerError!*zir.Inst { 941 const tree = scope.tree(); 942 const src = tree.token_locs[node.rtoken].start; 943 944 const operand = try expr(mod, scope, rl, node.lhs); 945 const op: zir.Inst.Tag = switch (rl) { 946 .ref => .optional_payload_safe_ptr, 947 else => .optional_payload_safe, 948 }; 949 return addZIRUnOp(mod, scope, src, op, operand); 950 } 951 952 fn containerField( 953 mod: *Module, 954 scope: *Scope, 955 node: *ast.Node.ContainerField, 956 ) InnerError!*zir.Inst { 957 const tree = scope.tree(); 958 const src = tree.token_locs[node.firstToken()].start; 959 const name = try mod.identifierTokenString(scope, node.name_token); 960 961 if (node.comptime_token == null and node.value_expr == null and node.align_expr == null) { 962 if (node.type_expr) |some| { 963 const ty = try typeExpr(mod, scope, some); 964 return addZIRInst(mod, scope, src, zir.Inst.ContainerFieldTyped, .{ 965 .bytes = name, 966 .ty = ty, 967 }, .{}); 968 } else { 969 return addZIRInst(mod, scope, src, zir.Inst.ContainerFieldNamed, .{ 970 .bytes = name, 971 }, .{}); 972 } 973 } 974 975 const ty = if (node.type_expr) |some| try typeExpr(mod, scope, some) else null; 976 const alignment = if (node.align_expr) |some| try expr(mod, scope, .none, some) else null; 977 const init = if (node.value_expr) |some| try expr(mod, scope, .none, some) else null; 978 979 return addZIRInst(mod, scope, src, zir.Inst.ContainerField, .{ 980 .bytes = name, 981 }, .{ 982 .ty = ty, 983 .init = init, 984 .alignment = alignment, 985 .is_comptime = node.comptime_token != null, 986 }); 987 } 988 989 fn containerDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.ContainerDecl) InnerError!*zir.Inst { 990 const tree = scope.tree(); 991 const src = tree.token_locs[node.kind_token].start; 992 993 var gen_scope: Scope.GenZIR = .{ 994 .parent = scope, 995 .decl = scope.ownerDecl().?, 996 .arena = scope.arena(), 997 .instructions = .{}, 998 }; 999 defer gen_scope.instructions.deinit(mod.gpa); 1000 1001 var fields = std.ArrayList(*zir.Inst).init(mod.gpa); 1002 defer fields.deinit(); 1003 1004 for (node.fieldsAndDecls()) |fd| { 1005 if (fd.castTag(.ContainerField)) |f| { 1006 try fields.append(try containerField(mod, &gen_scope.base, f)); 1007 } 1008 } 1009 1010 var decl_arena = std.heap.ArenaAllocator.init(mod.gpa); 1011 errdefer decl_arena.deinit(); 1012 const arena = &decl_arena.allocator; 1013 1014 var layout: std.builtin.TypeInfo.ContainerLayout = .Auto; 1015 if (node.layout_token) |some| switch (tree.token_ids[some]) { 1016 .Keyword_extern => layout = .Extern, 1017 .Keyword_packed => layout = .Packed, 1018 else => unreachable, 1019 }; 1020 1021 const container_type = switch (tree.token_ids[node.kind_token]) { 1022 .Keyword_enum => blk: { 1023 const tag_type: ?*zir.Inst = switch (node.init_arg_expr) { 1024 .Type => |t| try typeExpr(mod, &gen_scope.base, t), 1025 .None => null, 1026 .Enum => unreachable, 1027 }; 1028 const inst = try addZIRInst(mod, &gen_scope.base, src, zir.Inst.EnumType, .{ 1029 .fields = try arena.dupe(*zir.Inst, fields.items), 1030 }, .{ 1031 .layout = layout, 1032 .tag_type = tag_type, 1033 }); 1034 const enum_type = try arena.create(Type.Payload.Enum); 1035 enum_type.* = .{ 1036 .analysis = .{ 1037 .queued = .{ 1038 .body = .{ .instructions = try arena.dupe(*zir.Inst, gen_scope.instructions.items) }, 1039 .inst = inst, 1040 }, 1041 }, 1042 .scope = .{ 1043 .file_scope = scope.getFileScope(), 1044 .ty = Type.initPayload(&enum_type.base), 1045 }, 1046 }; 1047 break :blk Type.initPayload(&enum_type.base); 1048 }, 1049 .Keyword_struct => blk: { 1050 assert(node.init_arg_expr == .None); 1051 const inst = try addZIRInst(mod, &gen_scope.base, src, zir.Inst.StructType, .{ 1052 .fields = try arena.dupe(*zir.Inst, fields.items), 1053 }, .{ 1054 .layout = layout, 1055 }); 1056 const struct_type = try arena.create(Type.Payload.Struct); 1057 struct_type.* = .{ 1058 .analysis = .{ 1059 .queued = .{ 1060 .body = .{ .instructions = try arena.dupe(*zir.Inst, gen_scope.instructions.items) }, 1061 .inst = inst, 1062 }, 1063 }, 1064 .scope = .{ 1065 .file_scope = scope.getFileScope(), 1066 .ty = Type.initPayload(&struct_type.base), 1067 }, 1068 }; 1069 break :blk Type.initPayload(&struct_type.base); 1070 }, 1071 .Keyword_union => blk: { 1072 const init_inst = switch (node.init_arg_expr) { 1073 .Enum => |e| if (e) |t| try typeExpr(mod, &gen_scope.base, t) else null, 1074 .None => null, 1075 .Type => |t| try typeExpr(mod, &gen_scope.base, t), 1076 }; 1077 const init_kind: zir.Inst.UnionType.InitKind = switch (node.init_arg_expr) { 1078 .Enum => .enum_type, 1079 .None => .none, 1080 .Type => .tag_type, 1081 }; 1082 const inst = try addZIRInst(mod, &gen_scope.base, src, zir.Inst.UnionType, .{ 1083 .fields = try arena.dupe(*zir.Inst, fields.items), 1084 }, .{ 1085 .layout = layout, 1086 .init_kind = init_kind, 1087 .init_inst = init_inst, 1088 }); 1089 const union_type = try arena.create(Type.Payload.Union); 1090 union_type.* = .{ 1091 .analysis = .{ 1092 .queued = .{ 1093 .body = .{ .instructions = try arena.dupe(*zir.Inst, gen_scope.instructions.items) }, 1094 .inst = inst, 1095 }, 1096 }, 1097 .scope = .{ 1098 .file_scope = scope.getFileScope(), 1099 .ty = Type.initPayload(&union_type.base), 1100 }, 1101 }; 1102 break :blk Type.initPayload(&union_type.base); 1103 }, 1104 .Keyword_opaque => blk: { 1105 if (fields.items.len > 0) { 1106 return mod.fail(scope, fields.items[0].src, "opaque types cannot have fields", .{}); 1107 } 1108 const opaque_type = try arena.create(Type.Payload.Opaque); 1109 opaque_type.* = .{ 1110 .scope = .{ 1111 .file_scope = scope.getFileScope(), 1112 .ty = Type.initPayload(&opaque_type.base), 1113 }, 1114 }; 1115 break :blk Type.initPayload(&opaque_type.base); 1116 }, 1117 else => unreachable, 1118 }; 1119 const val = try Value.Tag.ty.create(arena, container_type); 1120 const decl = try mod.createContainerDecl(scope, node.kind_token, &decl_arena, .{ 1121 .ty = Type.initTag(.type), 1122 .val = val, 1123 }); 1124 if (rl == .ref) { 1125 return addZIRInst(mod, scope, src, zir.Inst.DeclRef, .{ .decl = decl }, .{}); 1126 } else { 1127 return rvalue(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.DeclVal, .{ 1128 .decl = decl, 1129 }, .{})); 1130 } 1131 } 1132 1133 fn errorSetDecl(mod: *Module, scope: *Scope, node: *ast.Node.ErrorSetDecl) InnerError!*zir.Inst { 1134 const tree = scope.tree(); 1135 const src = tree.token_locs[node.error_token].start; 1136 const decls = node.decls(); 1137 const fields = try scope.arena().alloc([]const u8, decls.len); 1138 1139 for (decls) |decl, i| { 1140 const tag = decl.castTag(.ErrorTag).?; 1141 fields[i] = try mod.identifierTokenString(scope, tag.name_token); 1142 } 1143 1144 return addZIRInst(mod, scope, src, zir.Inst.ErrorSet, .{ .fields = fields }, .{}); 1145 } 1146 1147 fn errorType(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*zir.Inst { 1148 const tree = scope.tree(); 1149 const src = tree.token_locs[node.token].start; 1150 return addZIRInstConst(mod, scope, src, .{ 1151 .ty = Type.initTag(.type), 1152 .val = Value.initTag(.anyerror_type), 1153 }); 1154 } 1155 1156 fn catchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Catch) InnerError!*zir.Inst { 1157 switch (rl) { 1158 .ref => return orelseCatchExpr( 1159 mod, 1160 scope, 1161 rl, 1162 node.lhs, 1163 node.op_token, 1164 .is_err_ptr, 1165 .err_union_payload_unsafe_ptr, 1166 .err_union_code_ptr, 1167 node.rhs, 1168 node.payload, 1169 ), 1170 else => return orelseCatchExpr( 1171 mod, 1172 scope, 1173 rl, 1174 node.lhs, 1175 node.op_token, 1176 .is_err, 1177 .err_union_payload_unsafe, 1178 .err_union_code, 1179 node.rhs, 1180 node.payload, 1181 ), 1182 } 1183 } 1184 1185 fn orelseExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleInfixOp) InnerError!*zir.Inst { 1186 switch (rl) { 1187 .ref => return orelseCatchExpr( 1188 mod, 1189 scope, 1190 rl, 1191 node.lhs, 1192 node.op_token, 1193 .is_null_ptr, 1194 .optional_payload_unsafe_ptr, 1195 undefined, 1196 node.rhs, 1197 null, 1198 ), 1199 else => return orelseCatchExpr( 1200 mod, 1201 scope, 1202 rl, 1203 node.lhs, 1204 node.op_token, 1205 .is_null, 1206 .optional_payload_unsafe, 1207 undefined, 1208 node.rhs, 1209 null, 1210 ), 1211 } 1212 } 1213 1214 fn orelseCatchExpr( 1215 mod: *Module, 1216 scope: *Scope, 1217 rl: ResultLoc, 1218 lhs: *ast.Node, 1219 op_token: ast.TokenIndex, 1220 cond_op: zir.Inst.Tag, 1221 unwrap_op: zir.Inst.Tag, 1222 unwrap_code_op: zir.Inst.Tag, 1223 rhs: *ast.Node, 1224 payload_node: ?*ast.Node, 1225 ) InnerError!*zir.Inst { 1226 if (true) { 1227 @panic("TODO reimplement this"); 1228 } 1229 const tree = scope.tree(); 1230 const src = tree.token_locs[op_token].start; 1231 1232 var block_scope: Scope.GenZIR = .{ 1233 .parent = scope, 1234 .decl = scope.ownerDecl().?, 1235 .arena = scope.arena(), 1236 .instructions = .{}, 1237 }; 1238 defer block_scope.instructions.deinit(mod.gpa); 1239 1240 const block = try addZIRInstBlock(mod, scope, src, .block, .{ 1241 .instructions = undefined, // populated below 1242 }); 1243 1244 // Most result location types can be forwarded directly; however 1245 // if we need to write to a pointer which has an inferred type, 1246 // proper type inference requires peer type resolution on the if's 1247 // branches. 1248 const branch_rl: ResultLoc = switch (rl) { 1249 .discard, .none, .ty, .ptr, .ref => rl, 1250 .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block }, 1251 }; 1252 // This could be a pointer or value depending on the `rl` parameter. 1253 const operand = try expr(mod, &block_scope.base, branch_rl, lhs); 1254 const cond = try addZIRUnOp(mod, &block_scope.base, src, cond_op, operand); 1255 1256 const condbr = try addZIRInstSpecial(mod, &block_scope.base, src, zir.Inst.CondBr, .{ 1257 .condition = cond, 1258 .then_body = undefined, // populated below 1259 .else_body = undefined, // populated below 1260 }, .{}); 1261 1262 var then_scope: Scope.GenZIR = .{ 1263 .parent = &block_scope.base, 1264 .decl = block_scope.decl, 1265 .arena = block_scope.arena, 1266 .instructions = .{}, 1267 }; 1268 defer then_scope.instructions.deinit(mod.gpa); 1269 1270 var err_val_scope: Scope.LocalVal = undefined; 1271 const then_sub_scope = blk: { 1272 const payload = payload_node orelse 1273 break :blk &then_scope.base; 1274 1275 const err_name = tree.tokenSlice(payload.castTag(.Payload).?.error_symbol.firstToken()); 1276 if (mem.eql(u8, err_name, "_")) 1277 break :blk &then_scope.base; 1278 1279 err_val_scope = .{ 1280 .parent = &then_scope.base, 1281 .gen_zir = &then_scope, 1282 .name = err_name, 1283 .inst = try addZIRUnOp(mod, &then_scope.base, src, unwrap_code_op, operand), 1284 }; 1285 break :blk &err_val_scope.base; 1286 }; 1287 1288 _ = try addZIRInst(mod, &then_scope.base, src, zir.Inst.Break, .{ 1289 .block = block, 1290 .operand = try expr(mod, then_sub_scope, branch_rl, rhs), 1291 }, .{}); 1292 1293 var else_scope: Scope.GenZIR = .{ 1294 .parent = &block_scope.base, 1295 .decl = block_scope.decl, 1296 .arena = block_scope.arena, 1297 .instructions = .{}, 1298 }; 1299 defer else_scope.instructions.deinit(mod.gpa); 1300 1301 // This could be a pointer or value depending on `unwrap_op`. 1302 const unwrapped_payload = try addZIRUnOp(mod, &else_scope.base, src, unwrap_op, operand); 1303 _ = try addZIRInst(mod, &else_scope.base, src, zir.Inst.Break, .{ 1304 .block = block, 1305 .operand = unwrapped_payload, 1306 }, .{}); 1307 1308 // All branches have been generated, add the instructions to the block. 1309 block.positionals.body.instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items); 1310 1311 condbr.positionals.then_body = .{ .instructions = try then_scope.arena.dupe(*zir.Inst, then_scope.instructions.items) }; 1312 condbr.positionals.else_body = .{ .instructions = try else_scope.arena.dupe(*zir.Inst, else_scope.instructions.items) }; 1313 return &block.base; 1314 } 1315 1316 /// Return whether the identifier names of two tokens are equal. Resolves @"" 1317 /// tokens without allocating. 1318 /// OK in theory it could do it without allocating. This implementation 1319 /// allocates when the @"" form is used. 1320 fn tokenIdentEql(mod: *Module, scope: *Scope, token1: ast.TokenIndex, token2: ast.TokenIndex) !bool { 1321 const ident_name_1 = try mod.identifierTokenString(scope, token1); 1322 const ident_name_2 = try mod.identifierTokenString(scope, token2); 1323 return mem.eql(u8, ident_name_1, ident_name_2); 1324 } 1325 1326 pub fn field(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleInfixOp) InnerError!*zir.Inst { 1327 const tree = scope.tree(); 1328 const src = tree.token_locs[node.op_token].start; 1329 // TODO custom AST node for field access so that we don't have to go through a node cast here 1330 const field_name = try mod.identifierTokenString(scope, node.rhs.castTag(.Identifier).?.token); 1331 if (rl == .ref) { 1332 return addZirInstTag(mod, scope, src, .field_ptr, .{ 1333 .object = try expr(mod, scope, .ref, node.lhs), 1334 .field_name = field_name, 1335 }); 1336 } 1337 return rvalue(mod, scope, rl, try addZirInstTag(mod, scope, src, .field_val, .{ 1338 .object = try expr(mod, scope, .none, node.lhs), 1339 .field_name = field_name, 1340 })); 1341 } 1342 1343 fn namedField( 1344 mod: *Module, 1345 scope: *Scope, 1346 rl: ResultLoc, 1347 call: *ast.Node.BuiltinCall, 1348 ) InnerError!*zir.Inst { 1349 try ensureBuiltinParamCount(mod, scope, call, 2); 1350 1351 const tree = scope.tree(); 1352 const src = tree.token_locs[call.builtin_token].start; 1353 const params = call.params(); 1354 1355 const string_type = try addZIRInstConst(mod, scope, src, .{ 1356 .ty = Type.initTag(.type), 1357 .val = Value.initTag(.const_slice_u8_type), 1358 }); 1359 const string_rl: ResultLoc = .{ .ty = string_type }; 1360 1361 if (rl == .ref) { 1362 return addZirInstTag(mod, scope, src, .field_ptr_named, .{ 1363 .object = try expr(mod, scope, .ref, params[0]), 1364 .field_name = try comptimeExpr(mod, scope, string_rl, params[1]), 1365 }); 1366 } 1367 return rvalue(mod, scope, rl, try addZirInstTag(mod, scope, src, .field_val_named, .{ 1368 .object = try expr(mod, scope, .none, params[0]), 1369 .field_name = try comptimeExpr(mod, scope, string_rl, params[1]), 1370 })); 1371 } 1372 1373 fn arrayAccess(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.ArrayAccess) InnerError!*zir.Inst { 1374 const tree = scope.tree(); 1375 const src = tree.token_locs[node.rtoken].start; 1376 const usize_type = try addZIRInstConst(mod, scope, src, .{ 1377 .ty = Type.initTag(.type), 1378 .val = Value.initTag(.usize_type), 1379 }); 1380 const index_rl: ResultLoc = .{ .ty = usize_type }; 1381 1382 if (rl == .ref) { 1383 return addZirInstTag(mod, scope, src, .elem_ptr, .{ 1384 .array = try expr(mod, scope, .ref, node.lhs), 1385 .index = try expr(mod, scope, index_rl, node.index_expr), 1386 }); 1387 } 1388 return rvalue(mod, scope, rl, try addZirInstTag(mod, scope, src, .elem_val, .{ 1389 .array = try expr(mod, scope, .none, node.lhs), 1390 .index = try expr(mod, scope, index_rl, node.index_expr), 1391 })); 1392 } 1393 1394 fn sliceExpr(mod: *Module, scope: *Scope, node: *ast.Node.Slice) InnerError!*zir.Inst { 1395 const tree = scope.tree(); 1396 const src = tree.token_locs[node.rtoken].start; 1397 1398 const usize_type = try addZIRInstConst(mod, scope, src, .{ 1399 .ty = Type.initTag(.type), 1400 .val = Value.initTag(.usize_type), 1401 }); 1402 1403 const array_ptr = try expr(mod, scope, .ref, node.lhs); 1404 const start = try expr(mod, scope, .{ .ty = usize_type }, node.start); 1405 1406 if (node.end == null and node.sentinel == null) { 1407 return try addZIRBinOp(mod, scope, src, .slice_start, array_ptr, start); 1408 } 1409 1410 const end = if (node.end) |end| try expr(mod, scope, .{ .ty = usize_type }, end) else null; 1411 // we could get the child type here, but it is easier to just do it in semantic analysis. 1412 const sentinel = if (node.sentinel) |sentinel| try expr(mod, scope, .none, sentinel) else null; 1413 1414 return try addZIRInst( 1415 mod, 1416 scope, 1417 src, 1418 zir.Inst.Slice, 1419 .{ .array_ptr = array_ptr, .start = start }, 1420 .{ .end = end, .sentinel = sentinel }, 1421 ); 1422 } 1423 1424 fn deref(mod: *Module, scope: *Scope, node: *ast.Node.SimpleSuffixOp) InnerError!*zir.Inst { 1425 const tree = scope.tree(); 1426 const src = tree.token_locs[node.rtoken].start; 1427 const lhs = try expr(mod, scope, .none, node.lhs); 1428 return addZIRUnOp(mod, scope, src, .deref, lhs); 1429 } 1430 1431 fn simpleBinOp( 1432 mod: *Module, 1433 scope: *Scope, 1434 rl: ResultLoc, 1435 infix_node: *ast.Node.SimpleInfixOp, 1436 op_inst_tag: zir.Inst.Tag, 1437 ) InnerError!*zir.Inst { 1438 const tree = scope.tree(); 1439 const src = tree.token_locs[infix_node.op_token].start; 1440 1441 const lhs = try expr(mod, scope, .none, infix_node.lhs); 1442 const rhs = try expr(mod, scope, .none, infix_node.rhs); 1443 1444 const result = try addZIRBinOp(mod, scope, src, op_inst_tag, lhs, rhs); 1445 return rvalue(mod, scope, rl, result); 1446 } 1447 1448 fn boolBinOp( 1449 mod: *Module, 1450 scope: *Scope, 1451 rl: ResultLoc, 1452 infix_node: *ast.Node.SimpleInfixOp, 1453 ) InnerError!*zir.Inst { 1454 const tree = scope.tree(); 1455 const src = tree.token_locs[infix_node.op_token].start; 1456 const bool_type = try addZIRInstConst(mod, scope, src, .{ 1457 .ty = Type.initTag(.type), 1458 .val = Value.initTag(.bool_type), 1459 }); 1460 1461 var block_scope: Scope.GenZIR = .{ 1462 .parent = scope, 1463 .decl = scope.ownerDecl().?, 1464 .arena = scope.arena(), 1465 .instructions = .{}, 1466 }; 1467 defer block_scope.instructions.deinit(mod.gpa); 1468 1469 const lhs = try expr(mod, scope, .{ .ty = bool_type }, infix_node.lhs); 1470 const condbr = try addZIRInstSpecial(mod, &block_scope.base, src, zir.Inst.CondBr, .{ 1471 .condition = lhs, 1472 .then_body = undefined, // populated below 1473 .else_body = undefined, // populated below 1474 }, .{}); 1475 1476 const block = try addZIRInstBlock(mod, scope, src, .block, .{ 1477 .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items), 1478 }); 1479 1480 var rhs_scope: Scope.GenZIR = .{ 1481 .parent = scope, 1482 .decl = block_scope.decl, 1483 .arena = block_scope.arena, 1484 .instructions = .{}, 1485 }; 1486 defer rhs_scope.instructions.deinit(mod.gpa); 1487 1488 const rhs = try expr(mod, &rhs_scope.base, .{ .ty = bool_type }, infix_node.rhs); 1489 _ = try addZIRInst(mod, &rhs_scope.base, src, zir.Inst.Break, .{ 1490 .block = block, 1491 .operand = rhs, 1492 }, .{}); 1493 1494 var const_scope: Scope.GenZIR = .{ 1495 .parent = scope, 1496 .decl = block_scope.decl, 1497 .arena = block_scope.arena, 1498 .instructions = .{}, 1499 }; 1500 defer const_scope.instructions.deinit(mod.gpa); 1501 1502 const is_bool_and = infix_node.base.tag == .BoolAnd; 1503 _ = try addZIRInst(mod, &const_scope.base, src, zir.Inst.Break, .{ 1504 .block = block, 1505 .operand = try addZIRInstConst(mod, &const_scope.base, src, .{ 1506 .ty = Type.initTag(.bool), 1507 .val = if (is_bool_and) Value.initTag(.bool_false) else Value.initTag(.bool_true), 1508 }), 1509 }, .{}); 1510 1511 if (is_bool_and) { 1512 // if lhs // AND 1513 // break rhs 1514 // else 1515 // break false 1516 condbr.positionals.then_body = .{ .instructions = try rhs_scope.arena.dupe(*zir.Inst, rhs_scope.instructions.items) }; 1517 condbr.positionals.else_body = .{ .instructions = try const_scope.arena.dupe(*zir.Inst, const_scope.instructions.items) }; 1518 } else { 1519 // if lhs // OR 1520 // break true 1521 // else 1522 // break rhs 1523 condbr.positionals.then_body = .{ .instructions = try const_scope.arena.dupe(*zir.Inst, const_scope.instructions.items) }; 1524 condbr.positionals.else_body = .{ .instructions = try rhs_scope.arena.dupe(*zir.Inst, rhs_scope.instructions.items) }; 1525 } 1526 1527 return rvalue(mod, scope, rl, &block.base); 1528 } 1529 1530 const CondKind = union(enum) { 1531 bool, 1532 optional: ?*zir.Inst, 1533 err_union: ?*zir.Inst, 1534 1535 fn cond(self: *CondKind, mod: *Module, block_scope: *Scope.GenZIR, src: usize, cond_node: *ast.Node) !*zir.Inst { 1536 switch (self.*) { 1537 .bool => { 1538 const bool_type = try addZIRInstConst(mod, &block_scope.base, src, .{ 1539 .ty = Type.initTag(.type), 1540 .val = Value.initTag(.bool_type), 1541 }); 1542 return try expr(mod, &block_scope.base, .{ .ty = bool_type }, cond_node); 1543 }, 1544 .optional => { 1545 const cond_ptr = try expr(mod, &block_scope.base, .ref, cond_node); 1546 self.* = .{ .optional = cond_ptr }; 1547 const result = try addZIRUnOp(mod, &block_scope.base, src, .deref, cond_ptr); 1548 return try addZIRUnOp(mod, &block_scope.base, src, .is_non_null, result); 1549 }, 1550 .err_union => { 1551 const err_ptr = try expr(mod, &block_scope.base, .ref, cond_node); 1552 self.* = .{ .err_union = err_ptr }; 1553 const result = try addZIRUnOp(mod, &block_scope.base, src, .deref, err_ptr); 1554 return try addZIRUnOp(mod, &block_scope.base, src, .is_err, result); 1555 }, 1556 } 1557 } 1558 1559 fn thenSubScope(self: CondKind, mod: *Module, then_scope: *Scope.GenZIR, src: usize, payload_node: ?*ast.Node) !*Scope { 1560 if (self == .bool) return &then_scope.base; 1561 1562 const payload = payload_node.?.castTag(.PointerPayload) orelse { 1563 // condition is error union and payload is not explicitly ignored 1564 _ = try addZIRUnOp(mod, &then_scope.base, src, .ensure_err_payload_void, self.err_union.?); 1565 return &then_scope.base; 1566 }; 1567 const is_ptr = payload.ptr_token != null; 1568 const ident_node = payload.value_symbol.castTag(.Identifier).?; 1569 1570 // This intentionally does not support @"_" syntax. 1571 const ident_name = then_scope.base.tree().tokenSlice(ident_node.token); 1572 if (mem.eql(u8, ident_name, "_")) { 1573 if (is_ptr) 1574 return mod.failTok(&then_scope.base, payload.ptr_token.?, "pointer modifier invalid on discard", .{}); 1575 return &then_scope.base; 1576 } 1577 1578 return mod.failNode(&then_scope.base, payload.value_symbol, "TODO implement payload symbols", .{}); 1579 } 1580 1581 fn elseSubScope(self: CondKind, mod: *Module, else_scope: *Scope.GenZIR, src: usize, payload_node: ?*ast.Node) !*Scope { 1582 if (self != .err_union) return &else_scope.base; 1583 1584 const payload_ptr = try addZIRUnOp(mod, &else_scope.base, src, .err_union_payload_unsafe_ptr, self.err_union.?); 1585 1586 const payload = payload_node.?.castTag(.Payload).?; 1587 const ident_node = payload.error_symbol.castTag(.Identifier).?; 1588 1589 // This intentionally does not support @"_" syntax. 1590 const ident_name = else_scope.base.tree().tokenSlice(ident_node.token); 1591 if (mem.eql(u8, ident_name, "_")) { 1592 return &else_scope.base; 1593 } 1594 1595 return mod.failNode(&else_scope.base, payload.error_symbol, "TODO implement payload symbols", .{}); 1596 } 1597 }; 1598 1599 fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) InnerError!*zir.Inst { 1600 var cond_kind: CondKind = .bool; 1601 if (if_node.payload) |_| cond_kind = .{ .optional = null }; 1602 if (if_node.@"else") |else_node| { 1603 if (else_node.payload) |payload| { 1604 cond_kind = .{ .err_union = null }; 1605 } 1606 } 1607 const block_branch_count = 2; // then and else 1608 var block_scope: Scope.GenZIR = .{ 1609 .parent = scope, 1610 .decl = scope.ownerDecl().?, 1611 .arena = scope.arena(), 1612 .instructions = .{}, 1613 }; 1614 defer block_scope.instructions.deinit(mod.gpa); 1615 1616 const tree = scope.tree(); 1617 const if_src = tree.token_locs[if_node.if_token].start; 1618 const cond = try cond_kind.cond(mod, &block_scope, if_src, if_node.condition); 1619 1620 const condbr = try addZIRInstSpecial(mod, &block_scope.base, if_src, zir.Inst.CondBr, .{ 1621 .condition = cond, 1622 .then_body = undefined, // populated below 1623 .else_body = undefined, // populated below 1624 }, .{}); 1625 1626 const block = try addZIRInstBlock(mod, scope, if_src, .block, .{ 1627 .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items), 1628 }); 1629 1630 // Depending on whether the result location is a pointer or value, different 1631 // ZIR needs to be generated. In the former case we rely on storing to the 1632 // pointer to communicate the result, and use breakvoid; in the latter case 1633 // the block break instructions will have the result values. 1634 // One more complication: when the result location is a pointer, we detect 1635 // the scenario where the result location is not consumed. In this case 1636 // we emit ZIR for the block break instructions to have the result values, 1637 // and then rvalue() on that to pass the value to the result location. 1638 const branch_rl: ResultLoc = switch (rl) { 1639 .discard, .none, .ty, .ptr, .ref => rl, 1640 1641 .inferred_ptr => |ptr| blk: { 1642 block_scope.rl_ptr = &ptr.base; 1643 break :blk .{ .block_ptr = &block_scope }; 1644 }, 1645 1646 .bitcasted_ptr => |ptr| blk: { 1647 block_scope.rl_ptr = &ptr.base; 1648 break :blk .{ .block_ptr = &block_scope }; 1649 }, 1650 1651 .block_ptr => |parent_block_scope| blk: { 1652 block_scope.rl_ptr = parent_block_scope.rl_ptr.?; 1653 break :blk .{ .block_ptr = &block_scope }; 1654 }, 1655 }; 1656 1657 const then_src = tree.token_locs[if_node.body.lastToken()].start; 1658 var then_scope: Scope.GenZIR = .{ 1659 .parent = scope, 1660 .decl = block_scope.decl, 1661 .arena = block_scope.arena, 1662 .instructions = .{}, 1663 }; 1664 defer then_scope.instructions.deinit(mod.gpa); 1665 1666 // declare payload to the then_scope 1667 const then_sub_scope = try cond_kind.thenSubScope(mod, &then_scope, then_src, if_node.payload); 1668 1669 const then_result = try expr(mod, then_sub_scope, branch_rl, if_node.body); 1670 // We hold off on the break instructions as well as copying the then/else 1671 // instructions into place until we know whether to keep store_to_block_ptr 1672 // instructions or not. 1673 1674 var else_scope: Scope.GenZIR = .{ 1675 .parent = scope, 1676 .decl = block_scope.decl, 1677 .arena = block_scope.arena, 1678 .instructions = .{}, 1679 }; 1680 defer else_scope.instructions.deinit(mod.gpa); 1681 1682 var else_src: usize = undefined; 1683 var else_sub_scope: *Module.Scope = undefined; 1684 const else_result: ?*zir.Inst = if (if_node.@"else") |else_node| blk: { 1685 else_src = tree.token_locs[else_node.body.lastToken()].start; 1686 // declare payload to the then_scope 1687 else_sub_scope = try cond_kind.elseSubScope(mod, &else_scope, else_src, else_node.payload); 1688 1689 break :blk try expr(mod, else_sub_scope, branch_rl, else_node.body); 1690 } else blk: { 1691 else_src = tree.token_locs[if_node.lastToken()].start; 1692 else_sub_scope = &else_scope.base; 1693 block_scope.rvalue_rl_count += 1; 1694 break :blk null; 1695 }; 1696 1697 // We now have enough information to decide whether the result instruction should 1698 // be communicated via result location pointer or break instructions. 1699 const Strategy = enum { 1700 /// Both branches will use break_void; result location is used to communicate the 1701 /// result instruction. 1702 break_void, 1703 /// Use break statements to pass the block result value, and call rvalue() at 1704 /// the end depending on rl. Also elide the store_to_block_ptr instructions 1705 /// depending on rl. 1706 break_operand, 1707 }; 1708 var elide_store_to_block_ptr_instructions = false; 1709 const strategy: Strategy = switch (rl) { 1710 // In this branch there will not be any store_to_block_ptr instructions. 1711 .discard, .none, .ty, .ref => .break_operand, 1712 // The pointer got passed through to the sub-expressions, so we will use 1713 // break_void here. 1714 // In this branch there will not be any store_to_block_ptr instructions. 1715 .ptr => .break_void, 1716 .inferred_ptr, .bitcasted_ptr, .block_ptr => blk: { 1717 if (block_scope.rvalue_rl_count == 2) { 1718 // Neither prong of the if consumed the result location, so we can 1719 // use break instructions to create an rvalue. 1720 elide_store_to_block_ptr_instructions = true; 1721 break :blk Strategy.break_operand; 1722 } else { 1723 // Allow the store_to_block_ptr instructions to remain so that 1724 // semantic analysis can turn them into bitcasts. 1725 break :blk Strategy.break_void; 1726 } 1727 }, 1728 }; 1729 switch (strategy) { 1730 .break_void => { 1731 if (!then_result.tag.isNoReturn()) { 1732 _ = try addZirInstTag(mod, then_sub_scope, then_src, .break_void, .{ 1733 .block = block, 1734 }); 1735 } 1736 if (else_result) |inst| { 1737 if (!inst.tag.isNoReturn()) { 1738 _ = try addZirInstTag(mod, else_sub_scope, else_src, .break_void, .{ 1739 .block = block, 1740 }); 1741 } 1742 } else { 1743 _ = try addZirInstTag(mod, else_sub_scope, else_src, .break_void, .{ 1744 .block = block, 1745 }); 1746 } 1747 assert(!elide_store_to_block_ptr_instructions); 1748 try copyBodyNoEliding(&condbr.positionals.then_body, then_scope); 1749 try copyBodyNoEliding(&condbr.positionals.else_body, else_scope); 1750 return &block.base; 1751 }, 1752 .break_operand => { 1753 if (!then_result.tag.isNoReturn()) { 1754 _ = try addZirInstTag(mod, then_sub_scope, then_src, .@"break", .{ 1755 .block = block, 1756 .operand = then_result, 1757 }); 1758 } 1759 if (else_result) |inst| { 1760 if (!inst.tag.isNoReturn()) { 1761 _ = try addZirInstTag(mod, else_sub_scope, else_src, .@"break", .{ 1762 .block = block, 1763 .operand = inst, 1764 }); 1765 } 1766 } else { 1767 _ = try addZirInstTag(mod, else_sub_scope, else_src, .break_void, .{ 1768 .block = block, 1769 }); 1770 } 1771 if (elide_store_to_block_ptr_instructions) { 1772 try copyBodyWithElidedStoreBlockPtr(&condbr.positionals.then_body, then_scope); 1773 try copyBodyWithElidedStoreBlockPtr(&condbr.positionals.else_body, else_scope); 1774 } else { 1775 try copyBodyNoEliding(&condbr.positionals.then_body, then_scope); 1776 try copyBodyNoEliding(&condbr.positionals.else_body, else_scope); 1777 } 1778 switch (rl) { 1779 .ref => return &block.base, 1780 else => return rvalue(mod, scope, rl, &block.base), 1781 } 1782 }, 1783 } 1784 } 1785 1786 /// Expects to find exactly 1 .store_to_block_ptr instruction. 1787 fn copyBodyWithElidedStoreBlockPtr(body: *zir.Body, scope: Module.Scope.GenZIR) !void { 1788 body.* = .{ 1789 .instructions = try scope.arena.alloc(*zir.Inst, scope.instructions.items.len - 1), 1790 }; 1791 var dst_index: usize = 0; 1792 for (scope.instructions.items) |src_inst| { 1793 if (src_inst.tag != .store_to_block_ptr) { 1794 body.instructions[dst_index] = src_inst; 1795 dst_index += 1; 1796 } 1797 } 1798 assert(dst_index == body.instructions.len); 1799 } 1800 1801 fn copyBodyNoEliding(body: *zir.Body, scope: Module.Scope.GenZIR) !void { 1802 body.* = .{ 1803 .instructions = try scope.arena.dupe(*zir.Inst, scope.instructions.items), 1804 }; 1805 } 1806 1807 fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.While) InnerError!*zir.Inst { 1808 if (true) { 1809 @panic("TODO reimplement this"); 1810 } 1811 var cond_kind: CondKind = .bool; 1812 if (while_node.payload) |_| cond_kind = .{ .optional = null }; 1813 if (while_node.@"else") |else_node| { 1814 if (else_node.payload) |payload| { 1815 cond_kind = .{ .err_union = null }; 1816 } 1817 } 1818 1819 if (while_node.label) |label| { 1820 try checkLabelRedefinition(mod, scope, label); 1821 } 1822 1823 if (while_node.inline_token) |tok| 1824 return mod.failTok(scope, tok, "TODO inline while", .{}); 1825 1826 var expr_scope: Scope.GenZIR = .{ 1827 .parent = scope, 1828 .decl = scope.ownerDecl().?, 1829 .arena = scope.arena(), 1830 .instructions = .{}, 1831 }; 1832 defer expr_scope.instructions.deinit(mod.gpa); 1833 1834 var loop_scope: Scope.GenZIR = .{ 1835 .parent = &expr_scope.base, 1836 .decl = expr_scope.decl, 1837 .arena = expr_scope.arena, 1838 .instructions = .{}, 1839 .break_result_loc = rl, 1840 }; 1841 defer loop_scope.instructions.deinit(mod.gpa); 1842 1843 var continue_scope: Scope.GenZIR = .{ 1844 .parent = &loop_scope.base, 1845 .decl = loop_scope.decl, 1846 .arena = loop_scope.arena, 1847 .instructions = .{}, 1848 }; 1849 defer continue_scope.instructions.deinit(mod.gpa); 1850 1851 const tree = scope.tree(); 1852 const while_src = tree.token_locs[while_node.while_token].start; 1853 const void_type = try addZIRInstConst(mod, scope, while_src, .{ 1854 .ty = Type.initTag(.type), 1855 .val = Value.initTag(.void_type), 1856 }); 1857 const cond = try cond_kind.cond(mod, &continue_scope, while_src, while_node.condition); 1858 1859 const condbr = try addZIRInstSpecial(mod, &continue_scope.base, while_src, zir.Inst.CondBr, .{ 1860 .condition = cond, 1861 .then_body = undefined, // populated below 1862 .else_body = undefined, // populated below 1863 }, .{}); 1864 const cond_block = try addZIRInstBlock(mod, &loop_scope.base, while_src, .block, .{ 1865 .instructions = try loop_scope.arena.dupe(*zir.Inst, continue_scope.instructions.items), 1866 }); 1867 // TODO avoid emitting the continue expr when there 1868 // are no jumps to it. This happens when the last statement of a while body is noreturn 1869 // and there are no `continue` statements. 1870 // The "repeat" at the end of a loop body is implied. 1871 if (while_node.continue_expr) |cont_expr| { 1872 _ = try expr(mod, &loop_scope.base, .{ .ty = void_type }, cont_expr); 1873 } 1874 const loop = try addZIRInstLoop(mod, &expr_scope.base, while_src, .{ 1875 .instructions = try expr_scope.arena.dupe(*zir.Inst, loop_scope.instructions.items), 1876 }); 1877 const while_block = try addZIRInstBlock(mod, scope, while_src, .block, .{ 1878 .instructions = try expr_scope.arena.dupe(*zir.Inst, expr_scope.instructions.items), 1879 }); 1880 loop_scope.break_block = while_block; 1881 loop_scope.continue_block = cond_block; 1882 if (while_node.label) |some| { 1883 loop_scope.label = @as(?Scope.GenZIR.Label, Scope.GenZIR.Label{ 1884 .token = some, 1885 .block_inst = while_block, 1886 }); 1887 } 1888 1889 const then_src = tree.token_locs[while_node.body.lastToken()].start; 1890 var then_scope: Scope.GenZIR = .{ 1891 .parent = &continue_scope.base, 1892 .decl = continue_scope.decl, 1893 .arena = continue_scope.arena, 1894 .instructions = .{}, 1895 }; 1896 defer then_scope.instructions.deinit(mod.gpa); 1897 1898 // declare payload to the then_scope 1899 const then_sub_scope = try cond_kind.thenSubScope(mod, &then_scope, then_src, while_node.payload); 1900 1901 // Most result location types can be forwarded directly; however 1902 // if we need to write to a pointer which has an inferred type, 1903 // proper type inference requires peer type resolution on the while's 1904 // branches. 1905 const branch_rl: ResultLoc = switch (rl) { 1906 .discard, .none, .ty, .ptr, .ref => rl, 1907 .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = while_block }, 1908 }; 1909 1910 const then_result = try expr(mod, then_sub_scope, branch_rl, while_node.body); 1911 if (!then_result.tag.isNoReturn()) { 1912 _ = try addZIRInst(mod, then_sub_scope, then_src, zir.Inst.Break, .{ 1913 .block = cond_block, 1914 .operand = then_result, 1915 }, .{}); 1916 } 1917 condbr.positionals.then_body = .{ 1918 .instructions = try then_scope.arena.dupe(*zir.Inst, then_scope.instructions.items), 1919 }; 1920 1921 var else_scope: Scope.GenZIR = .{ 1922 .parent = &continue_scope.base, 1923 .decl = continue_scope.decl, 1924 .arena = continue_scope.arena, 1925 .instructions = .{}, 1926 }; 1927 defer else_scope.instructions.deinit(mod.gpa); 1928 1929 if (while_node.@"else") |else_node| { 1930 const else_src = tree.token_locs[else_node.body.lastToken()].start; 1931 // declare payload to the then_scope 1932 const else_sub_scope = try cond_kind.elseSubScope(mod, &else_scope, else_src, else_node.payload); 1933 1934 const else_result = try expr(mod, else_sub_scope, branch_rl, else_node.body); 1935 if (!else_result.tag.isNoReturn()) { 1936 _ = try addZIRInst(mod, else_sub_scope, else_src, zir.Inst.Break, .{ 1937 .block = while_block, 1938 .operand = else_result, 1939 }, .{}); 1940 } 1941 } else { 1942 const else_src = tree.token_locs[while_node.lastToken()].start; 1943 _ = try addZIRInst(mod, &else_scope.base, else_src, zir.Inst.BreakVoid, .{ 1944 .block = while_block, 1945 }, .{}); 1946 } 1947 condbr.positionals.else_body = .{ 1948 .instructions = try else_scope.arena.dupe(*zir.Inst, else_scope.instructions.items), 1949 }; 1950 if (loop_scope.label) |some| { 1951 if (!some.used) { 1952 return mod.fail(scope, tree.token_locs[some.token].start, "unused while label", .{}); 1953 } 1954 } 1955 return &while_block.base; 1956 } 1957 1958 fn forExpr( 1959 mod: *Module, 1960 scope: *Scope, 1961 rl: ResultLoc, 1962 for_node: *ast.Node.For, 1963 ) InnerError!*zir.Inst { 1964 if (true) { 1965 @panic("TODO reimplement this"); 1966 } 1967 if (for_node.label) |label| { 1968 try checkLabelRedefinition(mod, scope, label); 1969 } 1970 1971 if (for_node.inline_token) |tok| 1972 return mod.failTok(scope, tok, "TODO inline for", .{}); 1973 1974 var for_scope: Scope.GenZIR = .{ 1975 .parent = scope, 1976 .decl = scope.ownerDecl().?, 1977 .arena = scope.arena(), 1978 .instructions = .{}, 1979 }; 1980 defer for_scope.instructions.deinit(mod.gpa); 1981 1982 // setup variables and constants 1983 const tree = scope.tree(); 1984 const for_src = tree.token_locs[for_node.for_token].start; 1985 const index_ptr = blk: { 1986 const usize_type = try addZIRInstConst(mod, &for_scope.base, for_src, .{ 1987 .ty = Type.initTag(.type), 1988 .val = Value.initTag(.usize_type), 1989 }); 1990 const index_ptr = try addZIRUnOp(mod, &for_scope.base, for_src, .alloc, usize_type); 1991 // initialize to zero 1992 const zero = try addZIRInstConst(mod, &for_scope.base, for_src, .{ 1993 .ty = Type.initTag(.usize), 1994 .val = Value.initTag(.zero), 1995 }); 1996 _ = try addZIRBinOp(mod, &for_scope.base, for_src, .store, index_ptr, zero); 1997 break :blk index_ptr; 1998 }; 1999 const array_ptr = try expr(mod, &for_scope.base, .ref, for_node.array_expr); 2000 const cond_src = tree.token_locs[for_node.array_expr.firstToken()].start; 2001 const len = try addZIRUnOp(mod, &for_scope.base, cond_src, .indexable_ptr_len, array_ptr); 2002 2003 var loop_scope: Scope.GenZIR = .{ 2004 .parent = &for_scope.base, 2005 .decl = for_scope.decl, 2006 .arena = for_scope.arena, 2007 .instructions = .{}, 2008 .break_result_loc = rl, 2009 }; 2010 defer loop_scope.instructions.deinit(mod.gpa); 2011 2012 var cond_scope: Scope.GenZIR = .{ 2013 .parent = &loop_scope.base, 2014 .decl = loop_scope.decl, 2015 .arena = loop_scope.arena, 2016 .instructions = .{}, 2017 }; 2018 defer cond_scope.instructions.deinit(mod.gpa); 2019 2020 // check condition i < array_expr.len 2021 const index = try addZIRUnOp(mod, &cond_scope.base, cond_src, .deref, index_ptr); 2022 const cond = try addZIRBinOp(mod, &cond_scope.base, cond_src, .cmp_lt, index, len); 2023 2024 const condbr = try addZIRInstSpecial(mod, &cond_scope.base, for_src, zir.Inst.CondBr, .{ 2025 .condition = cond, 2026 .then_body = undefined, // populated below 2027 .else_body = undefined, // populated below 2028 }, .{}); 2029 const cond_block = try addZIRInstBlock(mod, &loop_scope.base, for_src, .block, .{ 2030 .instructions = try loop_scope.arena.dupe(*zir.Inst, cond_scope.instructions.items), 2031 }); 2032 2033 // increment index variable 2034 const one = try addZIRInstConst(mod, &loop_scope.base, for_src, .{ 2035 .ty = Type.initTag(.usize), 2036 .val = Value.initTag(.one), 2037 }); 2038 const index_2 = try addZIRUnOp(mod, &loop_scope.base, cond_src, .deref, index_ptr); 2039 const index_plus_one = try addZIRBinOp(mod, &loop_scope.base, for_src, .add, index_2, one); 2040 _ = try addZIRBinOp(mod, &loop_scope.base, for_src, .store, index_ptr, index_plus_one); 2041 2042 // looping stuff 2043 const loop = try addZIRInstLoop(mod, &for_scope.base, for_src, .{ 2044 .instructions = try for_scope.arena.dupe(*zir.Inst, loop_scope.instructions.items), 2045 }); 2046 const for_block = try addZIRInstBlock(mod, scope, for_src, .block, .{ 2047 .instructions = try for_scope.arena.dupe(*zir.Inst, for_scope.instructions.items), 2048 }); 2049 loop_scope.break_block = for_block; 2050 loop_scope.continue_block = cond_block; 2051 if (for_node.label) |some| { 2052 loop_scope.label = @as(?Scope.GenZIR.Label, Scope.GenZIR.Label{ 2053 .token = some, 2054 .block_inst = for_block, 2055 }); 2056 } 2057 2058 // while body 2059 const then_src = tree.token_locs[for_node.body.lastToken()].start; 2060 var then_scope: Scope.GenZIR = .{ 2061 .parent = &cond_scope.base, 2062 .decl = cond_scope.decl, 2063 .arena = cond_scope.arena, 2064 .instructions = .{}, 2065 }; 2066 defer then_scope.instructions.deinit(mod.gpa); 2067 2068 // Most result location types can be forwarded directly; however 2069 // if we need to write to a pointer which has an inferred type, 2070 // proper type inference requires peer type resolution on the while's 2071 // branches. 2072 const branch_rl: ResultLoc = switch (rl) { 2073 .discard, .none, .ty, .ptr, .ref => rl, 2074 .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = for_block }, 2075 }; 2076 2077 var index_scope: Scope.LocalPtr = undefined; 2078 const then_sub_scope = blk: { 2079 const payload = for_node.payload.castTag(.PointerIndexPayload).?; 2080 const is_ptr = payload.ptr_token != null; 2081 const value_name = tree.tokenSlice(payload.value_symbol.firstToken()); 2082 if (!mem.eql(u8, value_name, "_")) { 2083 return mod.failNode(&then_scope.base, payload.value_symbol, "TODO implement for value payload", .{}); 2084 } else if (is_ptr) { 2085 return mod.failTok(&then_scope.base, payload.ptr_token.?, "pointer modifier invalid on discard", .{}); 2086 } 2087 2088 const index_symbol_node = payload.index_symbol orelse 2089 break :blk &then_scope.base; 2090 2091 const index_name = tree.tokenSlice(index_symbol_node.firstToken()); 2092 if (mem.eql(u8, index_name, "_")) { 2093 break :blk &then_scope.base; 2094 } 2095 // TODO make this const without an extra copy? 2096 index_scope = .{ 2097 .parent = &then_scope.base, 2098 .gen_zir = &then_scope, 2099 .name = index_name, 2100 .ptr = index_ptr, 2101 }; 2102 break :blk &index_scope.base; 2103 }; 2104 2105 const then_result = try expr(mod, then_sub_scope, branch_rl, for_node.body); 2106 if (!then_result.tag.isNoReturn()) { 2107 _ = try addZIRInst(mod, then_sub_scope, then_src, zir.Inst.Break, .{ 2108 .block = cond_block, 2109 .operand = then_result, 2110 }, .{}); 2111 } 2112 condbr.positionals.then_body = .{ 2113 .instructions = try then_scope.arena.dupe(*zir.Inst, then_scope.instructions.items), 2114 }; 2115 2116 // else branch 2117 var else_scope: Scope.GenZIR = .{ 2118 .parent = &cond_scope.base, 2119 .decl = cond_scope.decl, 2120 .arena = cond_scope.arena, 2121 .instructions = .{}, 2122 }; 2123 defer else_scope.instructions.deinit(mod.gpa); 2124 2125 if (for_node.@"else") |else_node| { 2126 const else_src = tree.token_locs[else_node.body.lastToken()].start; 2127 const else_result = try expr(mod, &else_scope.base, branch_rl, else_node.body); 2128 if (!else_result.tag.isNoReturn()) { 2129 _ = try addZIRInst(mod, &else_scope.base, else_src, zir.Inst.Break, .{ 2130 .block = for_block, 2131 .operand = else_result, 2132 }, .{}); 2133 } 2134 } else { 2135 const else_src = tree.token_locs[for_node.lastToken()].start; 2136 _ = try addZIRInst(mod, &else_scope.base, else_src, zir.Inst.BreakVoid, .{ 2137 .block = for_block, 2138 }, .{}); 2139 } 2140 condbr.positionals.else_body = .{ 2141 .instructions = try else_scope.arena.dupe(*zir.Inst, else_scope.instructions.items), 2142 }; 2143 if (loop_scope.label) |some| { 2144 if (!some.used) { 2145 return mod.fail(scope, tree.token_locs[some.token].start, "unused for label", .{}); 2146 } 2147 } 2148 return &for_block.base; 2149 } 2150 2151 fn getRangeNode(node: *ast.Node) ?*ast.Node.SimpleInfixOp { 2152 var cur = node; 2153 while (true) { 2154 switch (cur.tag) { 2155 .Range => return @fieldParentPtr(ast.Node.SimpleInfixOp, "base", cur), 2156 .GroupedExpression => cur = @fieldParentPtr(ast.Node.GroupedExpression, "base", cur).expr, 2157 else => return null, 2158 } 2159 } 2160 } 2161 2162 fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node.Switch) InnerError!*zir.Inst { 2163 if (true) { 2164 @panic("TODO reimplement this"); 2165 } 2166 var block_scope: Scope.GenZIR = .{ 2167 .parent = scope, 2168 .decl = scope.ownerDecl().?, 2169 .arena = scope.arena(), 2170 .instructions = .{}, 2171 }; 2172 defer block_scope.instructions.deinit(mod.gpa); 2173 2174 const tree = scope.tree(); 2175 const switch_src = tree.token_locs[switch_node.switch_token].start; 2176 const target_ptr = try expr(mod, &block_scope.base, .ref, switch_node.expr); 2177 const target = try addZIRUnOp(mod, &block_scope.base, target_ptr.src, .deref, target_ptr); 2178 // Add the switch instruction here so that it comes before any range checks. 2179 const switch_inst = (try addZIRInst(mod, &block_scope.base, switch_src, zir.Inst.SwitchBr, .{ 2180 .target_ptr = target_ptr, 2181 .cases = undefined, // populated below 2182 .items = &[_]*zir.Inst{}, // populated below 2183 .else_body = undefined, // populated below 2184 }, .{})).castTag(.switchbr).?; 2185 2186 var items = std.ArrayList(*zir.Inst).init(mod.gpa); 2187 defer items.deinit(); 2188 var cases = std.ArrayList(zir.Inst.SwitchBr.Case).init(mod.gpa); 2189 defer cases.deinit(); 2190 2191 // Add comptime block containing all prong items first, 2192 const item_block = try addZIRInstBlock(mod, scope, switch_src, .block_comptime_flat, .{ 2193 .instructions = undefined, // populated below 2194 }); 2195 // then add block containing the switch. 2196 const block = try addZIRInstBlock(mod, scope, switch_src, .block, .{ 2197 .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items), 2198 }); 2199 2200 // Most result location types can be forwarded directly; however 2201 // if we need to write to a pointer which has an inferred type, 2202 // proper type inference requires peer type resolution on the switch case. 2203 const case_rl: ResultLoc = switch (rl) { 2204 .discard, .none, .ty, .ptr, .ref => rl, 2205 .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block }, 2206 }; 2207 2208 var item_scope: Scope.GenZIR = .{ 2209 .parent = scope, 2210 .decl = scope.ownerDecl().?, 2211 .arena = scope.arena(), 2212 .instructions = .{}, 2213 }; 2214 defer item_scope.instructions.deinit(mod.gpa); 2215 2216 var case_scope: Scope.GenZIR = .{ 2217 .parent = scope, 2218 .decl = block_scope.decl, 2219 .arena = block_scope.arena, 2220 .instructions = .{}, 2221 }; 2222 defer case_scope.instructions.deinit(mod.gpa); 2223 2224 var else_scope: Scope.GenZIR = .{ 2225 .parent = scope, 2226 .decl = block_scope.decl, 2227 .arena = block_scope.arena, 2228 .instructions = .{}, 2229 }; 2230 defer else_scope.instructions.deinit(mod.gpa); 2231 2232 // first we gather all the switch items and check else/'_' prongs 2233 var else_src: ?usize = null; 2234 var underscore_src: ?usize = null; 2235 var first_range: ?*zir.Inst = null; 2236 var special_case: ?*ast.Node.SwitchCase = null; 2237 for (switch_node.cases()) |uncasted_case| { 2238 const case = uncasted_case.castTag(.SwitchCase).?; 2239 const case_src = tree.token_locs[case.firstToken()].start; 2240 // reset without freeing to reduce allocations. 2241 case_scope.instructions.items.len = 0; 2242 assert(case.items_len != 0); 2243 2244 // Check for else/_ prong, those are handled last. 2245 if (case.items_len == 1 and case.items()[0].tag == .SwitchElse) { 2246 if (else_src) |src| { 2247 const msg = msg: { 2248 const msg = try mod.errMsg( 2249 scope, 2250 case_src, 2251 "multiple else prongs in switch expression", 2252 .{}, 2253 ); 2254 errdefer msg.destroy(mod.gpa); 2255 try mod.errNote(scope, src, msg, "previous else prong is here", .{}); 2256 break :msg msg; 2257 }; 2258 return mod.failWithOwnedErrorMsg(scope, msg); 2259 } 2260 else_src = case_src; 2261 special_case = case; 2262 continue; 2263 } else if (case.items_len == 1 and case.items()[0].tag == .Identifier and 2264 mem.eql(u8, tree.tokenSlice(case.items()[0].firstToken()), "_")) 2265 { 2266 if (underscore_src) |src| { 2267 const msg = msg: { 2268 const msg = try mod.errMsg( 2269 scope, 2270 case_src, 2271 "multiple '_' prongs in switch expression", 2272 .{}, 2273 ); 2274 errdefer msg.destroy(mod.gpa); 2275 try mod.errNote(scope, src, msg, "previous '_' prong is here", .{}); 2276 break :msg msg; 2277 }; 2278 return mod.failWithOwnedErrorMsg(scope, msg); 2279 } 2280 underscore_src = case_src; 2281 special_case = case; 2282 continue; 2283 } 2284 2285 if (else_src) |some_else| { 2286 if (underscore_src) |some_underscore| { 2287 const msg = msg: { 2288 const msg = try mod.errMsg( 2289 scope, 2290 switch_src, 2291 "else and '_' prong in switch expression", 2292 .{}, 2293 ); 2294 errdefer msg.destroy(mod.gpa); 2295 try mod.errNote(scope, some_else, msg, "else prong is here", .{}); 2296 try mod.errNote(scope, some_underscore, msg, "'_' prong is here", .{}); 2297 break :msg msg; 2298 }; 2299 return mod.failWithOwnedErrorMsg(scope, msg); 2300 } 2301 } 2302 2303 // If this is a simple one item prong then it is handled by the switchbr. 2304 if (case.items_len == 1 and getRangeNode(case.items()[0]) == null) { 2305 const item = try expr(mod, &item_scope.base, .none, case.items()[0]); 2306 try items.append(item); 2307 try switchCaseExpr(mod, &case_scope.base, case_rl, block, case); 2308 2309 try cases.append(.{ 2310 .item = item, 2311 .body = .{ .instructions = try scope.arena().dupe(*zir.Inst, case_scope.instructions.items) }, 2312 }); 2313 continue; 2314 } 2315 2316 // TODO if the case has few items and no ranges it might be better 2317 // to just handle them as switch prongs. 2318 2319 // Check if the target matches any of the items. 2320 // 1, 2, 3..6 will result in 2321 // target == 1 or target == 2 or (target >= 3 and target <= 6) 2322 var any_ok: ?*zir.Inst = null; 2323 for (case.items()) |item| { 2324 if (getRangeNode(item)) |range| { 2325 const start = try expr(mod, &item_scope.base, .none, range.lhs); 2326 const end = try expr(mod, &item_scope.base, .none, range.rhs); 2327 const range_src = tree.token_locs[range.op_token].start; 2328 const range_inst = try addZIRBinOp(mod, &item_scope.base, range_src, .switch_range, start, end); 2329 try items.append(range_inst); 2330 if (first_range == null) first_range = range_inst; 2331 2332 // target >= start and target <= end 2333 const range_start_ok = try addZIRBinOp(mod, &else_scope.base, range_src, .cmp_gte, target, start); 2334 const range_end_ok = try addZIRBinOp(mod, &else_scope.base, range_src, .cmp_lte, target, end); 2335 const range_ok = try addZIRBinOp(mod, &else_scope.base, range_src, .bool_and, range_start_ok, range_end_ok); 2336 2337 if (any_ok) |some| { 2338 any_ok = try addZIRBinOp(mod, &else_scope.base, range_src, .bool_or, some, range_ok); 2339 } else { 2340 any_ok = range_ok; 2341 } 2342 continue; 2343 } 2344 2345 const item_inst = try expr(mod, &item_scope.base, .none, item); 2346 try items.append(item_inst); 2347 const cpm_ok = try addZIRBinOp(mod, &else_scope.base, item_inst.src, .cmp_eq, target, item_inst); 2348 2349 if (any_ok) |some| { 2350 any_ok = try addZIRBinOp(mod, &else_scope.base, item_inst.src, .bool_or, some, cpm_ok); 2351 } else { 2352 any_ok = cpm_ok; 2353 } 2354 } 2355 2356 const condbr = try addZIRInstSpecial(mod, &case_scope.base, case_src, zir.Inst.CondBr, .{ 2357 .condition = any_ok.?, 2358 .then_body = undefined, // populated below 2359 .else_body = undefined, // populated below 2360 }, .{}); 2361 const cond_block = try addZIRInstBlock(mod, &else_scope.base, case_src, .block, .{ 2362 .instructions = try scope.arena().dupe(*zir.Inst, case_scope.instructions.items), 2363 }); 2364 2365 // reset cond_scope for then_body 2366 case_scope.instructions.items.len = 0; 2367 try switchCaseExpr(mod, &case_scope.base, case_rl, block, case); 2368 condbr.positionals.then_body = .{ 2369 .instructions = try scope.arena().dupe(*zir.Inst, case_scope.instructions.items), 2370 }; 2371 2372 // reset cond_scope for else_body 2373 case_scope.instructions.items.len = 0; 2374 _ = try addZIRInst(mod, &case_scope.base, case_src, zir.Inst.BreakVoid, .{ 2375 .block = cond_block, 2376 }, .{}); 2377 condbr.positionals.else_body = .{ 2378 .instructions = try scope.arena().dupe(*zir.Inst, case_scope.instructions.items), 2379 }; 2380 } 2381 2382 // Generate else block or a break last to finish the block. 2383 if (special_case) |case| { 2384 try switchCaseExpr(mod, &else_scope.base, case_rl, block, case); 2385 } else { 2386 // Not handling all possible cases is a compile error. 2387 _ = try addZIRNoOp(mod, &else_scope.base, switch_src, .unreachable_unsafe); 2388 } 2389 2390 // All items have been generated, add the instructions to the comptime block. 2391 item_block.positionals.body = .{ 2392 .instructions = try block_scope.arena.dupe(*zir.Inst, item_scope.instructions.items), 2393 }; 2394 2395 // Actually populate switch instruction values. 2396 if (else_src != null) switch_inst.kw_args.special_prong = .@"else"; 2397 if (underscore_src != null) switch_inst.kw_args.special_prong = .underscore; 2398 switch_inst.positionals.cases = try block_scope.arena.dupe(zir.Inst.SwitchBr.Case, cases.items); 2399 switch_inst.positionals.items = try block_scope.arena.dupe(*zir.Inst, items.items); 2400 switch_inst.kw_args.range = first_range; 2401 switch_inst.positionals.else_body = .{ 2402 .instructions = try block_scope.arena.dupe(*zir.Inst, else_scope.instructions.items), 2403 }; 2404 return &block.base; 2405 } 2406 2407 fn switchCaseExpr(mod: *Module, scope: *Scope, rl: ResultLoc, block: *zir.Inst.Block, case: *ast.Node.SwitchCase) !void { 2408 const tree = scope.tree(); 2409 const case_src = tree.token_locs[case.firstToken()].start; 2410 if (case.payload != null) { 2411 return mod.fail(scope, case_src, "TODO switch case payload capture", .{}); 2412 } 2413 2414 const case_body = try expr(mod, scope, rl, case.expr); 2415 if (!case_body.tag.isNoReturn()) { 2416 _ = try addZIRInst(mod, scope, case_src, zir.Inst.Break, .{ 2417 .block = block, 2418 .operand = case_body, 2419 }, .{}); 2420 } 2421 } 2422 2423 fn ret(mod: *Module, scope: *Scope, cfe: *ast.Node.ControlFlowExpression) InnerError!*zir.Inst { 2424 const tree = scope.tree(); 2425 const src = tree.token_locs[cfe.ltoken].start; 2426 if (cfe.getRHS()) |rhs_node| { 2427 if (nodeMayNeedMemoryLocation(rhs_node, scope)) { 2428 const ret_ptr = try addZIRNoOp(mod, scope, src, .ret_ptr); 2429 const operand = try expr(mod, scope, .{ .ptr = ret_ptr }, rhs_node); 2430 return addZIRUnOp(mod, scope, src, .@"return", operand); 2431 } else { 2432 const fn_ret_ty = try addZIRNoOp(mod, scope, src, .ret_type); 2433 const operand = try expr(mod, scope, .{ .ty = fn_ret_ty }, rhs_node); 2434 return addZIRUnOp(mod, scope, src, .@"return", operand); 2435 } 2436 } else { 2437 return addZIRNoOp(mod, scope, src, .return_void); 2438 } 2439 } 2440 2441 fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneToken) InnerError!*zir.Inst { 2442 const tracy = trace(@src()); 2443 defer tracy.end(); 2444 2445 const tree = scope.tree(); 2446 const ident_name = try mod.identifierTokenString(scope, ident.token); 2447 const src = tree.token_locs[ident.token].start; 2448 if (mem.eql(u8, ident_name, "_")) { 2449 return mod.failNode(scope, &ident.base, "TODO implement '_' identifier", .{}); 2450 } 2451 2452 if (getSimplePrimitiveValue(ident_name)) |typed_value| { 2453 const result = try addZIRInstConst(mod, scope, src, typed_value); 2454 return rvalue(mod, scope, rl, result); 2455 } 2456 2457 if (ident_name.len >= 2) integer: { 2458 const first_c = ident_name[0]; 2459 if (first_c == 'i' or first_c == 'u') { 2460 const is_signed = first_c == 'i'; 2461 const bit_count = std.fmt.parseInt(u16, ident_name[1..], 10) catch |err| switch (err) { 2462 error.Overflow => return mod.failNode( 2463 scope, 2464 &ident.base, 2465 "primitive integer type '{s}' exceeds maximum bit width of 65535", 2466 .{ident_name}, 2467 ), 2468 error.InvalidCharacter => break :integer, 2469 }; 2470 const val = switch (bit_count) { 2471 8 => if (is_signed) Value.initTag(.i8_type) else Value.initTag(.u8_type), 2472 16 => if (is_signed) Value.initTag(.i16_type) else Value.initTag(.u16_type), 2473 32 => if (is_signed) Value.initTag(.i32_type) else Value.initTag(.u32_type), 2474 64 => if (is_signed) Value.initTag(.i64_type) else Value.initTag(.u64_type), 2475 else => { 2476 return rvalue(mod, scope, rl, try addZIRInstConst(mod, scope, src, .{ 2477 .ty = Type.initTag(.type), 2478 .val = try Value.Tag.int_type.create(scope.arena(), .{ 2479 .signed = is_signed, 2480 .bits = bit_count, 2481 }), 2482 })); 2483 }, 2484 }; 2485 const result = try addZIRInstConst(mod, scope, src, .{ 2486 .ty = Type.initTag(.type), 2487 .val = val, 2488 }); 2489 return rvalue(mod, scope, rl, result); 2490 } 2491 } 2492 2493 // Local variables, including function parameters. 2494 { 2495 var s = scope; 2496 while (true) switch (s.tag) { 2497 .local_val => { 2498 const local_val = s.cast(Scope.LocalVal).?; 2499 if (mem.eql(u8, local_val.name, ident_name)) { 2500 return rvalue(mod, scope, rl, local_val.inst); 2501 } 2502 s = local_val.parent; 2503 }, 2504 .local_ptr => { 2505 const local_ptr = s.cast(Scope.LocalPtr).?; 2506 if (mem.eql(u8, local_ptr.name, ident_name)) { 2507 if (rl == .ref) return local_ptr.ptr; 2508 const loaded = try addZIRUnOp(mod, scope, src, .deref, local_ptr.ptr); 2509 return rvalue(mod, scope, rl, loaded); 2510 } 2511 s = local_ptr.parent; 2512 }, 2513 .gen_zir => s = s.cast(Scope.GenZIR).?.parent, 2514 else => break, 2515 }; 2516 } 2517 2518 if (mod.lookupDeclName(scope, ident_name)) |decl| { 2519 if (rl == .ref) { 2520 return addZIRInst(mod, scope, src, zir.Inst.DeclRef, .{ .decl = decl }, .{}); 2521 } else { 2522 return rvalue(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.DeclVal, .{ 2523 .decl = decl, 2524 }, .{})); 2525 } 2526 } 2527 2528 return mod.failNode(scope, &ident.base, "use of undeclared identifier '{s}'", .{ident_name}); 2529 } 2530 2531 fn stringLiteral(mod: *Module, scope: *Scope, str_lit: *ast.Node.OneToken) InnerError!*zir.Inst { 2532 const tree = scope.tree(); 2533 const unparsed_bytes = tree.tokenSlice(str_lit.token); 2534 const arena = scope.arena(); 2535 2536 var bad_index: usize = undefined; 2537 const bytes = std.zig.parseStringLiteral(arena, unparsed_bytes, &bad_index) catch |err| switch (err) { 2538 error.InvalidCharacter => { 2539 const bad_byte = unparsed_bytes[bad_index]; 2540 const src = tree.token_locs[str_lit.token].start; 2541 return mod.fail(scope, src + bad_index, "invalid string literal character: '{c}'\n", .{bad_byte}); 2542 }, 2543 else => |e| return e, 2544 }; 2545 2546 const src = tree.token_locs[str_lit.token].start; 2547 return addZIRInst(mod, scope, src, zir.Inst.Str, .{ .bytes = bytes }, .{}); 2548 } 2549 2550 fn multilineStrLiteral(mod: *Module, scope: *Scope, node: *ast.Node.MultilineStringLiteral) !*zir.Inst { 2551 const tree = scope.tree(); 2552 const lines = node.linesConst(); 2553 const src = tree.token_locs[lines[0]].start; 2554 2555 // line lengths and new lines 2556 var len = lines.len - 1; 2557 for (lines) |line| { 2558 // 2 for the '//' + 1 for '\n' 2559 len += tree.tokenSlice(line).len - 3; 2560 } 2561 2562 const bytes = try scope.arena().alloc(u8, len); 2563 var i: usize = 0; 2564 for (lines) |line, line_i| { 2565 if (line_i != 0) { 2566 bytes[i] = '\n'; 2567 i += 1; 2568 } 2569 const slice = tree.tokenSlice(line); 2570 mem.copy(u8, bytes[i..], slice[2 .. slice.len - 1]); 2571 i += slice.len - 3; 2572 } 2573 2574 return addZIRInst(mod, scope, src, zir.Inst.Str, .{ .bytes = bytes }, .{}); 2575 } 2576 2577 fn charLiteral(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) !*zir.Inst { 2578 const tree = scope.tree(); 2579 const src = tree.token_locs[node.token].start; 2580 const slice = tree.tokenSlice(node.token); 2581 2582 var bad_index: usize = undefined; 2583 const value = std.zig.parseCharLiteral(slice, &bad_index) catch |err| switch (err) { 2584 error.InvalidCharacter => { 2585 const bad_byte = slice[bad_index]; 2586 return mod.fail(scope, src + bad_index, "invalid character: '{c}'\n", .{bad_byte}); 2587 }, 2588 }; 2589 2590 return addZIRInstConst(mod, scope, src, .{ 2591 .ty = Type.initTag(.comptime_int), 2592 .val = try Value.Tag.int_u64.create(scope.arena(), value), 2593 }); 2594 } 2595 2596 fn integerLiteral(mod: *Module, scope: *Scope, int_lit: *ast.Node.OneToken) InnerError!*zir.Inst { 2597 const arena = scope.arena(); 2598 const tree = scope.tree(); 2599 const prefixed_bytes = tree.tokenSlice(int_lit.token); 2600 const base = if (mem.startsWith(u8, prefixed_bytes, "0x")) 2601 16 2602 else if (mem.startsWith(u8, prefixed_bytes, "0o")) 2603 8 2604 else if (mem.startsWith(u8, prefixed_bytes, "0b")) 2605 2 2606 else 2607 @as(u8, 10); 2608 2609 const bytes = if (base == 10) 2610 prefixed_bytes 2611 else 2612 prefixed_bytes[2..]; 2613 2614 if (std.fmt.parseInt(u64, bytes, base)) |small_int| { 2615 const src = tree.token_locs[int_lit.token].start; 2616 return addZIRInstConst(mod, scope, src, .{ 2617 .ty = Type.initTag(.comptime_int), 2618 .val = try Value.Tag.int_u64.create(arena, small_int), 2619 }); 2620 } else |err| { 2621 return mod.failTok(scope, int_lit.token, "TODO implement int literals that don't fit in a u64", .{}); 2622 } 2623 } 2624 2625 fn floatLiteral(mod: *Module, scope: *Scope, float_lit: *ast.Node.OneToken) InnerError!*zir.Inst { 2626 const arena = scope.arena(); 2627 const tree = scope.tree(); 2628 const bytes = tree.tokenSlice(float_lit.token); 2629 if (bytes.len > 2 and bytes[1] == 'x') { 2630 return mod.failTok(scope, float_lit.token, "TODO hex floats", .{}); 2631 } 2632 2633 const float_number = std.fmt.parseFloat(f128, bytes) catch |e| switch (e) { 2634 error.InvalidCharacter => unreachable, // validated by tokenizer 2635 }; 2636 const src = tree.token_locs[float_lit.token].start; 2637 return addZIRInstConst(mod, scope, src, .{ 2638 .ty = Type.initTag(.comptime_float), 2639 .val = try Value.Tag.float_128.create(arena, float_number), 2640 }); 2641 } 2642 2643 fn undefLiteral(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*zir.Inst { 2644 const arena = scope.arena(); 2645 const tree = scope.tree(); 2646 const src = tree.token_locs[node.token].start; 2647 return addZIRInstConst(mod, scope, src, .{ 2648 .ty = Type.initTag(.@"undefined"), 2649 .val = Value.initTag(.undef), 2650 }); 2651 } 2652 2653 fn boolLiteral(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*zir.Inst { 2654 const arena = scope.arena(); 2655 const tree = scope.tree(); 2656 const src = tree.token_locs[node.token].start; 2657 return addZIRInstConst(mod, scope, src, .{ 2658 .ty = Type.initTag(.bool), 2659 .val = switch (tree.token_ids[node.token]) { 2660 .Keyword_true => Value.initTag(.bool_true), 2661 .Keyword_false => Value.initTag(.bool_false), 2662 else => unreachable, 2663 }, 2664 }); 2665 } 2666 2667 fn nullLiteral(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*zir.Inst { 2668 const arena = scope.arena(); 2669 const tree = scope.tree(); 2670 const src = tree.token_locs[node.token].start; 2671 return addZIRInstConst(mod, scope, src, .{ 2672 .ty = Type.initTag(.@"null"), 2673 .val = Value.initTag(.null_value), 2674 }); 2675 } 2676 2677 fn assembly(mod: *Module, scope: *Scope, asm_node: *ast.Node.Asm) InnerError!*zir.Inst { 2678 if (asm_node.outputs.len != 0) { 2679 return mod.failNode(scope, &asm_node.base, "TODO implement asm with an output", .{}); 2680 } 2681 const arena = scope.arena(); 2682 const tree = scope.tree(); 2683 2684 const inputs = try arena.alloc(*zir.Inst, asm_node.inputs.len); 2685 const args = try arena.alloc(*zir.Inst, asm_node.inputs.len); 2686 2687 const src = tree.token_locs[asm_node.asm_token].start; 2688 2689 const str_type = try addZIRInstConst(mod, scope, src, .{ 2690 .ty = Type.initTag(.type), 2691 .val = Value.initTag(.const_slice_u8_type), 2692 }); 2693 const str_type_rl: ResultLoc = .{ .ty = str_type }; 2694 2695 for (asm_node.inputs) |input, i| { 2696 // TODO semantically analyze constraints 2697 inputs[i] = try expr(mod, scope, str_type_rl, input.constraint); 2698 args[i] = try expr(mod, scope, .none, input.expr); 2699 } 2700 2701 const return_type = try addZIRInstConst(mod, scope, src, .{ 2702 .ty = Type.initTag(.type), 2703 .val = Value.initTag(.void_type), 2704 }); 2705 const asm_inst = try addZIRInst(mod, scope, src, zir.Inst.Asm, .{ 2706 .asm_source = try expr(mod, scope, str_type_rl, asm_node.template), 2707 .return_type = return_type, 2708 }, .{ 2709 .@"volatile" = asm_node.volatile_token != null, 2710 //.clobbers = TODO handle clobbers 2711 .inputs = inputs, 2712 .args = args, 2713 }); 2714 return asm_inst; 2715 } 2716 2717 fn ensureBuiltinParamCount(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall, count: u32) !void { 2718 if (call.params_len == count) 2719 return; 2720 2721 const s = if (count == 1) "" else "s"; 2722 return mod.failTok(scope, call.builtin_token, "expected {d} parameter{s}, found {d}", .{ count, s, call.params_len }); 2723 } 2724 2725 fn simpleCast( 2726 mod: *Module, 2727 scope: *Scope, 2728 rl: ResultLoc, 2729 call: *ast.Node.BuiltinCall, 2730 inst_tag: zir.Inst.Tag, 2731 ) InnerError!*zir.Inst { 2732 try ensureBuiltinParamCount(mod, scope, call, 2); 2733 const tree = scope.tree(); 2734 const src = tree.token_locs[call.builtin_token].start; 2735 const params = call.params(); 2736 const dest_type = try typeExpr(mod, scope, params[0]); 2737 const rhs = try expr(mod, scope, .none, params[1]); 2738 const result = try addZIRBinOp(mod, scope, src, inst_tag, dest_type, rhs); 2739 return rvalue(mod, scope, rl, result); 2740 } 2741 2742 fn ptrToInt(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst { 2743 try ensureBuiltinParamCount(mod, scope, call, 1); 2744 const operand = try expr(mod, scope, .none, call.params()[0]); 2745 const tree = scope.tree(); 2746 const src = tree.token_locs[call.builtin_token].start; 2747 return addZIRUnOp(mod, scope, src, .ptrtoint, operand); 2748 } 2749 2750 fn as( 2751 mod: *Module, 2752 scope: *Scope, 2753 rl: ResultLoc, 2754 call: *ast.Node.BuiltinCall, 2755 ) InnerError!*zir.Inst { 2756 try ensureBuiltinParamCount(mod, scope, call, 2); 2757 const tree = scope.tree(); 2758 const src = tree.token_locs[call.builtin_token].start; 2759 const params = call.params(); 2760 const dest_type = try typeExpr(mod, scope, params[0]); 2761 switch (rl) { 2762 .none, .discard, .ref, .ty => { 2763 const result = try expr(mod, scope, .{ .ty = dest_type }, params[1]); 2764 return rvalue(mod, scope, rl, result); 2765 }, 2766 2767 .ptr => |result_ptr| { 2768 return asRlPtr(mod, scope, rl, src, result_ptr, params[1], dest_type); 2769 }, 2770 .block_ptr => |block_scope| { 2771 return asRlPtr(mod, scope, rl, src, block_scope.rl_ptr.?, params[1], dest_type); 2772 }, 2773 2774 .bitcasted_ptr => |bitcasted_ptr| { 2775 // TODO here we should be able to resolve the inference; we now have a type for the result. 2776 return mod.failTok(scope, call.builtin_token, "TODO implement @as with result location @bitCast", .{}); 2777 }, 2778 .inferred_ptr => |result_alloc| { 2779 // TODO here we should be able to resolve the inference; we now have a type for the result. 2780 return mod.failTok(scope, call.builtin_token, "TODO implement @as with inferred-type result location pointer", .{}); 2781 }, 2782 } 2783 } 2784 2785 fn asRlPtr( 2786 mod: *Module, 2787 scope: *Scope, 2788 rl: ResultLoc, 2789 src: usize, 2790 result_ptr: *zir.Inst, 2791 operand_node: *ast.Node, 2792 dest_type: *zir.Inst, 2793 ) InnerError!*zir.Inst { 2794 // Detect whether this expr() call goes into rvalue() to store the result into the 2795 // result location. If it does, elide the coerce_result_ptr instruction 2796 // as well as the store instruction, instead passing the result as an rvalue. 2797 var as_scope: Scope.GenZIR = .{ 2798 .parent = scope, 2799 .decl = scope.ownerDecl().?, 2800 .arena = scope.arena(), 2801 .instructions = .{}, 2802 }; 2803 defer as_scope.instructions.deinit(mod.gpa); 2804 2805 as_scope.rl_ptr = try addZIRBinOp(mod, &as_scope.base, src, .coerce_result_ptr, dest_type, result_ptr); 2806 const result = try expr(mod, &as_scope.base, .{ .block_ptr = &as_scope }, operand_node); 2807 const parent_zir = &scope.getGenZIR().instructions; 2808 if (as_scope.rvalue_rl_count == 1) { 2809 // Busted! This expression didn't actually need a pointer. 2810 const expected_len = parent_zir.items.len + as_scope.instructions.items.len - 2; 2811 try parent_zir.ensureCapacity(mod.gpa, expected_len); 2812 for (as_scope.instructions.items) |src_inst| { 2813 switch (src_inst.tag) { 2814 .store_to_block_ptr, .coerce_result_ptr => continue, 2815 else => parent_zir.appendAssumeCapacity(src_inst), 2816 } 2817 } 2818 assert(parent_zir.items.len == expected_len); 2819 return rvalue(mod, scope, rl, result); 2820 } else { 2821 try parent_zir.appendSlice(mod.gpa, as_scope.instructions.items); 2822 return result; 2823 } 2824 } 2825 2826 fn bitCast(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst { 2827 try ensureBuiltinParamCount(mod, scope, call, 2); 2828 const tree = scope.tree(); 2829 const src = tree.token_locs[call.builtin_token].start; 2830 const params = call.params(); 2831 const dest_type = try typeExpr(mod, scope, params[0]); 2832 switch (rl) { 2833 .none => { 2834 const operand = try expr(mod, scope, .none, params[1]); 2835 return addZIRBinOp(mod, scope, src, .bitcast, dest_type, operand); 2836 }, 2837 .discard => { 2838 const operand = try expr(mod, scope, .none, params[1]); 2839 const result = try addZIRBinOp(mod, scope, src, .bitcast, dest_type, operand); 2840 _ = try addZIRUnOp(mod, scope, result.src, .ensure_result_non_error, result); 2841 return result; 2842 }, 2843 .ref => { 2844 const operand = try expr(mod, scope, .ref, params[1]); 2845 const result = try addZIRBinOp(mod, scope, src, .bitcast_ref, dest_type, operand); 2846 return result; 2847 }, 2848 .ty => |result_ty| { 2849 const result = try expr(mod, scope, .none, params[1]); 2850 const bitcasted = try addZIRBinOp(mod, scope, src, .bitcast, dest_type, result); 2851 return addZIRBinOp(mod, scope, src, .as, result_ty, bitcasted); 2852 }, 2853 .ptr => |result_ptr| { 2854 const casted_result_ptr = try addZIRUnOp(mod, scope, src, .bitcast_result_ptr, result_ptr); 2855 return expr(mod, scope, .{ .bitcasted_ptr = casted_result_ptr.castTag(.bitcast_result_ptr).? }, params[1]); 2856 }, 2857 .bitcasted_ptr => |bitcasted_ptr| { 2858 return mod.failTok(scope, call.builtin_token, "TODO implement @bitCast with result location another @bitCast", .{}); 2859 }, 2860 .block_ptr => |block_ptr| { 2861 return mod.failTok(scope, call.builtin_token, "TODO implement @bitCast with result location inferred peer types", .{}); 2862 }, 2863 .inferred_ptr => |result_alloc| { 2864 // TODO here we should be able to resolve the inference; we now have a type for the result. 2865 return mod.failTok(scope, call.builtin_token, "TODO implement @bitCast with inferred-type result location pointer", .{}); 2866 }, 2867 } 2868 } 2869 2870 fn import(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst { 2871 try ensureBuiltinParamCount(mod, scope, call, 1); 2872 const tree = scope.tree(); 2873 const src = tree.token_locs[call.builtin_token].start; 2874 const params = call.params(); 2875 const target = try expr(mod, scope, .none, params[0]); 2876 return addZIRUnOp(mod, scope, src, .import, target); 2877 } 2878 2879 fn compileError(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst { 2880 try ensureBuiltinParamCount(mod, scope, call, 1); 2881 const tree = scope.tree(); 2882 const src = tree.token_locs[call.builtin_token].start; 2883 const params = call.params(); 2884 const target = try expr(mod, scope, .none, params[0]); 2885 return addZIRUnOp(mod, scope, src, .compile_error, target); 2886 } 2887 2888 fn setEvalBranchQuota(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst { 2889 try ensureBuiltinParamCount(mod, scope, call, 1); 2890 const tree = scope.tree(); 2891 const src = tree.token_locs[call.builtin_token].start; 2892 const params = call.params(); 2893 const u32_type = try addZIRInstConst(mod, scope, src, .{ 2894 .ty = Type.initTag(.type), 2895 .val = Value.initTag(.u32_type), 2896 }); 2897 const quota = try expr(mod, scope, .{ .ty = u32_type }, params[0]); 2898 return addZIRUnOp(mod, scope, src, .set_eval_branch_quota, quota); 2899 } 2900 2901 fn typeOf(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst { 2902 const tree = scope.tree(); 2903 const arena = scope.arena(); 2904 const src = tree.token_locs[call.builtin_token].start; 2905 const params = call.params(); 2906 if (params.len < 1) { 2907 return mod.failTok(scope, call.builtin_token, "expected at least 1 argument, found 0", .{}); 2908 } 2909 if (params.len == 1) { 2910 return rvalue(mod, scope, rl, try addZIRUnOp(mod, scope, src, .typeof, try expr(mod, scope, .none, params[0]))); 2911 } 2912 var items = try arena.alloc(*zir.Inst, params.len); 2913 for (params) |param, param_i| 2914 items[param_i] = try expr(mod, scope, .none, param); 2915 return rvalue(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.TypeOfPeer, .{ .items = items }, .{})); 2916 } 2917 fn compileLog(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst { 2918 const tree = scope.tree(); 2919 const arena = scope.arena(); 2920 const src = tree.token_locs[call.builtin_token].start; 2921 const params = call.params(); 2922 var targets = try arena.alloc(*zir.Inst, params.len); 2923 for (params) |param, param_i| 2924 targets[param_i] = try expr(mod, scope, .none, param); 2925 return addZIRInst(mod, scope, src, zir.Inst.CompileLog, .{ .to_log = targets }, .{}); 2926 } 2927 2928 fn builtinCall(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst { 2929 const tree = scope.tree(); 2930 const builtin_name = tree.tokenSlice(call.builtin_token); 2931 2932 // We handle the different builtins manually because they have different semantics depending 2933 // on the function. For example, `@as` and others participate in result location semantics, 2934 // and `@cImport` creates a special scope that collects a .c source code text buffer. 2935 // Also, some builtins have a variable number of parameters. 2936 2937 if (mem.eql(u8, builtin_name, "@ptrToInt")) { 2938 return rvalue(mod, scope, rl, try ptrToInt(mod, scope, call)); 2939 } else if (mem.eql(u8, builtin_name, "@as")) { 2940 return as(mod, scope, rl, call); 2941 } else if (mem.eql(u8, builtin_name, "@floatCast")) { 2942 return simpleCast(mod, scope, rl, call, .floatcast); 2943 } else if (mem.eql(u8, builtin_name, "@intCast")) { 2944 return simpleCast(mod, scope, rl, call, .intcast); 2945 } else if (mem.eql(u8, builtin_name, "@bitCast")) { 2946 return bitCast(mod, scope, rl, call); 2947 } else if (mem.eql(u8, builtin_name, "@TypeOf")) { 2948 return typeOf(mod, scope, rl, call); 2949 } else if (mem.eql(u8, builtin_name, "@breakpoint")) { 2950 const src = tree.token_locs[call.builtin_token].start; 2951 return rvalue(mod, scope, rl, try addZIRNoOp(mod, scope, src, .breakpoint)); 2952 } else if (mem.eql(u8, builtin_name, "@import")) { 2953 return rvalue(mod, scope, rl, try import(mod, scope, call)); 2954 } else if (mem.eql(u8, builtin_name, "@compileError")) { 2955 return compileError(mod, scope, call); 2956 } else if (mem.eql(u8, builtin_name, "@setEvalBranchQuota")) { 2957 return setEvalBranchQuota(mod, scope, call); 2958 } else if (mem.eql(u8, builtin_name, "@compileLog")) { 2959 return compileLog(mod, scope, call); 2960 } else if (mem.eql(u8, builtin_name, "@field")) { 2961 return namedField(mod, scope, rl, call); 2962 } else { 2963 return mod.failTok(scope, call.builtin_token, "invalid builtin function: '{s}'", .{builtin_name}); 2964 } 2965 } 2966 2967 fn callExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Call) InnerError!*zir.Inst { 2968 const tree = scope.tree(); 2969 const lhs = try expr(mod, scope, .none, node.lhs); 2970 2971 const param_nodes = node.params(); 2972 const args = try scope.getGenZIR().arena.alloc(*zir.Inst, param_nodes.len); 2973 for (param_nodes) |param_node, i| { 2974 const param_src = tree.token_locs[param_node.firstToken()].start; 2975 const param_type = try addZIRInst(mod, scope, param_src, zir.Inst.ParamType, .{ 2976 .func = lhs, 2977 .arg_index = i, 2978 }, .{}); 2979 args[i] = try expr(mod, scope, .{ .ty = param_type }, param_node); 2980 } 2981 2982 const src = tree.token_locs[node.lhs.firstToken()].start; 2983 const result = try addZIRInst(mod, scope, src, zir.Inst.Call, .{ 2984 .func = lhs, 2985 .args = args, 2986 }, .{}); 2987 // TODO function call with result location 2988 return rvalue(mod, scope, rl, result); 2989 } 2990 2991 fn unreach(mod: *Module, scope: *Scope, unreach_node: *ast.Node.OneToken) InnerError!*zir.Inst { 2992 const tree = scope.tree(); 2993 const src = tree.token_locs[unreach_node.token].start; 2994 return addZIRNoOp(mod, scope, src, .unreachable_safe); 2995 } 2996 2997 fn getSimplePrimitiveValue(name: []const u8) ?TypedValue { 2998 const simple_types = std.ComptimeStringMap(Value.Tag, .{ 2999 .{ "u8", .u8_type }, 3000 .{ "i8", .i8_type }, 3001 .{ "isize", .isize_type }, 3002 .{ "usize", .usize_type }, 3003 .{ "c_short", .c_short_type }, 3004 .{ "c_ushort", .c_ushort_type }, 3005 .{ "c_int", .c_int_type }, 3006 .{ "c_uint", .c_uint_type }, 3007 .{ "c_long", .c_long_type }, 3008 .{ "c_ulong", .c_ulong_type }, 3009 .{ "c_longlong", .c_longlong_type }, 3010 .{ "c_ulonglong", .c_ulonglong_type }, 3011 .{ "c_longdouble", .c_longdouble_type }, 3012 .{ "f16", .f16_type }, 3013 .{ "f32", .f32_type }, 3014 .{ "f64", .f64_type }, 3015 .{ "f128", .f128_type }, 3016 .{ "c_void", .c_void_type }, 3017 .{ "bool", .bool_type }, 3018 .{ "void", .void_type }, 3019 .{ "type", .type_type }, 3020 .{ "anyerror", .anyerror_type }, 3021 .{ "comptime_int", .comptime_int_type }, 3022 .{ "comptime_float", .comptime_float_type }, 3023 .{ "noreturn", .noreturn_type }, 3024 }); 3025 if (simple_types.get(name)) |tag| { 3026 return TypedValue{ 3027 .ty = Type.initTag(.type), 3028 .val = Value.initTag(tag), 3029 }; 3030 } 3031 return null; 3032 } 3033 3034 fn nodeMayNeedMemoryLocation(start_node: *ast.Node, scope: *Scope) bool { 3035 var node = start_node; 3036 while (true) { 3037 switch (node.tag) { 3038 .Root, 3039 .Use, 3040 .TestDecl, 3041 .DocComment, 3042 .SwitchCase, 3043 .SwitchElse, 3044 .Else, 3045 .Payload, 3046 .PointerPayload, 3047 .PointerIndexPayload, 3048 .ContainerField, 3049 .ErrorTag, 3050 .FieldInitializer, 3051 => unreachable, 3052 3053 .Return, 3054 .Break, 3055 .Continue, 3056 .BitNot, 3057 .BoolNot, 3058 .VarDecl, 3059 .Defer, 3060 .AddressOf, 3061 .OptionalType, 3062 .Negation, 3063 .NegationWrap, 3064 .Resume, 3065 .ArrayType, 3066 .ArrayTypeSentinel, 3067 .PtrType, 3068 .SliceType, 3069 .Suspend, 3070 .AnyType, 3071 .ErrorType, 3072 .FnProto, 3073 .AnyFrameType, 3074 .IntegerLiteral, 3075 .FloatLiteral, 3076 .EnumLiteral, 3077 .StringLiteral, 3078 .MultilineStringLiteral, 3079 .CharLiteral, 3080 .BoolLiteral, 3081 .NullLiteral, 3082 .UndefinedLiteral, 3083 .Unreachable, 3084 .Identifier, 3085 .ErrorSetDecl, 3086 .ContainerDecl, 3087 .Asm, 3088 .Add, 3089 .AddWrap, 3090 .ArrayCat, 3091 .ArrayMult, 3092 .Assign, 3093 .AssignBitAnd, 3094 .AssignBitOr, 3095 .AssignBitShiftLeft, 3096 .AssignBitShiftRight, 3097 .AssignBitXor, 3098 .AssignDiv, 3099 .AssignSub, 3100 .AssignSubWrap, 3101 .AssignMod, 3102 .AssignAdd, 3103 .AssignAddWrap, 3104 .AssignMul, 3105 .AssignMulWrap, 3106 .BangEqual, 3107 .BitAnd, 3108 .BitOr, 3109 .BitShiftLeft, 3110 .BitShiftRight, 3111 .BitXor, 3112 .BoolAnd, 3113 .BoolOr, 3114 .Div, 3115 .EqualEqual, 3116 .ErrorUnion, 3117 .GreaterOrEqual, 3118 .GreaterThan, 3119 .LessOrEqual, 3120 .LessThan, 3121 .MergeErrorSets, 3122 .Mod, 3123 .Mul, 3124 .MulWrap, 3125 .Range, 3126 .Period, 3127 .Sub, 3128 .SubWrap, 3129 .Slice, 3130 .Deref, 3131 .ArrayAccess, 3132 .Block, 3133 => return false, 3134 3135 // Forward the question to a sub-expression. 3136 .GroupedExpression => node = node.castTag(.GroupedExpression).?.expr, 3137 .Try => node = node.castTag(.Try).?.rhs, 3138 .Await => node = node.castTag(.Await).?.rhs, 3139 .Catch => node = node.castTag(.Catch).?.rhs, 3140 .OrElse => node = node.castTag(.OrElse).?.rhs, 3141 .Comptime => node = node.castTag(.Comptime).?.expr, 3142 .Nosuspend => node = node.castTag(.Nosuspend).?.expr, 3143 .UnwrapOptional => node = node.castTag(.UnwrapOptional).?.lhs, 3144 3145 // True because these are exactly the expressions we need memory locations for. 3146 .ArrayInitializer, 3147 .ArrayInitializerDot, 3148 .StructInitializer, 3149 .StructInitializerDot, 3150 => return true, 3151 3152 // True because depending on comptime conditions, sub-expressions 3153 // may be the kind that need memory locations. 3154 .While, 3155 .For, 3156 .Switch, 3157 .Call, 3158 .LabeledBlock, 3159 => return true, 3160 3161 .BuiltinCall => { 3162 @setEvalBranchQuota(5000); 3163 const builtin_needs_mem_loc = std.ComptimeStringMap(bool, .{ 3164 .{ "@addWithOverflow", false }, 3165 .{ "@alignCast", false }, 3166 .{ "@alignOf", false }, 3167 .{ "@as", true }, 3168 .{ "@asyncCall", false }, 3169 .{ "@atomicLoad", false }, 3170 .{ "@atomicRmw", false }, 3171 .{ "@atomicStore", false }, 3172 .{ "@bitCast", true }, 3173 .{ "@bitOffsetOf", false }, 3174 .{ "@boolToInt", false }, 3175 .{ "@bitSizeOf", false }, 3176 .{ "@breakpoint", false }, 3177 .{ "@mulAdd", false }, 3178 .{ "@byteSwap", false }, 3179 .{ "@bitReverse", false }, 3180 .{ "@byteOffsetOf", false }, 3181 .{ "@call", true }, 3182 .{ "@cDefine", false }, 3183 .{ "@cImport", false }, 3184 .{ "@cInclude", false }, 3185 .{ "@clz", false }, 3186 .{ "@cmpxchgStrong", false }, 3187 .{ "@cmpxchgWeak", false }, 3188 .{ "@compileError", false }, 3189 .{ "@compileLog", false }, 3190 .{ "@ctz", false }, 3191 .{ "@cUndef", false }, 3192 .{ "@divExact", false }, 3193 .{ "@divFloor", false }, 3194 .{ "@divTrunc", false }, 3195 .{ "@embedFile", false }, 3196 .{ "@enumToInt", false }, 3197 .{ "@errorName", false }, 3198 .{ "@errorReturnTrace", false }, 3199 .{ "@errorToInt", false }, 3200 .{ "@errSetCast", false }, 3201 .{ "@export", false }, 3202 .{ "@fence", false }, 3203 .{ "@field", true }, 3204 .{ "@fieldParentPtr", false }, 3205 .{ "@floatCast", false }, 3206 .{ "@floatToInt", false }, 3207 .{ "@frame", false }, 3208 .{ "@Frame", false }, 3209 .{ "@frameAddress", false }, 3210 .{ "@frameSize", false }, 3211 .{ "@hasDecl", false }, 3212 .{ "@hasField", false }, 3213 .{ "@import", false }, 3214 .{ "@intCast", false }, 3215 .{ "@intToEnum", false }, 3216 .{ "@intToError", false }, 3217 .{ "@intToFloat", false }, 3218 .{ "@intToPtr", false }, 3219 .{ "@memcpy", false }, 3220 .{ "@memset", false }, 3221 .{ "@wasmMemorySize", false }, 3222 .{ "@wasmMemoryGrow", false }, 3223 .{ "@mod", false }, 3224 .{ "@mulWithOverflow", false }, 3225 .{ "@panic", false }, 3226 .{ "@popCount", false }, 3227 .{ "@ptrCast", false }, 3228 .{ "@ptrToInt", false }, 3229 .{ "@rem", false }, 3230 .{ "@returnAddress", false }, 3231 .{ "@setAlignStack", false }, 3232 .{ "@setCold", false }, 3233 .{ "@setEvalBranchQuota", false }, 3234 .{ "@setFloatMode", false }, 3235 .{ "@setRuntimeSafety", false }, 3236 .{ "@shlExact", false }, 3237 .{ "@shlWithOverflow", false }, 3238 .{ "@shrExact", false }, 3239 .{ "@shuffle", false }, 3240 .{ "@sizeOf", false }, 3241 .{ "@splat", true }, 3242 .{ "@reduce", false }, 3243 .{ "@src", true }, 3244 .{ "@sqrt", false }, 3245 .{ "@sin", false }, 3246 .{ "@cos", false }, 3247 .{ "@exp", false }, 3248 .{ "@exp2", false }, 3249 .{ "@log", false }, 3250 .{ "@log2", false }, 3251 .{ "@log10", false }, 3252 .{ "@fabs", false }, 3253 .{ "@floor", false }, 3254 .{ "@ceil", false }, 3255 .{ "@trunc", false }, 3256 .{ "@round", false }, 3257 .{ "@subWithOverflow", false }, 3258 .{ "@tagName", false }, 3259 .{ "@This", false }, 3260 .{ "@truncate", false }, 3261 .{ "@Type", false }, 3262 .{ "@typeInfo", false }, 3263 .{ "@typeName", false }, 3264 .{ "@TypeOf", false }, 3265 .{ "@unionInit", true }, 3266 }); 3267 const name = scope.tree().tokenSlice(node.castTag(.BuiltinCall).?.builtin_token); 3268 return builtin_needs_mem_loc.get(name).?; 3269 }, 3270 3271 // Depending on AST properties, they may need memory locations. 3272 .If => return node.castTag(.If).?.@"else" != null, 3273 } 3274 } 3275 } 3276 3277 /// Applies `rl` semantics to `inst`. Expressions which do not do their own handling of 3278 /// result locations must call this function on their result. 3279 /// As an example, if the `ResultLoc` is `ptr`, it will write the result to the pointer. 3280 /// If the `ResultLoc` is `ty`, it will coerce the result to the type. 3281 fn rvalue(mod: *Module, scope: *Scope, rl: ResultLoc, result: *zir.Inst) InnerError!*zir.Inst { 3282 switch (rl) { 3283 .none => return result, 3284 .discard => { 3285 // Emit a compile error for discarding error values. 3286 _ = try addZIRUnOp(mod, scope, result.src, .ensure_result_non_error, result); 3287 return result; 3288 }, 3289 .ref => { 3290 // We need a pointer but we have a value. 3291 return addZIRUnOp(mod, scope, result.src, .ref, result); 3292 }, 3293 .ty => |ty_inst| return addZIRBinOp(mod, scope, result.src, .as, ty_inst, result), 3294 .ptr => |ptr_inst| { 3295 _ = try addZIRBinOp(mod, scope, result.src, .store, ptr_inst, result); 3296 return result; 3297 }, 3298 .bitcasted_ptr => |bitcasted_ptr| { 3299 return mod.fail(scope, result.src, "TODO implement rvalue .bitcasted_ptr", .{}); 3300 }, 3301 .inferred_ptr => |alloc| { 3302 _ = try addZIRBinOp(mod, scope, result.src, .store_to_inferred_ptr, &alloc.base, result); 3303 return result; 3304 }, 3305 .block_ptr => |block_scope| { 3306 block_scope.rvalue_rl_count += 1; 3307 _ = try addZIRBinOp(mod, scope, result.src, .store_to_block_ptr, block_scope.rl_ptr.?, result); 3308 return result; 3309 }, 3310 } 3311 } 3312 3313 fn rvalueVoid(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node, result: void) InnerError!*zir.Inst { 3314 const src = scope.tree().token_locs[node.firstToken()].start; 3315 const void_inst = try addZIRInstConst(mod, scope, src, .{ 3316 .ty = Type.initTag(.void), 3317 .val = Value.initTag(.void_value), 3318 }); 3319 return rvalue(mod, scope, rl, void_inst); 3320 } 3321 3322 pub fn addZirInstTag( 3323 mod: *Module, 3324 scope: *Scope, 3325 src: usize, 3326 comptime tag: zir.Inst.Tag, 3327 positionals: std.meta.fieldInfo(tag.Type(), .positionals).field_type, 3328 ) !*zir.Inst { 3329 const gen_zir = scope.getGenZIR(); 3330 try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1); 3331 const inst = try gen_zir.arena.create(tag.Type()); 3332 inst.* = .{ 3333 .base = .{ 3334 .tag = tag, 3335 .src = src, 3336 }, 3337 .positionals = positionals, 3338 .kw_args = .{}, 3339 }; 3340 gen_zir.instructions.appendAssumeCapacity(&inst.base); 3341 return &inst.base; 3342 } 3343 3344 pub fn addZIRInstSpecial( 3345 mod: *Module, 3346 scope: *Scope, 3347 src: usize, 3348 comptime T: type, 3349 positionals: std.meta.fieldInfo(T, .positionals).field_type, 3350 kw_args: std.meta.fieldInfo(T, .kw_args).field_type, 3351 ) !*T { 3352 const gen_zir = scope.getGenZIR(); 3353 try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1); 3354 const inst = try gen_zir.arena.create(T); 3355 inst.* = .{ 3356 .base = .{ 3357 .tag = T.base_tag, 3358 .src = src, 3359 }, 3360 .positionals = positionals, 3361 .kw_args = kw_args, 3362 }; 3363 gen_zir.instructions.appendAssumeCapacity(&inst.base); 3364 return inst; 3365 } 3366 3367 pub fn addZIRNoOpT(mod: *Module, scope: *Scope, src: usize, tag: zir.Inst.Tag) !*zir.Inst.NoOp { 3368 const gen_zir = scope.getGenZIR(); 3369 try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1); 3370 const inst = try gen_zir.arena.create(zir.Inst.NoOp); 3371 inst.* = .{ 3372 .base = .{ 3373 .tag = tag, 3374 .src = src, 3375 }, 3376 .positionals = .{}, 3377 .kw_args = .{}, 3378 }; 3379 gen_zir.instructions.appendAssumeCapacity(&inst.base); 3380 return inst; 3381 } 3382 3383 pub fn addZIRNoOp(mod: *Module, scope: *Scope, src: usize, tag: zir.Inst.Tag) !*zir.Inst { 3384 const inst = try addZIRNoOpT(mod, scope, src, tag); 3385 return &inst.base; 3386 } 3387 3388 pub fn addZIRUnOp( 3389 mod: *Module, 3390 scope: *Scope, 3391 src: usize, 3392 tag: zir.Inst.Tag, 3393 operand: *zir.Inst, 3394 ) !*zir.Inst { 3395 const gen_zir = scope.getGenZIR(); 3396 try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1); 3397 const inst = try gen_zir.arena.create(zir.Inst.UnOp); 3398 inst.* = .{ 3399 .base = .{ 3400 .tag = tag, 3401 .src = src, 3402 }, 3403 .positionals = .{ 3404 .operand = operand, 3405 }, 3406 .kw_args = .{}, 3407 }; 3408 gen_zir.instructions.appendAssumeCapacity(&inst.base); 3409 return &inst.base; 3410 } 3411 3412 pub fn addZIRBinOp( 3413 mod: *Module, 3414 scope: *Scope, 3415 src: usize, 3416 tag: zir.Inst.Tag, 3417 lhs: *zir.Inst, 3418 rhs: *zir.Inst, 3419 ) !*zir.Inst { 3420 const gen_zir = scope.getGenZIR(); 3421 try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1); 3422 const inst = try gen_zir.arena.create(zir.Inst.BinOp); 3423 inst.* = .{ 3424 .base = .{ 3425 .tag = tag, 3426 .src = src, 3427 }, 3428 .positionals = .{ 3429 .lhs = lhs, 3430 .rhs = rhs, 3431 }, 3432 .kw_args = .{}, 3433 }; 3434 gen_zir.instructions.appendAssumeCapacity(&inst.base); 3435 return &inst.base; 3436 } 3437 3438 pub fn addZIRInstBlock( 3439 mod: *Module, 3440 scope: *Scope, 3441 src: usize, 3442 tag: zir.Inst.Tag, 3443 body: zir.Body, 3444 ) !*zir.Inst.Block { 3445 const gen_zir = scope.getGenZIR(); 3446 try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1); 3447 const inst = try gen_zir.arena.create(zir.Inst.Block); 3448 inst.* = .{ 3449 .base = .{ 3450 .tag = tag, 3451 .src = src, 3452 }, 3453 .positionals = .{ 3454 .body = body, 3455 }, 3456 .kw_args = .{}, 3457 }; 3458 gen_zir.instructions.appendAssumeCapacity(&inst.base); 3459 return inst; 3460 } 3461 3462 pub fn addZIRInst( 3463 mod: *Module, 3464 scope: *Scope, 3465 src: usize, 3466 comptime T: type, 3467 positionals: std.meta.fieldInfo(T, .positionals).field_type, 3468 kw_args: std.meta.fieldInfo(T, .kw_args).field_type, 3469 ) !*zir.Inst { 3470 const inst_special = try addZIRInstSpecial(mod, scope, src, T, positionals, kw_args); 3471 return &inst_special.base; 3472 } 3473 3474 /// TODO The existence of this function is a workaround for a bug in stage1. 3475 pub fn addZIRInstConst(mod: *Module, scope: *Scope, src: usize, typed_value: TypedValue) !*zir.Inst { 3476 const P = std.meta.fieldInfo(zir.Inst.Const, .positionals).field_type; 3477 return addZIRInst(mod, scope, src, zir.Inst.Const, P{ .typed_value = typed_value }, .{}); 3478 } 3479 3480 /// TODO The existence of this function is a workaround for a bug in stage1. 3481 pub fn addZIRInstLoop(mod: *Module, scope: *Scope, src: usize, body: zir.Body) !*zir.Inst.Loop { 3482 const P = std.meta.fieldInfo(zir.Inst.Loop, .positionals).field_type; 3483 return addZIRInstSpecial(mod, scope, src, zir.Inst.Loop, P{ .body = body }, .{}); 3484 }