jitcraft/SemanticAnalysis.cpp
changeset 71 f7e573226c2b
parent 68 b40b0e18a918
child 72 40746ab0a30b
     1.1 --- a/jitcraft/SemanticAnalysis.cpp	Thu Jul 12 00:38:00 2012 -0700
     1.2 +++ b/jitcraft/SemanticAnalysis.cpp	Sat Jul 14 18:43:34 2012 -0700
     1.3 @@ -100,8 +100,8 @@
     1.4    : zone_(zone),
     1.5      cc_(cc),
     1.6      tree_(tree),
     1.7 -    loopDepth_(0),
     1.8 -    scope_(NULL)
     1.9 +    scope_(NULL),
    1.10 +    loop_(NULL)
    1.11  {
    1.12  }
    1.13  
    1.14 @@ -147,18 +147,17 @@
    1.15      } else if (expression->isIndexExpression()) {
    1.16          if (type->isArray())
    1.17              expression->setType(type->contained());
    1.18 +    } else if (expression->isCallExpression()) {
    1.19 +        if (type->isVoid()) {
    1.20 +            CallExpression *call = expression->toCallExpression();
    1.21 +            cc_.reportError(call->callee()->pos(), Message_FunctionDoesNotReturnValue);
    1.22 +            return NULL;
    1.23 +        }
    1.24      }
    1.25  
    1.26      return expression->type();
    1.27  }
    1.28  
    1.29 -Type *
    1.30 -SemanticAnalysis::visitForRef(Expression *expression)
    1.31 -{
    1.32 -    expression->accept(this);
    1.33 -    return expression->type();
    1.34 -}
    1.35 -
    1.36  // :TODO: this leaks an interior pointer.
    1.37  static inline const char *
    1.38  GetTypeName(Type *type)
    1.39 @@ -269,6 +268,14 @@
    1.40      return var->type();
    1.41  }
    1.42  
    1.43 +SemanticAnalysis::ControlStatus
    1.44 +SemanticAnalysis::visitForControl(Statement *statement)
    1.45 +{
    1.46 +    ControlScope scope(&control_);
    1.47 +    statement->accept(this);
    1.48 +    return scope.status();
    1.49 +}
    1.50 +
    1.51  void
    1.52  SemanticAnalysis::visit(NameProxy *name)
    1.53  {
    1.54 @@ -332,6 +339,9 @@
    1.55  void
    1.56  SemanticAnalysis::visit(ReturnStatement *node)
    1.57  {
    1.58 +    // Set this early, so if we error we don't get more errors.
    1.59 +    control_->returns(Returns_Always);
    1.60 +
    1.61      Local<Type> type(zone_, visitForLoad(node->expression()));
    1.62      if (!type)
    1.63          return;
    1.64 @@ -344,7 +354,8 @@
    1.65  void
    1.66  SemanticAnalysis::visit(ForStatement *node)
    1.67  {
    1.68 -    loopDepth_++;
    1.69 +    LoopScope loop(&loop_);
    1.70 +
    1.71      if (node->scope())
    1.72          scope_ = node->scope();
    1.73  
    1.74 @@ -354,7 +365,6 @@
    1.75      if (node->condition()) {
    1.76          Local<Type> type(zone_, visitForLoad(node->condition()));
    1.77          if (!type || !canTest(node->condition(), type)) {
    1.78 -            loopDepth_--;
    1.79              return;
    1.80          }
    1.81      }
    1.82 @@ -362,26 +372,48 @@
    1.83      if (node->update())
    1.84          node->update()->accept(this);
    1.85  
    1.86 -    node->body()->accept(this);
    1.87 +    ControlStatus status = visitForControl(node->body());
    1.88 +
    1.89 +    // If there is a condition, we treat this like a while loop. Otherwise,
    1.90 +    // join point is only reachable if the loop contains a break. The
    1.91 +    // termination status doesn't tell us anything yet.
    1.92 +    if (node->condition() || loop.breaks())
    1.93 +        control_->merge(status, ControlStatus(false, Returns_Never));
    1.94 +    else
    1.95 +        control_->terminate(status.returns());
    1.96  
    1.97      if (node->scope())
    1.98          scope_ = scope_->enclosing();
    1.99 -    loopDepth_--;
   1.100  }
   1.101  
   1.102  void 
   1.103  SemanticAnalysis::visit(WhileStatement *node)
   1.104  {
   1.105 -    loopDepth_++;
   1.106 +    LoopScope loop(&loop_);
   1.107  
   1.108      Local<Type> type(zone_, visitForLoad(node->condition()));
   1.109      if (!type || !canTest(node->condition(), type)) {
   1.110 -        loopDepth_--;
   1.111          return;
   1.112      }
   1.113  
   1.114 -    node->body()->accept(this);
   1.115 -    loopDepth_--;
   1.116 +    ControlStatus status = visitForControl(node->body());
   1.117 +
   1.118 +    // Detect loops that will always have a fork in the control-flow graph.
   1.119 +    // This will be a |while| loop, or a |do-while| loop whose body does
   1.120 +    // not terminate.
   1.121 +    //
   1.122 +    // For now, we treat these as an |if| regardless of the direction the
   1.123 +    // branch can take. That means the control-flow is always conditional.
   1.124 +    if (node->token() == TOK_WHILE ||
   1.125 +        !status.terminates() ||
   1.126 +        loop.breaks())
   1.127 +    {
   1.128 +        control_->merge(status, ControlStatus(false, Returns_Never));
   1.129 +    } else {
   1.130 +        // At this point, we've got a do-while loop with a |return| or
   1.131 +        // |continue|, meaning that the rest of the block is unreachable.
   1.132 +        control_->terminate(status.returns());
   1.133 +    }
   1.134  }
   1.135  
   1.136  void
   1.137 @@ -408,7 +440,7 @@
   1.138      if (node->postDimensions()) {
   1.139          Local<Type> init(zone_);
   1.140          if (node->initialization()) {
   1.141 -            if ((init = visitAndApplyType(node->initialization())) == NULL)
   1.142 +            if ((init = visitForLoad(node->initialization())) == NULL)
   1.143                  return;
   1.144          }
   1.145  
   1.146 @@ -527,7 +559,7 @@
   1.147  void
   1.148  SemanticAnalysis::visit(ExpressionStatement *node)
   1.149  {
   1.150 -    node->expression()->accept(this);
   1.151 +    visitAndApplyType(node->expression());
   1.152  }
   1.153  
   1.154  bool
   1.155 @@ -597,7 +629,11 @@
   1.156          parameter->variable()->setType(type);
   1.157      }
   1.158  
   1.159 -    Local<Type> returnType(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32));
   1.160 +    Local<Type> returnType(zone_);
   1.161 +    if (node->hasExplicitReturn())
   1.162 +        returnType = zone_->types()->getPrimitive(PrimitiveType_Int32);
   1.163 +    else
   1.164 +        returnType = zone_->types()->getVoid();
   1.165      if (!returnType)
   1.166          return false;
   1.167  
   1.168 @@ -630,8 +666,20 @@
   1.169  {
   1.170      function_ = node->fun()->type();
   1.171      scope_ = node->scope();
   1.172 -    if (node->body())
   1.173 +
   1.174 +    ControlScope control(&control_);
   1.175 +    if (node->body()) {
   1.176          node->body()->accept(this);
   1.177 +
   1.178 +        ControlStatus status = control.status();
   1.179 +        if (status.returns() == Returns_Sometimes) {
   1.180 +            cc_.reportError(node->pos(), Message_NotAllPathsReturnValue);
   1.181 +        } else if (status.returns() == Returns_Never) {
   1.182 +            if (!function_->returnType()->isVoid())
   1.183 +                cc_.reportError(node->pos(), Message_MissingReturnValue);
   1.184 +        }
   1.185 +    }
   1.186 +
   1.187      scope_ = NULL;
   1.188      function_ = NULL;
   1.189  }
   1.190 @@ -772,6 +820,14 @@
   1.191          if (!given)
   1.192              return;
   1.193  
   1.194 +        // Since we skip a load, check for a call expression that returns void.
   1.195 +        if (given->isVoid()) {
   1.196 +            assert(expression->isCallExpression());
   1.197 +            CallExpression *call = expression->toCallExpression();
   1.198 +            cc_.reportError(call->callee()->pos(), Message_FunctionDoesNotReturnValue);
   1.199 +            return;
   1.200 +        }
   1.201 +        
   1.202          // If it's an IndexExpression, we special case the ability to compute
   1.203          // a reference.
   1.204          if (expression->isIndexExpression())
   1.205 @@ -801,6 +857,25 @@
   1.206  }
   1.207  
   1.208  void
   1.209 +SemanticAnalysis::ControlScope::merge(const ControlStatus &left, const ControlStatus &right)
   1.210 +{
   1.211 +    // If both sides terminate in a return, we consider this a return as well.
   1.212 +    if (left.returns() == Returns_Always && right.returns() == Returns_Always) {
   1.213 +        terminate(Returns_Always);
   1.214 +        return;
   1.215 +    }
   1.216 +
   1.217 +    ReturnStatus status = (left.returns() == Returns_Never && right.returns() == Returns_Never)
   1.218 +                          ? Returns_Never
   1.219 +                          : Returns_Sometimes;
   1.220 +
   1.221 +    if (left.terminates() && right.terminates())
   1.222 +        terminate(status);
   1.223 +    else
   1.224 +        returns(status);
   1.225 +}
   1.226 +
   1.227 +void
   1.228  SemanticAnalysis::visit(IfStatement *node)
   1.229  {
   1.230      Local<Type> type(zone_, visitForLoad(node->condition()));
   1.231 @@ -810,15 +885,19 @@
   1.232      if (!canTest(node, type))
   1.233          return;
   1.234  
   1.235 -    node->ifTrue()->accept(this);
   1.236 +    ControlStatus trueBranch = visitForControl(node->ifTrue());
   1.237 +    ControlStatus falseBranch = ControlStatus(false, Returns_Never);
   1.238 +
   1.239      if (node->ifFalse())
   1.240 -        node->ifFalse()->accept(this);
   1.241 +        falseBranch = visitForControl(node->ifFalse());
   1.242 +
   1.243 +    control_->merge(trueBranch, falseBranch);
   1.244  }
   1.245  
   1.246  void
   1.247  SemanticAnalysis::visit(IndexExpression *node)
   1.248  {
   1.249 -    Local<Type> left(zone_, visitForRef(node->left()));
   1.250 +    Local<Type> left(zone_, visitForLoad(node->left()));
   1.251      Local<Type> right(zone_, visitForLoad(node->right()));
   1.252  
   1.253      if (!left || !right)
   1.254 @@ -901,13 +980,29 @@
   1.255  void
   1.256  SemanticAnalysis::visit(BreakStatement *node)
   1.257  {
   1.258 -    if (loopDepth_ == 0)
   1.259 +    if (!loop_) {
   1.260          cc_.reportError(node->pos(), Message_BreakOutsideLoop);
   1.261 +        return;
   1.262 +    }
   1.263 +
   1.264 +    // Note: ignore breaks that occur in unreachable control-flow.
   1.265 +    if (!control_->status().terminates())
   1.266 +        loop_->addBreak();
   1.267 +
   1.268 +    control_->terminate(Returns_Never);
   1.269  }
   1.270  
   1.271  void
   1.272  SemanticAnalysis::visit(ContinueStatement *node)
   1.273  {
   1.274 -    if (loopDepth_ == 0)
   1.275 +    if (!loop_) {
   1.276          cc_.reportError(node->pos(), Message_ContinueOutsideLoop);
   1.277 +        return;
   1.278 +    }
   1.279 +
   1.280 +    // Note: ignore continues that occur in unreachable control-flow.
   1.281 +    if (!control_->status().terminates())
   1.282 +        loop_->addContinue();
   1.283 +
   1.284 +    control_->terminate(Returns_Never);
   1.285  }