authorgravatar for jacoblevgw@gmail.comJacob G-W <jacoblevgw@gmail.com> 2021-06-19 21:09:26-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-06-21 17:03:03-07:00
logb83b3883ba0b5e965f8f7f1298c77c6d766741af
tree5b6d0c9a9819721a862baa65283794adf6acf237
parent641ecc260f43ffb2398acb80cbd141535dbbb03d

stage2 AstGen: fix lots of bugs and catch more errors

Gotta catch 'em all! also simplify identifier( logic

1 files changed, 134 insertions(+), 61 deletions(-)

src/AstGen.zig+134-61
......@@ -2139,10 +2139,7 @@ fn genDefers(
21392139 .defer_error => {
21402140 const defer_scope = scope.cast(Scope.Defer).?;
21412141 scope = defer_scope.parent;
2142 // TODO add this back when we have more errdefer support
2143 // right now it is making stuff not get evaluated which causes
2144 // unused vars.
2145 // if (err_code == .none) continue;
2142 if (err_code == .none) continue;
21462143 const expr_node = node_datas[defer_scope.defer_node].rhs;
21472144 const prev_in_defer = gz.in_defer;
21482145 gz.in_defer = true;
......@@ -2168,12 +2165,26 @@ fn checkUsed(
21682165 .gen_zir => scope = scope.cast(GenZir).?.parent,
21692166 .local_val => {
21702167 const s = scope.cast(Scope.LocalVal).?;
2171 if (!s.used) return astgen.failTok(s.token_src, "unused local constant", .{});
2168 switch (s.used) {
2169 .used => {},
2170 .fn_param => return astgen.failTok(s.token_src, "unused function parameter", .{}),
2171 .constant => return astgen.failTok(s.token_src, "unused local constant", .{}),
2172 .variable => unreachable,
2173 .loop_index => unreachable,
2174 .capture => return astgen.failTok(s.token_src, "unused capture", .{}),
2175 }
21722176 scope = s.parent;
21732177 },
21742178 .local_ptr => {
21752179 const s = scope.cast(Scope.LocalPtr).?;
2176 if (!s.used) return astgen.failTok(s.token_src, "unused local variable", .{});
2180 switch (s.used) {
2181 .used => {},
2182 .fn_param => unreachable,
2183 .constant => return astgen.failTok(s.token_src, "unused local constant", .{}),
2184 .variable => return astgen.failTok(s.token_src, "unused local variable", .{}),
2185 .loop_index => return astgen.failTok(s.token_src, "unused loop index capture", .{}),
2186 .capture => unreachable,
2187 }
21772188 scope = s.parent;
21782189 },
21792190 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent,
......@@ -2303,6 +2314,7 @@ fn varDecl(
23032314 .name = ident_name,
23042315 .inst = init_inst,
23052316 .token_src = name_token,
2317 .used = .constant,
23062318 };
23072319 return &sub_scope.base;
23082320 }
......@@ -2370,6 +2382,7 @@ fn varDecl(
23702382 .name = ident_name,
23712383 .inst = init_inst,
23722384 .token_src = name_token,
2385 .used = .constant,
23732386 };
23742387 return &sub_scope.base;
23752388 }
......@@ -2399,6 +2412,7 @@ fn varDecl(
23992412 .ptr = init_scope.rl_ptr,
24002413 .token_src = name_token,
24012414 .maybe_comptime = true,
2415 .used = .constant,
24022416 };
24032417 return &sub_scope.base;
24042418 },
......@@ -2455,6 +2469,7 @@ fn varDecl(
24552469 .ptr = var_data.alloc,
24562470 .token_src = name_token,
24572471 .maybe_comptime = is_comptime,
2472 .used = .variable,
24582473 };
24592474 return &sub_scope.base;
24602475 },
......@@ -2943,6 +2958,10 @@ fn fnDecl(
29432958 const name_token = param.name_token orelse {
29442959 return astgen.failNode(param.type_expr, "missing parameter name", .{});
29452960 };
2961 if (param.type_expr != 0)
2962 _ = try typeExpr(&fn_gz, params_scope, param.type_expr);
2963 if (mem.eql(u8, "_", tree.tokenSlice(name_token)))
2964 continue;
29462965 const param_name = try astgen.identAsString(name_token);
29472966 // Create an arg instruction. This is needed to emit a semantic analysis
29482967 // error for shadowing decls.
......@@ -2955,17 +2974,19 @@ fn fnDecl(
29552974 .name = param_name,
29562975 .inst = arg_inst,
29572976 .token_src = name_token,
2958 // TODO make function paramater have different message instead of unused constant
2977 .used = .fn_param,
29592978 };
29602979 params_scope = &sub_scope.base;
29612980
29622981 // Additionally put the param name into `string_bytes` and reference it with
29632982 // `extra` so that we have access to the data in codegen, for debug info.
29642983 const str_index = try astgen.identAsString(name_token);
2965 astgen.extra.appendAssumeCapacity(str_index);
2984 try astgen.extra.append(astgen.gpa, str_index);
29662985 }
2986 _ = try typeExpr(&fn_gz, params_scope, fn_proto.ast.return_type);
29672987
29682988 _ = try expr(&fn_gz, params_scope, .none, body_node);
2989 try checkUsed(gz, &fn_gz.base, params_scope);
29692990 }
29702991
29712992 const need_implicit_ret = blk: {
......@@ -3396,7 +3417,6 @@ fn structDeclInner(
33963417 };
33973418 defer block_scope.instructions.deinit(gpa);
33983419
3399 // TODO should we change this to scope in other places too?
34003420 var namespace: Scope.Namespace = .{ .parent = scope };
34013421 defer namespace.decls.deinit(gpa);
34023422
......@@ -3659,7 +3679,7 @@ fn unionDeclInner(
36593679 };
36603680 defer block_scope.instructions.deinit(gpa);
36613681
3662 var namespace: Scope.Namespace = .{ .parent = &gz.base };
3682 var namespace: Scope.Namespace = .{ .parent = scope };
36633683 defer namespace.decls.deinit(gpa);
36643684
36653685 var wip_decls: WipDecls = .{};
......@@ -4060,7 +4080,7 @@ fn containerDecl(
40604080 };
40614081 defer block_scope.instructions.deinit(gpa);
40624082
4063 var namespace: Scope.Namespace = .{ .parent = &gz.base };
4083 var namespace: Scope.Namespace = .{ .parent = scope };
40644084 defer namespace.decls.deinit(gpa);
40654085
40664086 var wip_decls: WipDecls = .{};
......@@ -4287,7 +4307,7 @@ fn containerDecl(
42874307 return rvalue(gz, scope, rl, gz.indexToRef(decl_inst), node);
42884308 },
42894309 .keyword_opaque => {
4290 var namespace: Scope.Namespace = .{ .parent = &gz.base };
4310 var namespace: Scope.Namespace = .{ .parent = scope };
42914311 defer namespace.decls.deinit(gpa);
42924312
42934313 var wip_decls: WipDecls = .{};
......@@ -4622,12 +4642,15 @@ fn orelseCatchExpr(
46224642 .name = err_name,
46234643 .inst = try then_scope.addUnNode(unwrap_code_op, operand, node),
46244644 .token_src = payload,
4645 .used = .capture,
46254646 };
46264647 break :blk &err_val_scope.base;
46274648 };
46284649
46294650 block_scope.break_count += 1;
46304651 const then_result = try expr(&then_scope, then_sub_scope, block_scope.break_result_loc, rhs);
4652 try checkUsed(parent_gz, &then_scope.base, then_sub_scope);
4653
46314654 // We hold off on the break instructions as well as copying the then/else
46324655 // instructions into place until we know whether to keep store_to_block_ptr
46334656 // instructions or not.
......@@ -4900,27 +4923,38 @@ fn ifExpr(
49004923 var payload_val_scope: Scope.LocalVal = undefined;
49014924
49024925 const then_sub_scope = s: {
4903 if (if_full.error_token) |error_token| {
4904 const tag: Zir.Inst.Tag = if (payload_is_ref)
4905 .err_union_payload_unsafe_ptr
4906 else
4907 .err_union_payload_unsafe;
4908 const payload_inst = try then_scope.addUnNode(tag, cond.inst, node);
4909 const ident_name = try astgen.identAsString(error_token);
4910 payload_val_scope = .{
4911 .parent = &then_scope.base,
4912 .gen_zir = &then_scope,
4913 .name = ident_name,
4914 .inst = payload_inst,
4915 .token_src = error_token,
4916 };
4917 break :s &payload_val_scope.base;
4926 if (if_full.error_token != null) {
4927 if (if_full.payload_token) |payload_token| {
4928 const tag: Zir.Inst.Tag = if (payload_is_ref)
4929 .err_union_payload_unsafe_ptr
4930 else
4931 .err_union_payload_unsafe;
4932 const payload_inst = try then_scope.addUnNode(tag, cond.inst, node);
4933 const token_name_index = payload_token + @boolToInt(payload_is_ref);
4934 const ident_name = try astgen.identAsString(token_name_index);
4935 const token_name_str = tree.tokenSlice(token_name_index);
4936 if (mem.eql(u8, "_", token_name_str))
4937 break :s &then_scope.base;
4938 payload_val_scope = .{
4939 .parent = &then_scope.base,
4940 .gen_zir = &then_scope,
4941 .name = ident_name,
4942 .inst = payload_inst,
4943 .token_src = payload_token,
4944 .used = .capture,
4945 };
4946 break :s &payload_val_scope.base;
4947 } else {
4948 break :s &then_scope.base;
4949 }
49184950 } else if (if_full.payload_token) |payload_token| {
49194951 const ident_token = if (payload_is_ref) payload_token + 1 else payload_token;
49204952 const tag: Zir.Inst.Tag = if (payload_is_ref)
49214953 .optional_payload_unsafe_ptr
49224954 else
49234955 .optional_payload_unsafe;
4956 if (mem.eql(u8, "_", tree.tokenSlice(ident_token)))
4957 break :s &then_scope.base;
49244958 const payload_inst = try then_scope.addUnNode(tag, cond.inst, node);
49254959 const ident_name = try astgen.identAsString(ident_token);
49264960 payload_val_scope = .{
......@@ -4929,6 +4963,7 @@ fn ifExpr(
49294963 .name = ident_name,
49304964 .inst = payload_inst,
49314965 .token_src = ident_token,
4966 .used = .capture,
49324967 };
49334968 break :s &payload_val_scope.base;
49344969 } else {
......@@ -4938,6 +4973,7 @@ fn ifExpr(
49384973
49394974 block_scope.break_count += 1;
49404975 const then_result = try expr(&then_scope, then_sub_scope, block_scope.break_result_loc, if_full.ast.then_expr);
4976 try checkUsed(parent_gz, &then_scope.base, then_sub_scope);
49414977 // We hold off on the break instructions as well as copying the then/else
49424978 // instructions into place until we know whether to keep store_to_block_ptr
49434979 // instructions or not.
......@@ -4959,21 +4995,27 @@ fn ifExpr(
49594995 .err_union_code;
49604996 const payload_inst = try else_scope.addUnNode(tag, cond.inst, node);
49614997 const ident_name = try astgen.identAsString(error_token);
4998 const error_token_str = tree.tokenSlice(error_token);
4999 if (mem.eql(u8, "_", error_token_str))
5000 break :s &else_scope.base;
49625001 payload_val_scope = .{
49635002 .parent = &else_scope.base,
49645003 .gen_zir = &else_scope,
49655004 .name = ident_name,
49665005 .inst = payload_inst,
49675006 .token_src = error_token,
5007 .used = .capture,
49685008 };
49695009 break :s &payload_val_scope.base;
49705010 } else {
49715011 break :s &else_scope.base;
49725012 }
49735013 };
5014 const e = try expr(&else_scope, sub_scope, block_scope.break_result_loc, else_node);
5015 try checkUsed(parent_gz, &else_scope.base, sub_scope);
49745016 break :blk .{
49755017 .src = else_node,
4976 .result = try expr(&else_scope, sub_scope, block_scope.break_result_loc, else_node),
5018 .result = e,
49775019 };
49785020 } else .{
49795021 .src = if_full.ast.then_expr,
......@@ -5161,21 +5203,29 @@ fn whileExpr(
51615203 var payload_val_scope: Scope.LocalVal = undefined;
51625204
51635205 const then_sub_scope = s: {
5164 if (while_full.error_token) |error_token| {
5165 const tag: Zir.Inst.Tag = if (payload_is_ref)
5166 .err_union_payload_unsafe_ptr
5167 else
5168 .err_union_payload_unsafe;
5169 const payload_inst = try then_scope.addUnNode(tag, cond.inst, node);
5170 const ident_name = try astgen.identAsString(error_token);
5171 payload_val_scope = .{
5172 .parent = &then_scope.base,
5173 .gen_zir = &then_scope,
5174 .name = ident_name,
5175 .inst = payload_inst,
5176 .token_src = error_token,
5177 };
5178 break :s &payload_val_scope.base;
5206 if (while_full.error_token != null) {
5207 if (while_full.payload_token) |payload_token| {
5208 const tag: Zir.Inst.Tag = if (payload_is_ref)
5209 .err_union_payload_unsafe_ptr
5210 else
5211 .err_union_payload_unsafe;
5212 const payload_inst = try then_scope.addUnNode(tag, cond.inst, node);
5213 const ident_token = if (payload_is_ref) payload_token + 1 else payload_token;
5214 if (mem.eql(u8, "_", tree.tokenSlice(ident_token)))
5215 break :s &then_scope.base;
5216 const ident_name = try astgen.identAsString(payload_token + @boolToInt(payload_is_ref));
5217 payload_val_scope = .{
5218 .parent = &then_scope.base,
5219 .gen_zir = &then_scope,
5220 .name = ident_name,
5221 .inst = payload_inst,
5222 .token_src = payload_token,
5223 .used = .capture,
5224 };
5225 break :s &payload_val_scope.base;
5226 } else {
5227 break :s &then_scope.base;
5228 }
51795229 } else if (while_full.payload_token) |payload_token| {
51805230 const ident_token = if (payload_is_ref) payload_token + 1 else payload_token;
51815231 const tag: Zir.Inst.Tag = if (payload_is_ref)
......@@ -5184,12 +5234,15 @@ fn whileExpr(
51845234 .optional_payload_unsafe;
51855235 const payload_inst = try then_scope.addUnNode(tag, cond.inst, node);
51865236 const ident_name = try astgen.identAsString(ident_token);
5237 if (mem.eql(u8, "_", tree.tokenSlice(ident_token)))
5238 break :s &then_scope.base;
51875239 payload_val_scope = .{
51885240 .parent = &then_scope.base,
51895241 .gen_zir = &then_scope,
51905242 .name = ident_name,
51915243 .inst = payload_inst,
51925244 .token_src = ident_token,
5245 .used = .capture,
51935246 };
51945247 break :s &payload_val_scope.base;
51955248 } else {
......@@ -5199,6 +5252,7 @@ fn whileExpr(
51995252
52005253 loop_scope.break_count += 1;
52015254 const then_result = try expr(&then_scope, then_sub_scope, loop_scope.break_result_loc, while_full.ast.then_expr);
5255 try checkUsed(parent_gz, &then_scope.base, then_sub_scope);
52025256
52035257 var else_scope = parent_gz.makeSubBlock(&continue_scope.base);
52045258 defer else_scope.instructions.deinit(astgen.gpa);
......@@ -5217,21 +5271,26 @@ fn whileExpr(
52175271 .err_union_code;
52185272 const payload_inst = try else_scope.addUnNode(tag, cond.inst, node);
52195273 const ident_name = try astgen.identAsString(error_token);
5274 if (mem.eql(u8, tree.tokenSlice(error_token), "_"))
5275 break :s &else_scope.base;
52205276 payload_val_scope = .{
52215277 .parent = &else_scope.base,
52225278 .gen_zir = &else_scope,
52235279 .name = ident_name,
52245280 .inst = payload_inst,
52255281 .token_src = error_token,
5282 .used = .capture,
52265283 };
52275284 break :s &payload_val_scope.base;
52285285 } else {
52295286 break :s &else_scope.base;
52305287 }
52315288 };
5289 const e = try expr(&else_scope, sub_scope, loop_scope.break_result_loc, else_node);
5290 try checkUsed(parent_gz, &else_scope.base, sub_scope);
52325291 break :blk .{
52335292 .src = else_node,
5234 .result = try expr(&else_scope, sub_scope, loop_scope.break_result_loc, else_node),
5293 .result = e,
52355294 };
52365295 } else .{
52375296 .src = while_full.ast.then_expr,
......@@ -5362,6 +5421,7 @@ fn forExpr(
53625421 .name = name_str_index,
53635422 .inst = payload_inst,
53645423 .token_src = ident,
5424 .used = .capture,
53655425 };
53665426 payload_sub_scope = &payload_val_scope.base;
53675427 } else if (is_ptr) {
......@@ -5385,12 +5445,14 @@ fn forExpr(
53855445 .ptr = index_ptr,
53865446 .token_src = index_token,
53875447 .maybe_comptime = is_inline,
5448 .used = .loop_index,
53885449 };
53895450 break :blk &index_scope.base;
53905451 };
53915452
53925453 loop_scope.break_count += 1;
53935454 const then_result = try expr(&then_scope, then_sub_scope, loop_scope.break_result_loc, for_full.ast.then_expr);
5455 try checkUsed(parent_gz, &then_scope.base, then_sub_scope);
53945456
53955457 var else_scope = parent_gz.makeSubBlock(&cond_scope.base);
53965458 defer else_scope.instructions.deinit(astgen.gpa);
......@@ -5631,10 +5693,12 @@ fn switchExpr(
56315693 .name = capture_name,
56325694 .inst = capture,
56335695 .token_src = payload_token,
5696 .used = .capture,
56345697 };
56355698 break :blk &capture_val_scope.base;
56365699 };
56375700 const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr);
5701 try checkUsed(parent_gz, &case_scope.base, sub_scope);
56385702 if (!parent_gz.refIsNoReturn(case_result)) {
56395703 block_scope.break_count += 1;
56405704 _ = try case_scope.addBreak(.@"break", switch_block, case_result);
......@@ -5723,6 +5787,7 @@ fn switchExpr(
57235787 .name = capture_name,
57245788 .inst = capture,
57255789 .token_src = payload_token,
5790 .used = .capture,
57265791 };
57275792 break :blk &capture_val_scope.base;
57285793 };
......@@ -5756,6 +5821,7 @@ fn switchExpr(
57565821 }
57575822
57585823 const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr);
5824 try checkUsed(parent_gz, &case_scope.base, sub_scope);
57595825 if (!parent_gz.refIsNoReturn(case_result)) {
57605826 block_scope.break_count += 1;
57615827 _ = try case_scope.addBreak(.@"break", switch_block, case_result);
......@@ -5769,6 +5835,7 @@ fn switchExpr(
57695835 const item_node = case.ast.values[0];
57705836 const item_inst = try comptimeExpr(parent_gz, scope, item_rl, item_node);
57715837 const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr);
5838 try checkUsed(parent_gz, &case_scope.base, sub_scope);
57725839 if (!parent_gz.refIsNoReturn(case_result)) {
57735840 block_scope.break_count += 1;
57745841 _ = try case_scope.addBreak(.@"break", switch_block, case_result);
......@@ -6147,24 +6214,21 @@ fn identifier(
61476214 while (true) switch (s.tag) {
61486215 .local_val => {
61496216 const local_val = s.cast(Scope.LocalVal).?;
6217
61506218 if (local_val.name == name_str_index) {
6151 local_val.used = true;
6152 }
6153 if (hit_namespace) {
6154 // captures of non-locals need to be emitted as decl_val or decl_ref
6155 // This *might* be capturable depending on if it is comptime known
6156 s = local_val.parent;
6157 continue;
6158 }
6159 if (local_val.name == name_str_index) {
6160 return rvalue(gz, scope, rl, local_val.inst, ident);
6219 local_val.used = .used;
6220 // Captures of non-locals need to be emitted as decl_val or decl_ref.
6221 // This *might* be capturable depending on if it is comptime known.
6222 if (!hit_namespace) {
6223 return rvalue(gz, scope, rl, local_val.inst, ident);
6224 }
61616225 }
61626226 s = local_val.parent;
61636227 },
61646228 .local_ptr => {
61656229 const local_ptr = s.cast(Scope.LocalPtr).?;
61666230 if (local_ptr.name == name_str_index) {
6167 local_ptr.used = true;
6231 local_ptr.used = .used;
61686232 if (hit_namespace) {
61696233 if (local_ptr.maybe_comptime)
61706234 break
......@@ -6456,7 +6520,7 @@ fn asmExpr(
64566520 .local_val => {
64576521 const local_val = s.cast(Scope.LocalVal).?;
64586522 if (local_val.name == str_index) {
6459 local_val.used = true;
6523 local_val.used = .used;
64606524 break;
64616525 }
64626526 s = local_val.parent;
......@@ -6464,7 +6528,7 @@ fn asmExpr(
64646528 .local_ptr => {
64656529 const local_ptr = s.cast(Scope.LocalPtr).?;
64666530 if (local_ptr.name == str_index) {
6467 local_ptr.used = true;
6531 local_ptr.used = .used;
64686532 break;
64696533 }
64706534 s = local_ptr.parent;
......@@ -6815,7 +6879,7 @@ fn builtinCall(
68156879 .local_val => {
68166880 const local_val = s.cast(Scope.LocalVal).?;
68176881 if (local_val.name == decl_name) {
6818 local_val.used = true;
6882 local_val.used = .used;
68196883 break;
68206884 }
68216885 s = local_val.parent;
......@@ -6825,7 +6889,7 @@ fn builtinCall(
68256889 if (local_ptr.name == decl_name) {
68266890 if (!local_ptr.maybe_comptime)
68276891 return astgen.failNode(params[0], "unable to export runtime-known value", .{});
6828 local_ptr.used = true;
6892 local_ptr.used = .used;
68296893 break;
68306894 }
68316895 s = local_ptr.parent;
......@@ -8394,6 +8458,15 @@ const Scope = struct {
83948458 top,
83958459 };
83968460
8461 // either .used or the type of the var/constant
8462 const Used = enum {
8463 fn_param,
8464 constant,
8465 variable,
8466 loop_index,
8467 capture,
8468 used,
8469 };
83978470 /// This is always a `const` local and importantly the `inst` is a value type, not a pointer.
83988471 /// This structure lives as long as the AST generation of the Block
83998472 /// node that contains the variable.
......@@ -8409,7 +8482,7 @@ const Scope = struct {
84098482 /// String table index.
84108483 name: u32,
84118484 /// has this variable been referenced?
8412 used: bool = false,
8485 used: Used,
84138486 };
84148487
84158488 /// This could be a `const` or `var` local. It has a pointer instead of a value.
......@@ -8429,7 +8502,7 @@ const Scope = struct {
84298502 /// true means we find out during Sema whether the value is comptime. false means it is already known at AstGen the value is runtime-known.
84308503 maybe_comptime: bool,
84318504 /// has this variable been referenced?
8432 used: bool = false,
8505 used: Used,
84338506 };
84348507
84358508 const Defer = struct {