| ... | ... | @@ -4351,22 +4351,25 @@ fn namedFieldPtr( |
| 4351 | 4351 | field_name: []const u8, |
| 4352 | 4352 | field_name_src: LazySrcLoc, |
| 4353 | 4353 | ) InnerError!*Inst { |
| 4354 | const mod = sema.mod; |
| 4355 | const arena = sema.arena; |
| 4356 | |
| 4354 | 4357 | const elem_ty = switch (object_ptr.ty.zigTypeTag()) { |
| 4355 | 4358 | .Pointer => object_ptr.ty.elemType(), |
| 4356 | | else => return sema.mod.fail(&block.base, object_ptr.src, "expected pointer, found '{}'", .{object_ptr.ty}), |
| 4359 | else => return mod.fail(&block.base, object_ptr.src, "expected pointer, found '{}'", .{object_ptr.ty}), |
| 4357 | 4360 | }; |
| 4358 | 4361 | switch (elem_ty.zigTypeTag()) { |
| 4359 | 4362 | .Array => { |
| 4360 | 4363 | if (mem.eql(u8, field_name, "len")) { |
| 4361 | | return sema.mod.constInst(sema.arena, src, .{ |
| 4364 | return mod.constInst(arena, src, .{ |
| 4362 | 4365 | .ty = Type.initTag(.single_const_pointer_to_comptime_int), |
| 4363 | 4366 | .val = try Value.Tag.ref_val.create( |
| 4364 | | sema.arena, |
| 4365 | | try Value.Tag.int_u64.create(sema.arena, elem_ty.arrayLen()), |
| 4367 | arena, |
| 4368 | try Value.Tag.int_u64.create(arena, elem_ty.arrayLen()), |
| 4366 | 4369 | ), |
| 4367 | 4370 | }); |
| 4368 | 4371 | } else { |
| 4369 | | return sema.mod.fail( |
| 4372 | return mod.fail( |
| 4370 | 4373 | &block.base, |
| 4371 | 4374 | field_name_src, |
| 4372 | 4375 | "no member named '{s}' in '{}'", |
| ... | ... | @@ -4379,15 +4382,15 @@ fn namedFieldPtr( |
| 4379 | 4382 | switch (ptr_child.zigTypeTag()) { |
| 4380 | 4383 | .Array => { |
| 4381 | 4384 | if (mem.eql(u8, field_name, "len")) { |
| 4382 | | return sema.mod.constInst(sema.arena, src, .{ |
| 4385 | return mod.constInst(arena, src, .{ |
| 4383 | 4386 | .ty = Type.initTag(.single_const_pointer_to_comptime_int), |
| 4384 | 4387 | .val = try Value.Tag.ref_val.create( |
| 4385 | | sema.arena, |
| 4386 | | try Value.Tag.int_u64.create(sema.arena, ptr_child.arrayLen()), |
| 4388 | arena, |
| 4389 | try Value.Tag.int_u64.create(arena, ptr_child.arrayLen()), |
| 4387 | 4390 | ), |
| 4388 | 4391 | }); |
| 4389 | 4392 | } else { |
| 4390 | | return sema.mod.fail( |
| 4393 | return mod.fail( |
| 4391 | 4394 | &block.base, |
| 4392 | 4395 | field_name_src, |
| 4393 | 4396 | "no member named '{s}' in '{}'", |
| ... | ... | @@ -4402,7 +4405,7 @@ fn namedFieldPtr( |
| 4402 | 4405 | _ = try sema.resolveConstValue(block, object_ptr.src, object_ptr); |
| 4403 | 4406 | const result = try sema.analyzeLoad(block, src, object_ptr, object_ptr.src); |
| 4404 | 4407 | const val = result.value().?; |
| 4405 | | const child_type = try val.toType(sema.arena); |
| 4408 | const child_type = try val.toType(arena); |
| 4406 | 4409 | switch (child_type.zigTypeTag()) { |
| 4407 | 4410 | .ErrorSet => { |
| 4408 | 4411 | // TODO resolve inferred error sets |
| ... | ... | @@ -4416,42 +4419,87 @@ fn namedFieldPtr( |
| 4416 | 4419 | break :blk name; |
| 4417 | 4420 | } |
| 4418 | 4421 | } |
| 4419 | | return sema.mod.fail(&block.base, src, "no error named '{s}' in '{}'", .{ |
| 4422 | return mod.fail(&block.base, src, "no error named '{s}' in '{}'", .{ |
| 4420 | 4423 | field_name, |
| 4421 | 4424 | child_type, |
| 4422 | 4425 | }); |
| 4423 | | } else (try sema.mod.getErrorValue(field_name)).key; |
| 4426 | } else (try mod.getErrorValue(field_name)).key; |
| 4424 | 4427 | |
| 4425 | | return sema.mod.constInst(sema.arena, src, .{ |
| 4426 | | .ty = try sema.mod.simplePtrType(sema.arena, child_type, false, .One), |
| 4428 | return mod.constInst(arena, src, .{ |
| 4429 | .ty = try mod.simplePtrType(arena, child_type, false, .One), |
| 4427 | 4430 | .val = try Value.Tag.ref_val.create( |
| 4428 | | sema.arena, |
| 4429 | | try Value.Tag.@"error".create(sema.arena, .{ |
| 4431 | arena, |
| 4432 | try Value.Tag.@"error".create(arena, .{ |
| 4430 | 4433 | .name = name, |
| 4431 | 4434 | }), |
| 4432 | 4435 | ), |
| 4433 | 4436 | }); |
| 4434 | 4437 | }, |
| 4435 | | .Struct => { |
| 4436 | | const container_scope = child_type.getContainerScope(); |
| 4437 | | if (sema.mod.lookupDeclName(&container_scope.base, field_name)) |decl| { |
| 4438 | | // TODO if !decl.is_pub and inDifferentFiles() "{} is private" |
| 4439 | | return sema.analyzeDeclRef(block, src, decl); |
| 4440 | | } |
| 4438 | .Struct, .Opaque, .Union => { |
| 4439 | if (child_type.getContainerScope()) |container_scope| { |
| 4440 | if (mod.lookupDeclName(&container_scope.base, field_name)) |decl| { |
| 4441 | // TODO if !decl.is_pub and inDifferentFiles() "{} is private" |
| 4442 | return sema.analyzeDeclRef(block, src, decl); |
| 4443 | } |
| 4441 | 4444 | |
| 4442 | | if (container_scope.file_scope == sema.mod.root_scope) { |
| 4443 | | return sema.mod.fail(&block.base, src, "root source file has no member called '{s}'", .{field_name}); |
| 4444 | | } else { |
| 4445 | | return sema.mod.fail(&block.base, src, "container '{}' has no member called '{s}'", .{ child_type, field_name }); |
| 4445 | // TODO this will give false positives for structs inside the root file |
| 4446 | if (container_scope.file_scope == mod.root_scope) { |
| 4447 | return mod.fail( |
| 4448 | &block.base, |
| 4449 | src, |
| 4450 | "root source file has no member named '{s}'", |
| 4451 | .{field_name}, |
| 4452 | ); |
| 4453 | } |
| 4454 | } |
| 4455 | // TODO add note: declared here |
| 4456 | const kw_name = switch (child_type.zigTypeTag()) { |
| 4457 | .Struct => "struct", |
| 4458 | .Opaque => "opaque", |
| 4459 | .Union => "union", |
| 4460 | else => unreachable, |
| 4461 | }; |
| 4462 | return mod.fail(&block.base, src, "{s} '{}' has no member named '{s}'", .{ |
| 4463 | kw_name, child_type, field_name, |
| 4464 | }); |
| 4465 | }, |
| 4466 | .Enum => { |
| 4467 | if (child_type.getContainerScope()) |container_scope| { |
| 4468 | if (mod.lookupDeclName(&container_scope.base, field_name)) |decl| { |
| 4469 | // TODO if !decl.is_pub and inDifferentFiles() "{} is private" |
| 4470 | return sema.analyzeDeclRef(block, src, decl); |
| 4471 | } |
| 4446 | 4472 | } |
| 4473 | const maybe_field_index: ?usize = switch (child_type.tag()) { |
| 4474 | .enum_full, .enum_nonexhaustive => blk: { |
| 4475 | const enum_full = child_type.castTag(.enum_full).?.data; |
| 4476 | break :blk enum_full.fields.getIndex(field_name); |
| 4477 | }, |
| 4478 | .enum_simple => blk: { |
| 4479 | const enum_simple = child_type.castTag(.enum_simple).?.data; |
| 4480 | break :blk enum_simple.fields.getIndex(field_name); |
| 4481 | }, |
| 4482 | else => unreachable, |
| 4483 | }; |
| 4484 | const field_index = maybe_field_index orelse { |
| 4485 | return mod.fail(&block.base, src, "enum '{}' has no member named '{s}'", .{ |
| 4486 | child_type, field_name, |
| 4487 | }); |
| 4488 | }; |
| 4489 | const field_index_u32 = @intCast(u32, field_index); |
| 4490 | const enum_val = try Value.Tag.enum_field_index.create(arena, field_index_u32); |
| 4491 | return mod.constInst(arena, src, .{ |
| 4492 | .ty = try mod.simplePtrType(arena, child_type, false, .One), |
| 4493 | .val = try Value.Tag.ref_val.create(arena, enum_val), |
| 4494 | }); |
| 4447 | 4495 | }, |
| 4448 | | else => return sema.mod.fail(&block.base, src, "type '{}' does not support field access", .{child_type}), |
| 4496 | else => return mod.fail(&block.base, src, "type '{}' has no members", .{child_type}), |
| 4449 | 4497 | } |
| 4450 | 4498 | }, |
| 4451 | 4499 | .Struct => return sema.analyzeStructFieldPtr(block, src, object_ptr, field_name, field_name_src, elem_ty), |
| 4452 | 4500 | else => {}, |
| 4453 | 4501 | } |
| 4454 | | return sema.mod.fail(&block.base, src, "type '{}' does not support field access", .{elem_ty}); |
| 4502 | return mod.fail(&block.base, src, "type '{}' does not support field access", .{elem_ty}); |
| 4455 | 4503 | } |
| 4456 | 4504 | |
| 4457 | 4505 | fn analyzeStructFieldPtr( |