| ... | ... | @@ -273,6 +273,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr |
| 273 | 273 | .AnyFrameType => return rlWrap(mod, scope, rl, try anyFrameType(mod, scope, node.castTag(.AnyFrameType).?)), |
| 274 | 274 | .ErrorSetDecl => return errorSetDecl(mod, scope, rl, node.castTag(.ErrorSetDecl).?), |
| 275 | 275 | .ErrorType => return rlWrap(mod, scope, rl, try errorType(mod, scope, node.castTag(.ErrorType).?)), |
| 276 | .For => return forExpr(mod, scope, rl, node.castTag(.For).?), |
| 276 | 277 | |
| 277 | 278 | .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}), |
| 278 | 279 | .Catch => return mod.failNode(scope, node, "TODO implement astgen.expr for .Catch", .{}), |
| ... | ... | @@ -288,7 +289,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr |
| 288 | 289 | .StructInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .StructInitializer", .{}), |
| 289 | 290 | .StructInitializerDot => return mod.failNode(scope, node, "TODO implement astgen.expr for .StructInitializerDot", .{}), |
| 290 | 291 | .Switch => return mod.failNode(scope, node, "TODO implement astgen.expr for .Switch", .{}), |
| 291 | | .For => return mod.failNode(scope, node, "TODO implement astgen.expr for .For", .{}), |
| 292 | 292 | .Suspend => return mod.failNode(scope, node, "TODO implement astgen.expr for .Suspend", .{}), |
| 293 | 293 | .Continue => return mod.failNode(scope, node, "TODO implement astgen.expr for .Continue", .{}), |
| 294 | 294 | .AnyType => return mod.failNode(scope, node, "TODO implement astgen.expr for .AnyType", .{}), |
| ... | ... | @@ -497,7 +497,7 @@ fn varDecl( |
| 497 | 497 | const var_data: struct { result_loc: ResultLoc, alloc: *zir.Inst } = if (node.getTrailer("type_node")) |type_node| a: { |
| 498 | 498 | const type_inst = try typeExpr(mod, scope, type_node); |
| 499 | 499 | const alloc = try addZIRUnOp(mod, scope, name_src, .alloc, type_inst); |
| 500 | | break :a .{ .alloc = try addZIRUnOp(mod, scope, name_src, .alloc, type_inst), .result_loc = .{ .ptr = alloc } }; |
| 500 | break :a .{ .alloc = alloc, .result_loc = .{ .ptr = alloc } }; |
| 501 | 501 | } else a: { |
| 502 | 502 | const alloc = try addZIRNoOp(mod, scope, name_src, .alloc_inferred); |
| 503 | 503 | break :a .{ .alloc = alloc, .result_loc = .{ .inferred_ptr = alloc.castTag(.alloc_inferred).? } }; |
| ... | ... | @@ -624,7 +624,7 @@ fn ptrSliceType(mod: *Module, scope: *Scope, src: usize, ptr_info: *ast.PtrInfo, |
| 624 | 624 | .One => if (mutable) T.single_mut_ptr_type else T.single_const_ptr_type, |
| 625 | 625 | .Many => if (mutable) T.many_mut_ptr_type else T.many_const_ptr_type, |
| 626 | 626 | .C => if (mutable) T.c_mut_ptr_type else T.c_const_ptr_type, |
| 627 | | .Slice => if (mutable) T.mut_slice_type else T.mut_slice_type, |
| 627 | .Slice => if (mutable) T.mut_slice_type else T.const_slice_type, |
| 628 | 628 | }, child_type); |
| 629 | 629 | } |
| 630 | 630 | |
| ... | ... | @@ -794,9 +794,7 @@ fn field(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleInfix |
| 794 | 794 | const lhs = try expr(mod, scope, .ref, node.lhs); |
| 795 | 795 | const field_name = try identifierStringInst(mod, scope, node.rhs.castTag(.Identifier).?); |
| 796 | 796 | |
| 797 | | const pointer = try addZIRInst(mod, scope, src, zir.Inst.FieldPtr, .{ .object_ptr = lhs, .field_name = field_name }, .{}); |
| 798 | | if (rl == .ref) return pointer; |
| 799 | | return rlWrap(mod, scope, rl, try addZIRUnOp(mod, scope, src, .deref, pointer)); |
| 797 | return rlWrapPtr(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.FieldPtr, .{ .object_ptr = lhs, .field_name = field_name }, .{})); |
| 800 | 798 | } |
| 801 | 799 | |
| 802 | 800 | fn deref(mod: *Module, scope: *Scope, node: *ast.Node.SimpleSuffixOp) InnerError!*zir.Inst { |
| ... | ... | @@ -1080,6 +1078,12 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W |
| 1080 | 1078 | } |
| 1081 | 1079 | } |
| 1082 | 1080 | |
| 1081 | if (while_node.label) |tok| |
| 1082 | return mod.failTok(scope, tok, "TODO labeled while", .{}); |
| 1083 | |
| 1084 | if (while_node.inline_token) |tok| |
| 1085 | return mod.failTok(scope, tok, "TODO inline while", .{}); |
| 1086 | |
| 1083 | 1087 | var expr_scope: Scope.GenZIR = .{ |
| 1084 | 1088 | .parent = scope, |
| 1085 | 1089 | .decl = scope.decl().?, |
| ... | ... | @@ -1198,6 +1202,179 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W |
| 1198 | 1202 | return &while_block.base; |
| 1199 | 1203 | } |
| 1200 | 1204 | |
| 1205 | fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For) InnerError!*zir.Inst { |
| 1206 | if (for_node.label) |tok| |
| 1207 | return mod.failTok(scope, tok, "TODO labeled for", .{}); |
| 1208 | |
| 1209 | if (for_node.inline_token) |tok| |
| 1210 | return mod.failTok(scope, tok, "TODO inline for", .{}); |
| 1211 | |
| 1212 | var for_scope: Scope.GenZIR = .{ |
| 1213 | .parent = scope, |
| 1214 | .decl = scope.decl().?, |
| 1215 | .arena = scope.arena(), |
| 1216 | .instructions = .{}, |
| 1217 | }; |
| 1218 | defer for_scope.instructions.deinit(mod.gpa); |
| 1219 | |
| 1220 | // setup variables and constants |
| 1221 | const tree = scope.tree(); |
| 1222 | const for_src = tree.token_locs[for_node.for_token].start; |
| 1223 | const index_ptr = blk: { |
| 1224 | const usize_type = try addZIRInstConst(mod, &for_scope.base, for_src, .{ |
| 1225 | .ty = Type.initTag(.type), |
| 1226 | .val = Value.initTag(.usize_type), |
| 1227 | }); |
| 1228 | const index_ptr = try addZIRUnOp(mod, &for_scope.base, for_src, .alloc, usize_type); |
| 1229 | // initialize to zero |
| 1230 | const zero = try addZIRInstConst(mod, &for_scope.base, for_src, .{ |
| 1231 | .ty = Type.initTag(.usize), |
| 1232 | .val = Value.initTag(.zero), |
| 1233 | }); |
| 1234 | _ = try addZIRBinOp(mod, &for_scope.base, for_src, .store, index_ptr, zero); |
| 1235 | break :blk index_ptr; |
| 1236 | }; |
| 1237 | const array_ptr = try expr(mod, &for_scope.base, .ref, for_node.array_expr); |
| 1238 | const cond_src = tree.token_locs[for_node.array_expr.firstToken()].start; |
| 1239 | const len_ptr = try addZIRInst(mod, &for_scope.base, cond_src, zir.Inst.FieldPtr, .{ |
| 1240 | .object_ptr = array_ptr, |
| 1241 | .field_name = try addZIRInst(mod, &for_scope.base, cond_src, zir.Inst.Str, .{ .bytes = "len" }, .{}), |
| 1242 | }, .{}); |
| 1243 | |
| 1244 | var loop_scope: Scope.GenZIR = .{ |
| 1245 | .parent = &for_scope.base, |
| 1246 | .decl = for_scope.decl, |
| 1247 | .arena = for_scope.arena, |
| 1248 | .instructions = .{}, |
| 1249 | }; |
| 1250 | defer loop_scope.instructions.deinit(mod.gpa); |
| 1251 | |
| 1252 | var cond_scope: Scope.GenZIR = .{ |
| 1253 | .parent = &loop_scope.base, |
| 1254 | .decl = loop_scope.decl, |
| 1255 | .arena = loop_scope.arena, |
| 1256 | .instructions = .{}, |
| 1257 | }; |
| 1258 | defer cond_scope.instructions.deinit(mod.gpa); |
| 1259 | |
| 1260 | // check condition i < array_expr.len |
| 1261 | const index = try addZIRUnOp(mod, &cond_scope.base, cond_src, .deref, index_ptr); |
| 1262 | const len = try addZIRUnOp(mod, &cond_scope.base, cond_src, .deref, len_ptr); |
| 1263 | const cond = try addZIRBinOp(mod, &cond_scope.base, cond_src, .cmp_lt, index, len); |
| 1264 | |
| 1265 | const condbr = try addZIRInstSpecial(mod, &cond_scope.base, for_src, zir.Inst.CondBr, .{ |
| 1266 | .condition = cond, |
| 1267 | .then_body = undefined, // populated below |
| 1268 | .else_body = undefined, // populated below |
| 1269 | }, .{}); |
| 1270 | const cond_block = try addZIRInstBlock(mod, &loop_scope.base, for_src, .{ |
| 1271 | .instructions = try loop_scope.arena.dupe(*zir.Inst, cond_scope.instructions.items), |
| 1272 | }); |
| 1273 | |
| 1274 | // increment index variable |
| 1275 | const one = try addZIRInstConst(mod, &loop_scope.base, for_src, .{ |
| 1276 | .ty = Type.initTag(.usize), |
| 1277 | .val = Value.initTag(.one), |
| 1278 | }); |
| 1279 | const index_plus_one = try addZIRBinOp(mod, &loop_scope.base, for_src, .add, index, one); |
| 1280 | _ = try addZIRBinOp(mod, &loop_scope.base, for_src, .store, index_ptr, index_plus_one); |
| 1281 | |
| 1282 | // looping stuff |
| 1283 | const loop = try addZIRInstLoop(mod, &for_scope.base, for_src, .{ |
| 1284 | .instructions = try for_scope.arena.dupe(*zir.Inst, loop_scope.instructions.items), |
| 1285 | }); |
| 1286 | const for_block = try addZIRInstBlock(mod, scope, for_src, .{ |
| 1287 | .instructions = try scope.arena().dupe(*zir.Inst, for_scope.instructions.items), |
| 1288 | }); |
| 1289 | |
| 1290 | // while body |
| 1291 | const then_src = tree.token_locs[for_node.body.lastToken()].start; |
| 1292 | var then_scope: Scope.GenZIR = .{ |
| 1293 | .parent = &cond_scope.base, |
| 1294 | .decl = cond_scope.decl, |
| 1295 | .arena = cond_scope.arena, |
| 1296 | .instructions = .{}, |
| 1297 | }; |
| 1298 | defer then_scope.instructions.deinit(mod.gpa); |
| 1299 | |
| 1300 | // Most result location types can be forwarded directly; however |
| 1301 | // if we need to write to a pointer which has an inferred type, |
| 1302 | // proper type inference requires peer type resolution on the while's |
| 1303 | // branches. |
| 1304 | const branch_rl: ResultLoc = switch (rl) { |
| 1305 | .discard, .none, .ty, .ptr, .ref => rl, |
| 1306 | .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = for_block }, |
| 1307 | }; |
| 1308 | |
| 1309 | var index_scope: Scope.LocalPtr = undefined; |
| 1310 | const then_sub_scope = blk: { |
| 1311 | const payload = for_node.payload.castTag(.PointerIndexPayload).?; |
| 1312 | const is_ptr = payload.ptr_token != null; |
| 1313 | const value_name = tree.tokenSlice(payload.value_symbol.firstToken()); |
| 1314 | if (!mem.eql(u8, value_name, "_")) { |
| 1315 | return mod.failNode(&then_scope.base, payload.value_symbol, "TODO implement for value payload", .{}); |
| 1316 | } else if (is_ptr) { |
| 1317 | return mod.failTok(&then_scope.base, payload.ptr_token.?, "pointer modifier invalid on discard", .{}); |
| 1318 | } |
| 1319 | |
| 1320 | const index_symbol_node = payload.index_symbol orelse |
| 1321 | break :blk &then_scope.base; |
| 1322 | |
| 1323 | const index_name = tree.tokenSlice(index_symbol_node.firstToken()); |
| 1324 | if (mem.eql(u8, index_name, "_")) { |
| 1325 | break :blk &then_scope.base; |
| 1326 | } |
| 1327 | // TODO ensure this is const |
| 1328 | index_scope = .{ |
| 1329 | .parent = &then_scope.base, |
| 1330 | .gen_zir = &then_scope, |
| 1331 | .name = index_name, |
| 1332 | .ptr = index_ptr, |
| 1333 | }; |
| 1334 | break :blk &index_scope.base; |
| 1335 | }; |
| 1336 | |
| 1337 | const then_result = try expr(mod, then_sub_scope, branch_rl, for_node.body); |
| 1338 | if (!then_result.tag.isNoReturn()) { |
| 1339 | _ = try addZIRInst(mod, then_sub_scope, then_src, zir.Inst.Break, .{ |
| 1340 | .block = cond_block, |
| 1341 | .operand = then_result, |
| 1342 | }, .{}); |
| 1343 | } |
| 1344 | condbr.positionals.then_body = .{ |
| 1345 | .instructions = try then_scope.arena.dupe(*zir.Inst, then_scope.instructions.items), |
| 1346 | }; |
| 1347 | |
| 1348 | // else branch |
| 1349 | var else_scope: Scope.GenZIR = .{ |
| 1350 | .parent = &cond_scope.base, |
| 1351 | .decl = cond_scope.decl, |
| 1352 | .arena = cond_scope.arena, |
| 1353 | .instructions = .{}, |
| 1354 | }; |
| 1355 | defer else_scope.instructions.deinit(mod.gpa); |
| 1356 | |
| 1357 | if (for_node.@"else") |else_node| { |
| 1358 | const else_src = tree.token_locs[else_node.body.lastToken()].start; |
| 1359 | const else_result = try expr(mod, &else_scope.base, branch_rl, else_node.body); |
| 1360 | if (!else_result.tag.isNoReturn()) { |
| 1361 | _ = try addZIRInst(mod, &else_scope.base, else_src, zir.Inst.Break, .{ |
| 1362 | .block = for_block, |
| 1363 | .operand = else_result, |
| 1364 | }, .{}); |
| 1365 | } |
| 1366 | } else { |
| 1367 | const else_src = tree.token_locs[for_node.lastToken()].start; |
| 1368 | _ = try addZIRInst(mod, &else_scope.base, else_src, zir.Inst.BreakVoid, .{ |
| 1369 | .block = for_block, |
| 1370 | }, .{}); |
| 1371 | } |
| 1372 | condbr.positionals.else_body = .{ |
| 1373 | .instructions = try else_scope.arena.dupe(*zir.Inst, else_scope.instructions.items), |
| 1374 | }; |
| 1375 | return &for_block.base; |
| 1376 | } |
| 1377 | |
| 1201 | 1378 | fn ret(mod: *Module, scope: *Scope, cfe: *ast.Node.ControlFlowExpression) InnerError!*zir.Inst { |
| 1202 | 1379 | const tree = scope.tree(); |
| 1203 | 1380 | const src = tree.token_locs[cfe.ltoken].start; |