1 #include "semantic/AstValidator.h"
7 #include "ast/ExprNode.h"
9 #include "semantic/ExprTypeResolver.h"
10 #include "utils/Utils.h"
14 void AstChecker::ValidateLU(
const ast::LinkingUnit& LU) {
16 for(
auto* cu : LU.compliationUnits()) {
21 void AstChecker::validateCU(
const ast::CompilationUnit& CU) {
23 if(!CU.bodyAsDecl())
return;
25 if(
auto* method = dyn_cast_or_null<ast::MethodDecl>(child)) {
26 validateMethod(*method);
27 }
else if(
auto* field = dyn_cast_or_null<ast::FieldDecl>(child)) {
28 valdiateTypedDecl(*field);
33 void AstChecker::validateMethod(
const ast::MethodDecl& method) {
34 currentMethod = &method;
35 if(method.body()) validateStmt(*method.body());
36 currentMethod =
nullptr;
39 void AstChecker::validateStmt(
const ast::
Stmt& stmt) {
40 if(
auto ret = dyn_cast<ast::ReturnStmt>(stmt)) {
41 validateReturnStmt(*ret);
42 }
else if(
auto decl = dyn_cast<ast::DeclStmt>(stmt)) {
43 valdiateTypedDecl(*decl->decl());
44 }
else if(
auto ifstmt = dyn_cast<ast::IfStmt>(stmt)) {
45 assert(ifstmt->condition());
46 auto* condTy = getTypeFromExpr(ifstmt->condition());
47 if(!condTy || !condTy->isBoolean()) {
48 diag.ReportError(ifstmt->condition()->location())
49 <<
"if condition expression must be yield a boolean";
51 }
else if(
auto forstmt = dyn_cast<ast::ForStmt>(stmt)) {
52 if (forstmt->condition()) {
53 auto* condTy = getTypeFromExpr(forstmt->condition());
54 if(!condTy || !condTy->isBoolean()) {
55 diag.ReportError(forstmt->condition()->location())
56 <<
"for condition expression must be yield a boolean";
59 }
else if(
auto whilestmt = dyn_cast<ast::WhileStmt>(stmt)) {
60 assert(whilestmt->condition());
61 auto* condTy = getTypeFromExpr(whilestmt->condition());
62 if(!condTy || !condTy->isBoolean()) {
63 diag.ReportError(whilestmt->condition()->location())
64 <<
"while condition expression must be yield a boolean";
68 if(
auto* stmt = dyn_cast_or_null<ast::Stmt>(child)) {
74 ast::
Type const* AstChecker::getTypeFromExpr(ast::
Expr const* expr)
const {
76 auto lastExpr = expr->list().tail();
78 if(
auto op = dyn_cast<ast::exprnode::ExprOp>(lastExpr)) {
79 return op->resultType();
80 }
else if(
auto value = dyn_cast<ast::exprnode::ExprValue>(lastExpr)) {
81 assert(value->type() &&
"Expr value type cannot be null");
87 void AstChecker::valdiateTypedDecl(
const ast::
TypedDecl& decl) {
88 if(!decl.hasInit())
return;
89 auto* declTy = decl.type();
90 auto* exprTy = getTypeFromExpr(decl.init());
92 diag.ReportError(decl.init()->location())
93 <<
"initializer type cannot be void";
96 if(!exprTypeResolver.isAssignableTo(declTy, exprTy)) {
98 <<
"initializer type must be assignable to declared type";
102 void AstChecker::validateReturnStmt(
const ast::ReturnStmt& ret) {
104 auto methodRetTy = currentMethod->returnTy().type;
107 diag.ReportError(ret.location())
108 <<
"return must be non-void" << ret.location() <<
"return is here"
109 << currentMethod
->location() <<
"method declared here";
114 ast::
Type const* retTy = getTypeFromExpr(ret.expr());
116 diag.ReportError(ret.expr()->location())
117 <<
"return expression cannot be void, regardless of method return "
124 diag.ReportError(ret.location())
125 <<
"return must be void" << ret.location() <<
"return is here"
126 << currentMethod
->location() <<
"method declared here";
131 if(!exprTypeResolver.isAssignableTo(methodRetTy, retTy)) {
132 diag.ReportError(ret.location())
133 <<
"return type must be assignable to method return type"
134 << ret.location() <<
"return is type " << retTy->toString()
135 << currentMethod
->location() <<
"method declared here";