diff options
Diffstat (limited to 'source/slang/slang-check-expr.cpp')
| -rw-r--r-- | source/slang/slang-check-expr.cpp | 69 |
1 files changed, 44 insertions, 25 deletions
diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp index db507c060..75b1b7024 100644 --- a/source/slang/slang-check-expr.cpp +++ b/source/slang/slang-check-expr.cpp @@ -3951,45 +3951,64 @@ Expr* SemanticsExprVisitor::visitTryExpr(TryExpr* expr) return expr; auto parentFunc = this->m_parentFunc; - // TODO: check if the try clause is caught. - // For now we assume all `try`s are not caught (because we don't have catch yet). - if (!parentFunc) + auto base = as<InvokeExpr>(expr->base); + if (!base) { - getSink()->diagnose(expr, Diagnostics::uncaughtTryCallInNonThrowFunc); + getSink()->diagnose(expr, Diagnostics::tryClauseMustApplyToInvokeExpr); return expr; } - if (parentFunc->errorType->equals(m_astBuilder->getBottomType())) + + auto callee = as<DeclRefExpr>(base->functionExpr); + if (!callee) { - getSink()->diagnose(expr, Diagnostics::uncaughtTryCallInNonThrowFunc); + getSink()->diagnose(expr, Diagnostics::calleeOfTryCallMustBeFunc); return expr; } - if (!as<InvokeExpr>(expr->base)) + + auto funcCallee = as<FuncDecl>(callee->declRef.getDecl()); + Stmt* catchStmt = nullptr; + if (funcCallee) { - getSink()->diagnose(expr, Diagnostics::tryClauseMustApplyToInvokeExpr); + if (funcCallee->errorType->equals(m_astBuilder->getBottomType())) + { + getSink()->diagnose(expr, Diagnostics::tryInvokeCalleeShouldThrow, callee->declRef); + return expr; + } + catchStmt = findMatchingCatchStmt(funcCallee->errorType); + } + + if (FindOuterStmt<DeferStmt>(catchStmt)) + { + // 'try' may jump outside a defer statement, which isn't allowed for + // now. + getSink()->diagnose(expr, Diagnostics::uncaughtTryInsideDefer); return expr; } - auto base = as<InvokeExpr>(expr->base); - if (auto callee = as<DeclRefExpr>(base->functionExpr)) + + if (!catchStmt) { - if (auto funcCallee = as<FuncDecl>(callee->declRef.getDecl())) + // Uncaught try. + if (!parentFunc) { - if (funcCallee->errorType->equals(m_astBuilder->getBottomType())) - { - getSink()->diagnose(expr, Diagnostics::tryInvokeCalleeShouldThrow, callee->declRef); - } - if (!parentFunc->errorType->equals(funcCallee->errorType)) - { - getSink()->diagnose( - expr, - Diagnostics::errorTypeOfCalleeIncompatibleWithCaller, - callee->declRef, - funcCallee->errorType, - parentFunc->errorType); - } + getSink()->diagnose(expr, Diagnostics::uncaughtTryCallInNonThrowFunc); + return expr; + } + if (parentFunc->errorType->equals(m_astBuilder->getBottomType())) + { + getSink()->diagnose(expr, Diagnostics::uncaughtTryCallInNonThrowFunc); + return expr; + } + if (funcCallee && !parentFunc->errorType->equals(funcCallee->errorType)) + { + getSink()->diagnose( + expr, + Diagnostics::errorTypeOfCalleeIncompatibleWithCaller, + callee->declRef, + funcCallee->errorType, + parentFunc->errorType); return expr; } } - getSink()->diagnose(expr, Diagnostics::calleeOfTryCallMustBeFunc); return expr; } |
