1 // Copyright 2013 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #include "typing.h" 29 30 #include "parser.h" // for CompileTimeValue; TODO(rossberg): should move 31 #include "scopes.h" 32 33 namespace v8 { 34 namespace internal { 35 36 37 AstTyper::AstTyper(CompilationInfo* info) 38 : info_(info), 39 oracle_( 40 Handle<Code>(info->closure()->shared()->code()), 41 Handle<Context>(info->closure()->context()->native_context()), 42 info->isolate(), 43 info->zone()), 44 store_(info->zone()) { 45 InitializeAstVisitor(); 46 } 47 48 49 #define RECURSE(call) \ 50 do { \ 51 ASSERT(!visitor->HasStackOverflow()); \ 52 call; \ 53 if (visitor->HasStackOverflow()) return; \ 54 } while (false) 55 56 void AstTyper::Run(CompilationInfo* info) { 57 AstTyper* visitor = new(info->zone()) AstTyper(info); 58 Scope* scope = info->scope(); 59 60 // Handle implicit declaration of the function name in named function 61 // expressions before other declarations. 62 if (scope->is_function_scope() && scope->function() != NULL) { 63 RECURSE(visitor->VisitVariableDeclaration(scope->function())); 64 } 65 RECURSE(visitor->VisitDeclarations(scope->declarations())); 66 RECURSE(visitor->VisitStatements(info->function()->body())); 67 } 68 69 #undef RECURSE 70 71 #define RECURSE(call) \ 72 do { \ 73 ASSERT(!HasStackOverflow()); \ 74 call; \ 75 if (HasStackOverflow()) return; \ 76 } while (false) 77 78 79 void AstTyper::VisitStatements(ZoneList<Statement*>* stmts) { 80 for (int i = 0; i < stmts->length(); ++i) { 81 Statement* stmt = stmts->at(i); 82 RECURSE(Visit(stmt)); 83 if (stmt->IsJump()) break; 84 } 85 } 86 87 88 void AstTyper::VisitBlock(Block* stmt) { 89 RECURSE(VisitStatements(stmt->statements())); 90 if (stmt->labels() != NULL) { 91 store_.Forget(); // Control may transfer here via 'break l'. 92 } 93 } 94 95 96 void AstTyper::VisitExpressionStatement(ExpressionStatement* stmt) { 97 RECURSE(Visit(stmt->expression())); 98 } 99 100 101 void AstTyper::VisitEmptyStatement(EmptyStatement* stmt) { 102 } 103 104 105 void AstTyper::VisitIfStatement(IfStatement* stmt) { 106 // Collect type feedback. 107 if (!stmt->condition()->ToBooleanIsTrue() && 108 !stmt->condition()->ToBooleanIsFalse()) { 109 stmt->condition()->RecordToBooleanTypeFeedback(oracle()); 110 } 111 112 RECURSE(Visit(stmt->condition())); 113 Effects then_effects = EnterEffects(); 114 RECURSE(Visit(stmt->then_statement())); 115 ExitEffects(); 116 Effects else_effects = EnterEffects(); 117 RECURSE(Visit(stmt->else_statement())); 118 ExitEffects(); 119 then_effects.Alt(else_effects); 120 store_.Seq(then_effects); 121 } 122 123 124 void AstTyper::VisitContinueStatement(ContinueStatement* stmt) { 125 // TODO(rossberg): is it worth having a non-termination effect? 126 } 127 128 129 void AstTyper::VisitBreakStatement(BreakStatement* stmt) { 130 // TODO(rossberg): is it worth having a non-termination effect? 131 } 132 133 134 void AstTyper::VisitReturnStatement(ReturnStatement* stmt) { 135 // Collect type feedback. 136 // TODO(rossberg): we only need this for inlining into test contexts... 137 stmt->expression()->RecordToBooleanTypeFeedback(oracle()); 138 139 RECURSE(Visit(stmt->expression())); 140 // TODO(rossberg): is it worth having a non-termination effect? 141 } 142 143 144 void AstTyper::VisitWithStatement(WithStatement* stmt) { 145 RECURSE(stmt->expression()); 146 RECURSE(stmt->statement()); 147 } 148 149 150 void AstTyper::VisitSwitchStatement(SwitchStatement* stmt) { 151 RECURSE(Visit(stmt->tag())); 152 153 ZoneList<CaseClause*>* clauses = stmt->cases(); 154 SwitchStatement::SwitchType switch_type = stmt->switch_type(); 155 Effects local_effects(zone()); 156 bool complex_effects = false; // True for label effects or fall-through. 157 158 for (int i = 0; i < clauses->length(); ++i) { 159 CaseClause* clause = clauses->at(i); 160 Effects clause_effects = EnterEffects(); 161 162 if (!clause->is_default()) { 163 Expression* label = clause->label(); 164 SwitchStatement::SwitchType label_switch_type = 165 label->IsSmiLiteral() ? SwitchStatement::SMI_SWITCH : 166 label->IsStringLiteral() ? SwitchStatement::STRING_SWITCH : 167 SwitchStatement::GENERIC_SWITCH; 168 if (switch_type == SwitchStatement::UNKNOWN_SWITCH) 169 switch_type = label_switch_type; 170 else if (switch_type != label_switch_type) 171 switch_type = SwitchStatement::GENERIC_SWITCH; 172 173 RECURSE(Visit(label)); 174 if (!clause_effects.IsEmpty()) complex_effects = true; 175 } 176 177 ZoneList<Statement*>* stmts = clause->statements(); 178 RECURSE(VisitStatements(stmts)); 179 ExitEffects(); 180 if (stmts->is_empty() || stmts->last()->IsJump()) { 181 local_effects.Alt(clause_effects); 182 } else { 183 complex_effects = true; 184 } 185 } 186 187 if (complex_effects) { 188 store_.Forget(); // Reached this in unknown state. 189 } else { 190 store_.Seq(local_effects); 191 } 192 193 if (switch_type == SwitchStatement::UNKNOWN_SWITCH) 194 switch_type = SwitchStatement::GENERIC_SWITCH; 195 stmt->set_switch_type(switch_type); 196 197 // Collect type feedback. 198 // TODO(rossberg): can we eliminate this special case and extra loop? 199 if (switch_type == SwitchStatement::SMI_SWITCH) { 200 for (int i = 0; i < clauses->length(); ++i) { 201 CaseClause* clause = clauses->at(i); 202 if (!clause->is_default()) 203 clause->RecordTypeFeedback(oracle()); 204 } 205 } 206 } 207 208 209 void AstTyper::VisitDoWhileStatement(DoWhileStatement* stmt) { 210 // Collect type feedback. 211 if (!stmt->cond()->ToBooleanIsTrue()) { 212 stmt->cond()->RecordToBooleanTypeFeedback(oracle()); 213 } 214 215 // TODO(rossberg): refine the unconditional Forget (here and elsewhere) by 216 // computing the set of variables assigned in only some of the origins of the 217 // control transfer (such as the loop body here). 218 store_.Forget(); // Control may transfer here via looping or 'continue'. 219 RECURSE(Visit(stmt->body())); 220 RECURSE(Visit(stmt->cond())); 221 store_.Forget(); // Control may transfer here via 'break'. 222 } 223 224 225 void AstTyper::VisitWhileStatement(WhileStatement* stmt) { 226 // Collect type feedback. 227 if (!stmt->cond()->ToBooleanIsTrue()) { 228 stmt->cond()->RecordToBooleanTypeFeedback(oracle()); 229 } 230 231 store_.Forget(); // Control may transfer here via looping or 'continue'. 232 RECURSE(Visit(stmt->cond())); 233 RECURSE(Visit(stmt->body())); 234 store_.Forget(); // Control may transfer here via termination or 'break'. 235 } 236 237 238 void AstTyper::VisitForStatement(ForStatement* stmt) { 239 if (stmt->init() != NULL) { 240 RECURSE(Visit(stmt->init())); 241 } 242 store_.Forget(); // Control may transfer here via looping. 243 if (stmt->cond() != NULL) { 244 // Collect type feedback. 245 stmt->cond()->RecordToBooleanTypeFeedback(oracle()); 246 247 RECURSE(Visit(stmt->cond())); 248 } 249 RECURSE(Visit(stmt->body())); 250 store_.Forget(); // Control may transfer here via 'continue'. 251 if (stmt->next() != NULL) { 252 RECURSE(Visit(stmt->next())); 253 } 254 store_.Forget(); // Control may transfer here via termination or 'break'. 255 } 256 257 258 void AstTyper::VisitForInStatement(ForInStatement* stmt) { 259 // Collect type feedback. 260 stmt->RecordTypeFeedback(oracle()); 261 262 RECURSE(Visit(stmt->enumerable())); 263 store_.Forget(); // Control may transfer here via looping or 'continue'. 264 RECURSE(Visit(stmt->body())); 265 store_.Forget(); // Control may transfer here via 'break'. 266 } 267 268 269 void AstTyper::VisitForOfStatement(ForOfStatement* stmt) { 270 RECURSE(Visit(stmt->iterable())); 271 store_.Forget(); // Control may transfer here via looping or 'continue'. 272 RECURSE(Visit(stmt->body())); 273 store_.Forget(); // Control may transfer here via 'break'. 274 } 275 276 277 void AstTyper::VisitTryCatchStatement(TryCatchStatement* stmt) { 278 Effects try_effects = EnterEffects(); 279 RECURSE(Visit(stmt->try_block())); 280 ExitEffects(); 281 Effects catch_effects = EnterEffects(); 282 store_.Forget(); // Control may transfer here via 'throw'. 283 RECURSE(Visit(stmt->catch_block())); 284 ExitEffects(); 285 try_effects.Alt(catch_effects); 286 store_.Seq(try_effects); 287 // At this point, only variables that were reassigned in the catch block are 288 // still remembered. 289 } 290 291 292 void AstTyper::VisitTryFinallyStatement(TryFinallyStatement* stmt) { 293 RECURSE(Visit(stmt->try_block())); 294 store_.Forget(); // Control may transfer here via 'throw'. 295 RECURSE(Visit(stmt->finally_block())); 296 } 297 298 299 void AstTyper::VisitDebuggerStatement(DebuggerStatement* stmt) { 300 store_.Forget(); // May do whatever. 301 } 302 303 304 void AstTyper::VisitFunctionLiteral(FunctionLiteral* expr) { 305 } 306 307 308 void AstTyper::VisitSharedFunctionInfoLiteral(SharedFunctionInfoLiteral* expr) { 309 } 310 311 312 void AstTyper::VisitConditional(Conditional* expr) { 313 // Collect type feedback. 314 expr->condition()->RecordToBooleanTypeFeedback(oracle()); 315 316 RECURSE(Visit(expr->condition())); 317 Effects then_effects = EnterEffects(); 318 RECURSE(Visit(expr->then_expression())); 319 ExitEffects(); 320 Effects else_effects = EnterEffects(); 321 RECURSE(Visit(expr->else_expression())); 322 ExitEffects(); 323 then_effects.Alt(else_effects); 324 store_.Seq(then_effects); 325 326 NarrowType(expr, Bounds::Either( 327 expr->then_expression()->bounds(), 328 expr->else_expression()->bounds(), isolate_)); 329 } 330 331 332 void AstTyper::VisitVariableProxy(VariableProxy* expr) { 333 Variable* var = expr->var(); 334 if (var->IsStackAllocated()) { 335 NarrowType(expr, store_.LookupBounds(variable_index(var))); 336 } 337 } 338 339 340 void AstTyper::VisitLiteral(Literal* expr) { 341 Type* type = Type::Constant(expr->value(), isolate_); 342 NarrowType(expr, Bounds(type, isolate_)); 343 } 344 345 346 void AstTyper::VisitRegExpLiteral(RegExpLiteral* expr) { 347 NarrowType(expr, Bounds(Type::RegExp(), isolate_)); 348 } 349 350 351 void AstTyper::VisitObjectLiteral(ObjectLiteral* expr) { 352 ZoneList<ObjectLiteral::Property*>* properties = expr->properties(); 353 for (int i = 0; i < properties->length(); ++i) { 354 ObjectLiteral::Property* prop = properties->at(i); 355 356 // Collect type feedback. 357 if ((prop->kind() == ObjectLiteral::Property::MATERIALIZED_LITERAL && 358 !CompileTimeValue::IsCompileTimeValue(prop->value())) || 359 prop->kind() == ObjectLiteral::Property::COMPUTED) { 360 if (prop->key()->value()->IsInternalizedString() && prop->emit_store()) { 361 prop->RecordTypeFeedback(oracle()); 362 } 363 } 364 365 RECURSE(Visit(prop->value())); 366 } 367 368 NarrowType(expr, Bounds(Type::Object(), isolate_)); 369 } 370 371 372 void AstTyper::VisitArrayLiteral(ArrayLiteral* expr) { 373 ZoneList<Expression*>* values = expr->values(); 374 for (int i = 0; i < values->length(); ++i) { 375 Expression* value = values->at(i); 376 RECURSE(Visit(value)); 377 } 378 379 NarrowType(expr, Bounds(Type::Array(), isolate_)); 380 } 381 382 383 void AstTyper::VisitAssignment(Assignment* expr) { 384 // TODO(rossberg): Can we clean this up? 385 if (expr->is_compound()) { 386 // Collect type feedback. 387 Expression* target = expr->target(); 388 Property* prop = target->AsProperty(); 389 if (prop != NULL) { 390 prop->RecordTypeFeedback(oracle(), zone()); 391 expr->RecordTypeFeedback(oracle(), zone()); 392 } 393 394 RECURSE(Visit(expr->binary_operation())); 395 396 NarrowType(expr, expr->binary_operation()->bounds()); 397 } else { 398 // Collect type feedback. 399 if (expr->target()->IsProperty()) { 400 expr->RecordTypeFeedback(oracle(), zone()); 401 } 402 403 RECURSE(Visit(expr->target())); 404 RECURSE(Visit(expr->value())); 405 406 NarrowType(expr, expr->value()->bounds()); 407 } 408 409 VariableProxy* proxy = expr->target()->AsVariableProxy(); 410 if (proxy != NULL && proxy->var()->IsStackAllocated()) { 411 store_.Seq(variable_index(proxy->var()), Effect(expr->bounds())); 412 } 413 } 414 415 416 void AstTyper::VisitYield(Yield* expr) { 417 RECURSE(Visit(expr->generator_object())); 418 RECURSE(Visit(expr->expression())); 419 420 // We don't know anything about the result type. 421 } 422 423 424 void AstTyper::VisitThrow(Throw* expr) { 425 RECURSE(Visit(expr->exception())); 426 // TODO(rossberg): is it worth having a non-termination effect? 427 428 NarrowType(expr, Bounds(Type::None(), isolate_)); 429 } 430 431 432 void AstTyper::VisitProperty(Property* expr) { 433 // Collect type feedback. 434 expr->RecordTypeFeedback(oracle(), zone()); 435 436 RECURSE(Visit(expr->obj())); 437 RECURSE(Visit(expr->key())); 438 439 // We don't know anything about the result type. 440 } 441 442 443 void AstTyper::VisitCall(Call* expr) { 444 // Collect type feedback. 445 Expression* callee = expr->expression(); 446 Property* prop = callee->AsProperty(); 447 if (prop != NULL) { 448 if (prop->key()->IsPropertyName()) 449 expr->RecordTypeFeedback(oracle(), CALL_AS_METHOD); 450 } else { 451 expr->RecordTypeFeedback(oracle(), CALL_AS_FUNCTION); 452 } 453 454 RECURSE(Visit(expr->expression())); 455 ZoneList<Expression*>* args = expr->arguments(); 456 for (int i = 0; i < args->length(); ++i) { 457 Expression* arg = args->at(i); 458 RECURSE(Visit(arg)); 459 } 460 461 VariableProxy* proxy = expr->expression()->AsVariableProxy(); 462 if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) { 463 store_.Forget(); // Eval could do whatever to local variables. 464 } 465 466 // We don't know anything about the result type. 467 } 468 469 470 void AstTyper::VisitCallNew(CallNew* expr) { 471 // Collect type feedback. 472 expr->RecordTypeFeedback(oracle()); 473 474 RECURSE(Visit(expr->expression())); 475 ZoneList<Expression*>* args = expr->arguments(); 476 for (int i = 0; i < args->length(); ++i) { 477 Expression* arg = args->at(i); 478 RECURSE(Visit(arg)); 479 } 480 481 // We don't know anything about the result type. 482 } 483 484 485 void AstTyper::VisitCallRuntime(CallRuntime* expr) { 486 ZoneList<Expression*>* args = expr->arguments(); 487 for (int i = 0; i < args->length(); ++i) { 488 Expression* arg = args->at(i); 489 RECURSE(Visit(arg)); 490 } 491 492 // We don't know anything about the result type. 493 } 494 495 496 void AstTyper::VisitUnaryOperation(UnaryOperation* expr) { 497 // Collect type feedback. 498 if (expr->op() == Token::NOT) { 499 // TODO(rossberg): only do in test or value context. 500 expr->expression()->RecordToBooleanTypeFeedback(oracle()); 501 } 502 503 RECURSE(Visit(expr->expression())); 504 505 switch (expr->op()) { 506 case Token::NOT: 507 case Token::DELETE: 508 NarrowType(expr, Bounds(Type::Boolean(), isolate_)); 509 break; 510 case Token::VOID: 511 NarrowType(expr, Bounds(Type::Undefined(), isolate_)); 512 break; 513 case Token::TYPEOF: 514 NarrowType(expr, Bounds(Type::InternalizedString(), isolate_)); 515 break; 516 default: 517 UNREACHABLE(); 518 } 519 } 520 521 522 void AstTyper::VisitCountOperation(CountOperation* expr) { 523 // Collect type feedback. 524 expr->RecordTypeFeedback(oracle(), zone()); 525 Property* prop = expr->expression()->AsProperty(); 526 if (prop != NULL) { 527 prop->RecordTypeFeedback(oracle(), zone()); 528 } 529 530 RECURSE(Visit(expr->expression())); 531 532 NarrowType(expr, Bounds(Type::Smi(), Type::Number(), isolate_)); 533 534 VariableProxy* proxy = expr->expression()->AsVariableProxy(); 535 if (proxy != NULL && proxy->var()->IsStackAllocated()) { 536 store_.Seq(variable_index(proxy->var()), Effect(expr->bounds())); 537 } 538 } 539 540 541 void AstTyper::VisitBinaryOperation(BinaryOperation* expr) { 542 // Collect type feedback. 543 Handle<Type> type, left_type, right_type; 544 Maybe<int> fixed_right_arg; 545 oracle()->BinaryType(expr->BinaryOperationFeedbackId(), 546 &left_type, &right_type, &type, &fixed_right_arg); 547 NarrowLowerType(expr, type); 548 NarrowLowerType(expr->left(), left_type); 549 NarrowLowerType(expr->right(), right_type); 550 expr->set_fixed_right_arg(fixed_right_arg); 551 if (expr->op() == Token::OR || expr->op() == Token::AND) { 552 expr->left()->RecordToBooleanTypeFeedback(oracle()); 553 } 554 555 switch (expr->op()) { 556 case Token::COMMA: 557 RECURSE(Visit(expr->left())); 558 RECURSE(Visit(expr->right())); 559 NarrowType(expr, expr->right()->bounds()); 560 break; 561 case Token::OR: 562 case Token::AND: { 563 Effects left_effects = EnterEffects(); 564 RECURSE(Visit(expr->left())); 565 ExitEffects(); 566 Effects right_effects = EnterEffects(); 567 RECURSE(Visit(expr->right())); 568 ExitEffects(); 569 left_effects.Alt(right_effects); 570 store_.Seq(left_effects); 571 572 NarrowType(expr, Bounds::Either( 573 expr->left()->bounds(), expr->right()->bounds(), isolate_)); 574 break; 575 } 576 case Token::BIT_OR: 577 case Token::BIT_AND: { 578 RECURSE(Visit(expr->left())); 579 RECURSE(Visit(expr->right())); 580 Type* upper = Type::Union( 581 expr->left()->bounds().upper, expr->right()->bounds().upper); 582 if (!upper->Is(Type::Signed32())) upper = Type::Signed32(); 583 NarrowType(expr, Bounds(Type::Smi(), upper, isolate_)); 584 break; 585 } 586 case Token::BIT_XOR: 587 case Token::SHL: 588 case Token::SAR: 589 RECURSE(Visit(expr->left())); 590 RECURSE(Visit(expr->right())); 591 NarrowType(expr, Bounds(Type::Smi(), Type::Signed32(), isolate_)); 592 break; 593 case Token::SHR: 594 RECURSE(Visit(expr->left())); 595 RECURSE(Visit(expr->right())); 596 NarrowType(expr, Bounds(Type::Smi(), Type::Unsigned32(), isolate_)); 597 break; 598 case Token::ADD: { 599 RECURSE(Visit(expr->left())); 600 RECURSE(Visit(expr->right())); 601 Bounds l = expr->left()->bounds(); 602 Bounds r = expr->right()->bounds(); 603 Type* lower = 604 l.lower->Is(Type::Number()) && r.lower->Is(Type::Number()) ? 605 Type::Smi() : 606 l.lower->Is(Type::String()) || r.lower->Is(Type::String()) ? 607 Type::String() : Type::None(); 608 Type* upper = 609 l.upper->Is(Type::Number()) && r.upper->Is(Type::Number()) ? 610 Type::Number() : 611 l.upper->Is(Type::String()) || r.upper->Is(Type::String()) ? 612 Type::String() : Type::NumberOrString(); 613 NarrowType(expr, Bounds(lower, upper, isolate_)); 614 break; 615 } 616 case Token::SUB: 617 case Token::MUL: 618 case Token::DIV: 619 case Token::MOD: 620 RECURSE(Visit(expr->left())); 621 RECURSE(Visit(expr->right())); 622 NarrowType(expr, Bounds(Type::Smi(), Type::Number(), isolate_)); 623 break; 624 default: 625 UNREACHABLE(); 626 } 627 } 628 629 630 void AstTyper::VisitCompareOperation(CompareOperation* expr) { 631 // Collect type feedback. 632 Handle<Type> left_type, right_type, combined_type; 633 oracle()->CompareType(expr->CompareOperationFeedbackId(), 634 &left_type, &right_type, &combined_type); 635 NarrowLowerType(expr->left(), left_type); 636 NarrowLowerType(expr->right(), right_type); 637 expr->set_combined_type(combined_type); 638 639 RECURSE(Visit(expr->left())); 640 RECURSE(Visit(expr->right())); 641 642 NarrowType(expr, Bounds(Type::Boolean(), isolate_)); 643 } 644 645 646 void AstTyper::VisitThisFunction(ThisFunction* expr) { 647 } 648 649 650 void AstTyper::VisitDeclarations(ZoneList<Declaration*>* decls) { 651 for (int i = 0; i < decls->length(); ++i) { 652 Declaration* decl = decls->at(i); 653 RECURSE(Visit(decl)); 654 } 655 } 656 657 658 void AstTyper::VisitVariableDeclaration(VariableDeclaration* declaration) { 659 } 660 661 662 void AstTyper::VisitFunctionDeclaration(FunctionDeclaration* declaration) { 663 RECURSE(Visit(declaration->fun())); 664 } 665 666 667 void AstTyper::VisitModuleDeclaration(ModuleDeclaration* declaration) { 668 RECURSE(Visit(declaration->module())); 669 } 670 671 672 void AstTyper::VisitImportDeclaration(ImportDeclaration* declaration) { 673 RECURSE(Visit(declaration->module())); 674 } 675 676 677 void AstTyper::VisitExportDeclaration(ExportDeclaration* declaration) { 678 } 679 680 681 void AstTyper::VisitModuleLiteral(ModuleLiteral* module) { 682 RECURSE(Visit(module->body())); 683 } 684 685 686 void AstTyper::VisitModuleVariable(ModuleVariable* module) { 687 } 688 689 690 void AstTyper::VisitModulePath(ModulePath* module) { 691 RECURSE(Visit(module->module())); 692 } 693 694 695 void AstTyper::VisitModuleUrl(ModuleUrl* module) { 696 } 697 698 699 void AstTyper::VisitModuleStatement(ModuleStatement* stmt) { 700 RECURSE(Visit(stmt->body())); 701 } 702 703 704 } } // namespace v8::internal 705