diff --git a/src/analysis.zig b/src/analysis.zig index 331003dd6..531ce3f16 100644 --- a/src/analysis.zig +++ b/src/analysis.zig @@ -799,6 +799,13 @@ pub fn resolveOptionalUnwrap(analyser: *Analyser, optional: Type) error{OutOfMem } } +pub fn resolveOrelseType(analyser: *Analyser, lhs: Type, rhs: Type) error{OutOfMemory}!?Type { + return switch (rhs.data) { + .optional => rhs, + else => try analyser.resolveOptionalUnwrap(lhs), + }; +} + /// Resolves the child type of an optional type pub fn resolveOptionalChildType(analyser: *Analyser, optional_type: Type) error{OutOfMemory}!?Type { _ = analyser; @@ -1470,7 +1477,10 @@ fn resolveTypeOfNodeUncached(analyser: *Analyser, node_handle: NodeWithHandle) e .deref => try analyser.resolveDerefType(base_type), .unwrap_optional => try analyser.resolveOptionalUnwrap(base_type), .array_access => try analyser.resolveBracketAccessType(base_type, .Single), - .@"orelse" => try analyser.resolveOptionalUnwrap(base_type), + .@"orelse" => { + const type_right = try analyser.resolveTypeOfNodeInternal(.{ .node = datas[node].rhs, .handle = handle }) orelse return null; + return try analyser.resolveOrelseType(base_type, type_right); + }, .@"catch" => try analyser.resolveUnwrapErrorUnionType(base_type, .payload), .@"try" => try analyser.resolveUnwrapErrorUnionType(base_type, .payload), .address_of => try analyser.resolveAddressOf(base_type), @@ -2122,10 +2132,13 @@ fn resolveTypeOfNodeUncached(analyser: *Analyser, node_handle: NodeWithHandle) e .switch_case, .switch_case_inline, .switch_range, + => {}, .@"continue", .@"break", .@"return", - => {}, + => { + return try Type.typeValFromIP(analyser, .noreturn_type); + }, .@"await", .@"suspend", diff --git a/tests/lsp_features/hover.zig b/tests/lsp_features/hover.zig index e8d00618b..d212121a4 100644 --- a/tests/lsp_features/hover.zig +++ b/tests/lsp_features/hover.zig @@ -554,6 +554,71 @@ test "optional" { \\ \\Go to [S](file:///test.zig#L1) ); + + try testHover( + \\const foo: ?i32 = 5; + \\const bar = foo orelse 0; + , + \\```zig + \\const bar = foo orelse 0 + \\``` + \\```zig + \\(i32) + \\``` + ); + + try testHover( + \\const foo: ?i32 = 5; + \\const bar = foo orelse foo; + , + \\```zig + \\const bar = foo orelse foo + \\``` + \\```zig + \\(?i32) + \\``` + ); + + try testHover( + \\const foo: ?i32 = 5; + \\const bar = foo orelse unreachable; + , + \\```zig + \\const bar = foo orelse unreachable + \\``` + \\```zig + \\(i32) + \\``` + ); + + try testHover( + \\fn foo(a: ?i32) void { + \\ const bar = a orelse return; + \\} + , + \\```zig + \\const bar = a orelse return + \\``` + \\```zig + \\(i32) + \\``` + ); + + try testHover( + \\fn foo() void { + \\ const array: [1]?i32 = [1]?i32{ 4 }; + \\ for (array) |elem| { + \\ const bar = elem orelse continue; + \\ } + \\} + , + \\```zig + \\const bar = elem orelse continue + \\``` + \\```zig + \\(i32) + \\``` + ); } test "error union" {