@@ -3,6 +3,7 @@ package decaf.typecheck
33import decaf .annot .ScopeImplicit ._
44import decaf .annot .SymbolImplicit ._
55import decaf .annot .TypeImplicit ._
6+ import decaf .annot .FlagImplicit ._
67import decaf .annot ._
78import decaf .driver .{Config , Phase }
89import decaf .error ._
@@ -61,11 +62,13 @@ class Typer extends Phase[Tree, Tree]("typer") with Util {
6162 val ctx = global.open(symbol.scope)
6263 val checkedFields = fields.map {
6364 case v : VarDef => v
64- case f @ MethodDef (id, params, returnType, body, isStatic) =>
65- val formalCtx = ctx.open(f .symbol.scope)
65+ case m @ MethodDef (id, params, returnType, body, isStatic) =>
66+ val formalCtx = ctx.open(m .symbol.scope)
6667 val checkedBody = checkBlock(body)(formalCtx)
67- // FIXME check every path is returned, if its return type is not void
68- MethodDef (id, params, returnType, checkedBody, isStatic)(f.symbol).setPos(f.pos)
68+ // Check if the body always returns a value, when the method is non-void
69+ if (! m.symbol.returnType.isVoidType && checkedBody.no)
70+ issue(new MissingReturnError (checkedBody.pos))
71+ MethodDef (id, params, returnType, checkedBody, isStatic)(m.symbol).setPos(m.pos)
6972 }
7073 ClassDef (id, parent, checkedFields)(symbol).setPos(clazz.pos)
7174 }
@@ -96,10 +99,17 @@ class Typer extends Phase[Tree, Tree]("typer") with Util {
9699 }
97100 val local = ctx.open(scope)
98101 val ss = block.stmts.map { checkStmt(_)(local, insideLoop) }
99- Block (ss).setPos(block.pos)
102+ val ret = if (ss.isEmpty) No else ss.last match {
103+ case c : ControlFlowStmt => c.flag // a block returns a value if its last statement does so
104+ case _ => No
105+ }
106+
107+ Block (ss)(ret).setPos(block.pos)
100108 }
101109
102110 def checkStmt (stmt : Stmt )(implicit ctx : ScopeContext , insideLoop : Boolean ): Stmt = {
111+ implicit val noReturn : Flag = No
112+
103113 val checked = stmt match {
104114 case block : Block => checkBlock(block)
105115
@@ -126,7 +136,9 @@ class Typer extends Phase[Tree, Tree]("typer") with Util {
126136 val c = checkTestExpr(cond)
127137 val t = checkBlock(trueBranch)
128138 val f = falseBranch.map(checkBlock)
129- If (c, t, f)
139+ // if-stmt returns a value if both branches return
140+ val ret = if (t.yes && f.isDefined && f.get.yes) Yes else No
141+ If (c, t, f)(ret)
130142
131143 case While (cond, body) =>
132144 val c = checkTestExpr(cond)
@@ -152,7 +164,7 @@ class Typer extends Phase[Tree, Tree]("typer") with Util {
152164 }
153165 val actual = e.map(_.typ).getOrElse(VoidType )
154166 if (actual.noError && ! (actual <= expected)) issue(new BadReturnTypeError (expected, actual, stmt.pos))
155- Return (e)
167+ Return (e)( Yes ) // returned
156168
157169 case Print (exprs) =>
158170 val es = exprs.zipWithIndex.map {
@@ -315,7 +327,6 @@ class Typer extends Phase[Tree, Tree]("typer") with Util {
315327 if (ctx.currentMethod.isStatic) // member vars cannot be accessed in a static method
316328 issue(new RefNonStaticError (id, ctx.currentMethod.name, expr.pos))
317329 MemberVar (This (), v)(v.typ)
318- // TODO report error: method and types are not allowed here
319330 case _ => issue(new UndeclVarError (id, expr.pos)); err
320331 }
321332 case None => issue(new UndeclVarError (id, expr.pos)); err
@@ -337,7 +348,6 @@ class Typer extends Phase[Tree, Tree]("typer") with Util {
337348 if (! (ctx.currentClass.typ <= t)) // member vars are protected
338349 issue(new FieldNotAccessError (id, t, expr.pos))
339350 MemberVar (r, v)(v.typ)
340- // case m: MethodSymbol => TODO report error: method and types are not allowed here
341351 case _ => issue(new FieldNotFoundError (id, t, expr.pos)); err
342352 }
343353 case None => issue(new FieldNotFoundError (id, t, expr.pos)); err
0 commit comments