Skip to content

Commit c72a34a

Browse files
committed
Fix result of catch null and catch return null
1 parent b35e0d2 commit c72a34a

File tree

4 files changed

+36
-6
lines changed

4 files changed

+36
-6
lines changed

duchain/expressionvisitor.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1677,7 +1677,22 @@ VisitResult ExpressionVisitor::visitCatch(const ZigNode &node, const ZigNode &pa
16771677
v.startVisiting(lhs, node);
16781678
// TODO: Check that lhs and rhs are compatable
16791679
if (auto errorType = v.lastType().dynamicCast<ErrorType>()) {
1680-
encounter(errorType->baseType());
1680+
ZigNode rhs = {node.ast, data.rhs};
1681+
ExpressionVisitor v2(this);
1682+
v2.startVisiting(rhs, node);
1683+
1684+
auto baseType = errorType->baseType();
1685+
1686+
// Make type optional if it has catch null but not catch return null
1687+
if (auto builtin = v2.exprType().dynamicCast<BuiltinType>()) {
1688+
if (!v2.returnType() && builtin->isNull() && !baseType.dynamicCast<OptionalType>()) {
1689+
OptionalType::Ptr result(new OptionalType());
1690+
result->setBaseType(baseType);
1691+
encounter(result);
1692+
return Continue;
1693+
}
1694+
}
1695+
encounter(baseType);
16811696
} else {
16821697
encounterUnknown(); // TODO: Show error?
16831698
}

duchain/expressionvisitor.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "zignode.h"
1616
#include "zigdebug.h"
1717
#include "parsesession.h"
18+
#include "types/builtintype.h"
1819

1920
namespace Zig
2021
{
@@ -167,6 +168,18 @@ class KDEVZIGDUCHAIN_EXPORT ExpressionVisitor : public KDevelop::DynamicLanguage
167168
return m_breakType;
168169
}
169170

171+
/**
172+
* If a break or return was encountered this returns the BuiltinType "void"
173+
* otherwise, return the result of the last expression encountered.
174+
*/
175+
const KDevelop::AbstractType::Ptr exprType() const {
176+
if (m_returnType || m_breakType) {
177+
return BuiltinType::newFromName(QLatin1String("void"));
178+
}
179+
return lastType();
180+
}
181+
182+
170183
void setExcludedDeclaration(const KDevelop::Declaration* d) {
171184
m_excludedDeclaration = d;
172185
}

duchain/tests/duchaintest.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,8 @@ void DUChainTest::testVarType_data()
677677
<< "const WriteError = error{EndOfStream};\n"
678678
"pub fn write() WriteError!void {}\n"
679679
"test{write() catch |err| {\n}}" << "err" << "WriteError" << "3,0";
680+
QTest::newRow("catch null") << "pub fn foo() !u8 { return 0; }; var x = foo() catch null;" << "x" << "?u8" << "";
681+
QTest::newRow("catch return null") << "pub fn foo() !u8 { return 0; }; var x = foo() catch return null;" << "x" << "u8" << "";
680682

681683
QTest::newRow("labelled block") << "const x = blk: { break :blk true; };" << "x" << "bool = true" << "";
682684

@@ -947,7 +949,7 @@ void DUChainTest::testProblems_data()
947949
// QTest::newRow("catch return 2") << "pub fn write(msg: []const u8) !usize { return 0; } pub fn main() void { const x = write(\"abcd\") catch |err| { if (true) { return; } return err; }; }" << QStringList{} << "";
948950
QTest::newRow("catch no return") << "pub fn write(msg: []const u8) !usize { return 0; } pub fn main() void { const x = write(\"abcd\") catch { }; }" << QStringList{QLatin1String("Incompatible types")} << "";
949951
QTest::newRow("catch panic") << "pub fn write(msg: []const u8) !usize { return 0; } pub fn main() void { const x = write(\"abcd\") catch @panic(\"doom\"); }" << QStringList{} << "";
950-
952+
QTest::newRow("catch return null") << "const Obj = struct{}; pub fn new() !*Obj { return error.OutOfMem; } pub fn init() ?*Obj { return new() catch null; } test { const x = init();}" << QStringList{} << "";
951953

952954
QTest::newRow("struct field") << "const A = struct {a: u8}; test {const x = A{.a = 0}; }" << QStringList{} << "";
953955
QTest::newRow("struct field type invalid") << "const A = struct {a: u8}; test {const x = A{.a = false}; }" << QStringList{QLatin1String("type mismatch")} << "";

duchain/usebuilder.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -918,14 +918,14 @@ VisitResult UseBuilder::visitCatch(const ZigNode &node, const ZigNode &parent)
918918
if (Helper::isMixedType(v2.lastType())) {
919919
return Continue;
920920
}
921+
auto targetType = errorType->baseType();
922+
921923
if (auto builtin = v2.lastType().dynamicCast<BuiltinType>()) {
922-
if (builtin->isTrap()) {
923-
return Continue; // Ignore foo() catch @panic()
924+
if (builtin->isTrap() || builtin->isNull()) {
925+
return Continue; // Ignore foo() catch @panic() or catch null
924926
}
925927
}
926928

927-
928-
auto targetType = errorType->baseType();
929929
// TODO: Determining whether the target is const should be done better,
930930
// this only works for a single case of const foo = a catch b;
931931
if (parent.kind() == VarDecl && parent.mainToken() == QStringLiteral("const")) {

0 commit comments

Comments
 (0)