| ... | ... | @@ -2127,6 +2127,50 @@ fn failWithUseOfAsync(sema: *Sema, block: *Block, src: LazySrcLoc) CompileError |
| 2127 | 2127 | return sema.failWithOwnedErrorMsg(msg); |
| 2128 | 2128 | } |
| 2129 | 2129 | |
| 2130 | fn failWithInvalidFieldAccess(sema: *Sema, block: *Block, src: LazySrcLoc, object_ty: Type, field_name: []const u8) CompileError { |
| 2131 | const inner_ty = if (object_ty.isSinglePointer()) object_ty.childType() else object_ty; |
| 2132 | |
| 2133 | if (inner_ty.zigTypeTag() == .Optional) opt: { |
| 2134 | var buf: Type.Payload.ElemType = undefined; |
| 2135 | const child_ty = inner_ty.optionalChild(&buf); |
| 2136 | if (!typeSupportsFieldAccess(child_ty, field_name)) break :opt; |
| 2137 | const msg = msg: { |
| 2138 | const msg = try sema.errMsg(block, src, "optional type '{}' does not support field access", .{object_ty.fmt(sema.mod)}); |
| 2139 | errdefer msg.destroy(sema.gpa); |
| 2140 | try sema.errNote(block, src, msg, "consider using '.?', 'orelse', or 'if'", .{}); |
| 2141 | break :msg msg; |
| 2142 | }; |
| 2143 | return sema.failWithOwnedErrorMsg(msg); |
| 2144 | } else if (inner_ty.zigTypeTag() == .ErrorUnion) err: { |
| 2145 | const child_ty = inner_ty.errorUnionPayload(); |
| 2146 | if (!typeSupportsFieldAccess(child_ty, field_name)) break :err; |
| 2147 | const msg = msg: { |
| 2148 | const msg = try sema.errMsg(block, src, "error union type '{}' does not support field access", .{object_ty.fmt(sema.mod)}); |
| 2149 | errdefer msg.destroy(sema.gpa); |
| 2150 | try sema.errNote(block, src, msg, "consider using 'try', 'catch', or 'if'", .{}); |
| 2151 | break :msg msg; |
| 2152 | }; |
| 2153 | return sema.failWithOwnedErrorMsg(msg); |
| 2154 | } |
| 2155 | return sema.fail(block, src, "type '{}' does not support field access", .{object_ty.fmt(sema.mod)}); |
| 2156 | } |
| 2157 | |
| 2158 | fn typeSupportsFieldAccess(ty: Type, field_name: []const u8) bool { |
| 2159 | switch (ty.zigTypeTag()) { |
| 2160 | .Array => return mem.eql(u8, field_name, "len"), |
| 2161 | .Pointer => { |
| 2162 | const ptr_info = ty.ptrInfo().data; |
| 2163 | if (ptr_info.size == .Slice) { |
| 2164 | return mem.eql(u8, field_name, "ptr") or mem.eql(u8, field_name, "len"); |
| 2165 | } else if (ptr_info.pointee_type.zigTypeTag() == .Array) { |
| 2166 | return mem.eql(u8, field_name, "len"); |
| 2167 | } else return false; |
| 2168 | }, |
| 2169 | .Type, .Struct, .Union => return true, |
| 2170 | else => return false, |
| 2171 | } |
| 2172 | } |
| 2173 | |
| 2130 | 2174 | /// We don't return a pointer to the new error note because the pointer |
| 2131 | 2175 | /// becomes invalid when you add another one. |
| 2132 | 2176 | fn errNote( |
| ... | ... | @@ -23321,7 +23365,7 @@ fn fieldVal( |
| 23321 | 23365 | }, |
| 23322 | 23366 | else => {}, |
| 23323 | 23367 | } |
| 23324 | | return sema.fail(block, src, "type '{}' does not support field access", .{object_ty.fmt(sema.mod)}); |
| 23368 | return sema.failWithInvalidFieldAccess(block, src, object_ty, field_name); |
| 23325 | 23369 | } |
| 23326 | 23370 | |
| 23327 | 23371 | fn fieldPtr( |
| ... | ... | @@ -23535,7 +23579,7 @@ fn fieldPtr( |
| 23535 | 23579 | }, |
| 23536 | 23580 | else => {}, |
| 23537 | 23581 | } |
| 23538 | | return sema.fail(block, src, "type '{}' does not support field access", .{object_ty.fmt(sema.mod)}); |
| 23582 | return sema.failWithInvalidFieldAccess(block, src, object_ty, field_name); |
| 23539 | 23583 | } |
| 23540 | 23584 | |
| 23541 | 23585 | fn fieldCallBind( |