Index: src/typing-asm.cc |
diff --git a/src/typing-asm.cc b/src/typing-asm.cc |
index e121e7f19accd7961d5039be617780f16199b23b..ebb5eaa67f3f34c26103b4ef60bb4cb6b6193e18 100644 |
--- a/src/typing-asm.cc |
+++ b/src/typing-asm.cc |
@@ -41,6 +41,7 @@ AsmTyper::AsmTyper(Isolate* isolate, Zone* zone, Script* script, |
script_(script), |
root_(root), |
valid_(true), |
+ intish_(0), |
stdlib_types_(zone), |
stdlib_heap_types_(zone), |
stdlib_math_types_(zone), |
@@ -155,7 +156,7 @@ void AsmTyper::VisitFunctionAnnotation(FunctionLiteral* fun) { |
if (literal) { |
RECURSE(VisitLiteral(literal, true)); |
} else { |
- RECURSE(VisitExpressionAnnotation(stmt->expression(), true)); |
+ RECURSE(VisitExpressionAnnotation(stmt->expression(), NULL, true)); |
} |
expected_type_ = old_expected; |
result_type = computed_type_; |
@@ -179,7 +180,7 @@ void AsmTyper::VisitFunctionAnnotation(FunctionLiteral* fun) { |
Variable* var = proxy->var(); |
if (var->location() != VariableLocation::PARAMETER || var->index() != i) |
break; |
- RECURSE(VisitExpressionAnnotation(expr->value(), false)); |
+ RECURSE(VisitExpressionAnnotation(expr->value(), var, false)); |
SetType(var, computed_type_); |
type->InitParameter(i, computed_type_); |
good = true; |
@@ -190,10 +191,20 @@ void AsmTyper::VisitFunctionAnnotation(FunctionLiteral* fun) { |
} |
-void AsmTyper::VisitExpressionAnnotation(Expression* expr, bool is_return) { |
+void AsmTyper::VisitExpressionAnnotation(Expression* expr, Variable* var, |
+ bool is_return) { |
// Normal +x or x|0 annotations. |
BinaryOperation* bin = expr->AsBinaryOperation(); |
if (bin != NULL) { |
+ if (var != NULL) { |
+ VariableProxy* left = bin->left()->AsVariableProxy(); |
+ if (!left) { |
+ FAIL(expr, "variable name expected in type annotation"); |
+ } |
+ if (left->var() != var) { |
+ FAIL(left, "variable type annotation references other variable"); |
+ } |
+ } |
Literal* right = bin->right()->AsLiteral(); |
if (right != NULL) { |
switch (bin->op()) { |
@@ -593,19 +604,23 @@ void AsmTyper::VisitAssignment(Assignment* expr) { |
Type* type = expected_type_; |
RECURSE(VisitWithExpectation( |
expr->value(), type, "assignment value expected to match surrounding")); |
+ Type* target_type = StorageType(computed_type_); |
if (intish_ != 0) { |
- FAIL(expr, "value still an intish"); |
- } |
- Type* target_type = computed_type_; |
- if (target_type->Is(cache_.kAsmInt)) { |
- target_type = cache_.kAsmInt; |
- } |
- RECURSE(VisitWithExpectation(expr->target(), target_type, |
- "assignment target expected to match value")); |
- if (intish_ != 0) { |
- FAIL(expr, "value still an intish"); |
+ FAIL(expr, "intish or floatish assignment"); |
+ } |
+ if (expr->target()->IsVariableProxy()) { |
+ RECURSE(VisitWithExpectation(expr->target(), target_type, |
+ "assignment target expected to match value")); |
+ } else if (expr->target()->IsProperty()) { |
+ Property* property = expr->target()->AsProperty(); |
+ RECURSE(VisitWithExpectation(property->obj(), Type::Any(), |
+ "bad propety object")); |
+ if (!computed_type_->IsArray()) { |
+ FAIL(property->obj(), "array expected"); |
+ } |
+ VisitHeapAccess(property, true, target_type); |
} |
- IntersectResult(expr, computed_type_); |
+ IntersectResult(expr, target_type); |
} |
@@ -637,11 +652,15 @@ Type* AsmTyper::StorageType(Type* type) { |
} |
-void AsmTyper::VisitHeapAccess(Property* expr) { |
+void AsmTyper::VisitHeapAccess(Property* expr, bool assigning, |
+ Type* assignment_type) { |
Type::ArrayType* array_type = computed_type_->AsArray(); |
size_t size = array_size_; |
Type* type = array_type->AsArray()->Element(); |
if (type->IsFunction()) { |
+ if (assigning) { |
+ FAIL(expr, "assigning to function table is illegal"); |
+ } |
BinaryOperation* bin = expr->key()->AsBinaryOperation(); |
if (bin == NULL || bin->op() != Token::BIT_AND) { |
FAIL(expr->key(), "expected & in call"); |
@@ -658,6 +677,7 @@ void AsmTyper::VisitHeapAccess(Property* expr) { |
FAIL(right, "call mask must match function table"); |
} |
bin->set_bounds(Bounds(cache_.kAsmSigned)); |
+ IntersectResult(expr, type); |
} else { |
Literal* literal = expr->key()->AsLiteral(); |
if (literal) { |
@@ -683,8 +703,39 @@ void AsmTyper::VisitHeapAccess(Property* expr) { |
} |
bin->set_bounds(Bounds(cache_.kAsmSigned)); |
} |
+ Type* result_type; |
+ if (type->Is(cache_.kAsmIntArrayElement)) { |
+ result_type = cache_.kAsmIntQ; |
+ intish_ = kMaxUncombinedAdditiveSteps; |
+ } else if (type->Is(cache_.kAsmFloat)) { |
+ if (assigning) { |
+ result_type = cache_.kAsmFloatDoubleQ; |
+ } else { |
+ result_type = cache_.kAsmFloatQ; |
+ } |
+ intish_ = 0; |
+ } else if (type->Is(cache_.kAsmDouble)) { |
+ if (assigning) { |
+ result_type = cache_.kAsmFloatDoubleQ; |
+ if (intish_ != 0) { |
+ FAIL(expr, "Assignment of floatish to Float64Array"); |
+ } |
+ } else { |
+ result_type = cache_.kAsmDoubleQ; |
+ } |
+ intish_ = 0; |
+ } else { |
+ UNREACHABLE(); |
+ } |
+ if (assigning) { |
+ if (!assignment_type->Is(result_type)) { |
+ FAIL(expr, "illegal type in assignment"); |
+ } |
+ } else { |
+ IntersectResult(expr, expected_type_); |
+ IntersectResult(expr, result_type); |
+ } |
} |
- IntersectResult(expr, type); |
} |
@@ -720,12 +771,11 @@ void AsmTyper::VisitProperty(Property* expr) { |
// Only recurse at this point so that we avoid needing |
// stdlib.Math to have a real type. |
- RECURSE(VisitWithExpectation(expr->obj(), Type::Any(), |
- "property holder expected to be object")); |
+ RECURSE(VisitWithExpectation(expr->obj(), Type::Any(), "bad propety object")); |
// For heap view or function table access. |
if (computed_type_->IsArray()) { |
- VisitHeapAccess(expr); |
+ VisitHeapAccess(expr, false, NULL); |
return; |
} |
@@ -780,6 +830,7 @@ void AsmTyper::VisitCall(Call* expr) { |
arg, fun_type->Parameter(i), |
"call argument expected to match callee parameter")); |
} |
+ intish_ = 0; |
IntersectResult(expr, fun_type->Result()); |
} else if (computed_type_->Is(Type::Any())) { |
// For foreign calls. |
@@ -789,6 +840,7 @@ void AsmTyper::VisitCall(Call* expr) { |
RECURSE(VisitWithExpectation(arg, Type::Any(), |
"foreign call argument expected to be any")); |
} |
+ intish_ = kMaxUncombinedAdditiveSteps; |
IntersectResult(expr, Type::Number()); |
} else { |
FAIL(expr, "invalid callee"); |
@@ -994,13 +1046,17 @@ void AsmTyper::VisitBinaryOperation(BinaryOperation* expr) { |
IntersectResult(expr, cache_.kAsmInt); |
return; |
} |
- } else if (expr->op() == Token::MUL && left_type->Is(cache_.kAsmInt) && |
+ } else if (expr->op() == Token::MUL && expr->right()->IsLiteral() && |
right_type->Is(cache_.kAsmDouble)) { |
// For unary +, expressed as x * 1.0 |
IntersectResult(expr, cache_.kAsmDouble); |
return; |
} else if (type->Is(cache_.kAsmFloat) && expr->op() != Token::MOD) { |
+ if (left_intish != 0 || right_intish != 0) { |
+ FAIL(expr, "float operation before required fround"); |
+ } |
IntersectResult(expr, cache_.kAsmFloat); |
+ intish_ = 1; |
return; |
} else if (type->Is(cache_.kAsmDouble)) { |
IntersectResult(expr, cache_.kAsmDouble); |