Index: src/typing-asm.cc |
diff --git a/src/typing-asm.cc b/src/typing-asm.cc |
index 015be1348922319a66e11826d66774253eec3f7c..6e7b90ccd120f7a30d721b570d375d7d6979d927 100644 |
--- a/src/typing-asm.cc |
+++ b/src/typing-asm.cc |
@@ -99,7 +99,6 @@ void AsmTyper::VisitAsmModule(FunctionLiteral* fun) { |
if (decl != NULL) { |
RECURSE(VisitFunctionAnnotation(decl->fun())); |
Variable* var = decl->proxy()->var(); |
- DCHECK(GetType(var) == NULL); |
if (property_info_ != NULL) { |
SetVariableInfo(var, property_info_); |
property_info_ = NULL; |
@@ -151,6 +150,10 @@ void AsmTyper::VisitFunctionDeclaration(FunctionDeclaration* decl) { |
if (in_function_) { |
FAIL(decl, "function declared inside another"); |
} |
+ // Set function type so global references to functions have some type |
+ // (so they can give a more useful error). |
+ Variable* var = decl->proxy()->var(); |
+ SetType(var, Type::Function(zone())); |
} |
@@ -535,7 +538,7 @@ void AsmTyper::VisitVariableProxy(VariableProxy* expr) { |
if (type->Is(cache_.kAsmInt)) { |
type = cache_.kAsmInt; |
} |
- SetType(var, type); |
+ info->type = type; |
intish_ = 0; |
IntersectResult(expr, type); |
} |
@@ -776,14 +779,14 @@ bool AsmTyper::IsStdlibObject(Expression* expr) { |
Variable* var = proxy->var(); |
VariableInfo* info = GetVariableInfo(var, false); |
if (info) { |
- if (info->is_stdlib_object) return info->is_stdlib_object; |
+ if (info->standard_member == kStdlib) return true; |
} |
if (var->location() != VariableLocation::PARAMETER || var->index() != 0) { |
return false; |
} |
info = GetVariableInfo(var, true); |
info->type = Type::Object(); |
- info->is_stdlib_object = true; |
+ info->standard_member = kStdlib; |
return true; |
} |
@@ -874,8 +877,20 @@ void AsmTyper::VisitProperty(Property* expr) { |
void AsmTyper::VisitCall(Call* expr) { |
RECURSE(VisitWithExpectation(expr->expression(), Type::Any(), |
"callee expected to be any")); |
+ StandardMember standard_member = kNone; |
+ VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
+ if (proxy) { |
+ standard_member = VariableAsStandardMember(proxy->var()); |
+ } |
+ if (!in_function_ && (proxy == NULL || standard_member != kMathFround)) { |
+ FAIL(expr, "calls forbidden outside function bodies"); |
+ } |
+ if (proxy == NULL && !expr->expression()->IsProperty()) { |
+ FAIL(expr, "calls must be to bound variables or function tables"); |
+ } |
if (computed_type_->IsFunction()) { |
Type::FunctionType* fun_type = computed_type_->AsFunction(); |
+ Type* result_type = fun_type->Result(); |
ZoneList<Expression*>* args = expr->arguments(); |
if (fun_type->Arity() != args->length()) { |
FAIL(expr, "call with wrong arity"); |
@@ -885,9 +900,36 @@ void AsmTyper::VisitCall(Call* expr) { |
RECURSE(VisitWithExpectation( |
arg, fun_type->Parameter(i), |
"call argument expected to match callee parameter")); |
+ if (standard_member != kNone && standard_member != kMathFround && |
+ i == 0) { |
+ result_type = computed_type_; |
+ } |
+ } |
+ // Handle polymorphic stdlib functions specially. |
+ if (standard_member == kMathCeil || standard_member == kMathFloor || |
+ standard_member == kMathSqrt) { |
+ if (!args->at(0)->bounds().upper->Is(cache_.kAsmFloat) && |
+ !args->at(0)->bounds().upper->Is(cache_.kAsmDouble)) { |
+ FAIL(expr, "illegal function argument type"); |
+ } |
+ } else if (standard_member == kMathAbs || standard_member == kMathMin || |
+ standard_member == kMathMax) { |
+ if (!args->at(0)->bounds().upper->Is(cache_.kAsmFloat) && |
+ !args->at(0)->bounds().upper->Is(cache_.kAsmDouble) && |
+ !args->at(0)->bounds().upper->Is(cache_.kAsmSigned)) { |
+ FAIL(expr, "illegal function argument type"); |
+ } |
+ if (args->length() > 1) { |
+ Type* other = Type::Intersect(args->at(0)->bounds().upper, |
+ args->at(1)->bounds().upper, zone()); |
+ if (!other->Is(cache_.kAsmFloat) && !other->Is(cache_.kAsmDouble) && |
+ !other->Is(cache_.kAsmSigned)) { |
+ FAIL(expr, "function arguments types don't match"); |
+ } |
+ } |
} |
intish_ = 0; |
- IntersectResult(expr, fun_type->Result()); |
+ IntersectResult(expr, result_type); |
} else if (computed_type_->Is(Type::Any())) { |
// For foreign calls. |
ZoneList<Expression*>* args = expr->arguments(); |
@@ -1230,34 +1272,52 @@ void AsmTyper::InitializeStdlib() { |
Type::Function(cache_.kAsmSigned, cache_.kAsmInt, cache_.kAsmInt, zone()); |
// TODO(bradnelson): currently only approximating the proper intersection type |
// (which we cannot currently represent). |
- Type* abs_type = Type::Function(number_type, number_type, zone()); |
+ Type* number_fn1_type = Type::Function(number_type, number_type, zone()); |
+ Type* number_fn2_type = |
+ Type::Function(number_type, number_type, number_type, zone()); |
struct Assignment { |
const char* name; |
+ StandardMember standard_member; |
Type* type; |
}; |
- const Assignment math[] = { |
- {"PI", double_type}, {"E", double_type}, |
- {"LN2", double_type}, {"LN10", double_type}, |
- {"LOG2E", double_type}, {"LOG10E", double_type}, |
- {"SQRT2", double_type}, {"SQRT1_2", double_type}, |
- {"imul", imul_type}, {"abs", abs_type}, |
- {"ceil", double_fn1_type}, {"floor", double_fn1_type}, |
- {"fround", fround_type}, {"pow", double_fn2_type}, |
- {"exp", double_fn1_type}, {"log", double_fn1_type}, |
- {"min", double_fn2_type}, {"max", double_fn2_type}, |
- {"sqrt", double_fn1_type}, {"cos", double_fn1_type}, |
- {"sin", double_fn1_type}, {"tan", double_fn1_type}, |
- {"acos", double_fn1_type}, {"asin", double_fn1_type}, |
- {"atan", double_fn1_type}, {"atan2", double_fn2_type}}; |
+ const Assignment math[] = {{"PI", kMathPI, double_type}, |
+ {"E", kMathE, double_type}, |
+ {"LN2", kMathLN2, double_type}, |
+ {"LN10", kMathLN10, double_type}, |
+ {"LOG2E", kMathLOG2E, double_type}, |
+ {"LOG10E", kMathLOG10E, double_type}, |
+ {"SQRT2", kMathSQRT2, double_type}, |
+ {"SQRT1_2", kMathSQRT1_2, double_type}, |
+ {"imul", kMathImul, imul_type}, |
+ {"abs", kMathAbs, number_fn1_type}, |
+ {"ceil", kMathCeil, number_fn1_type}, |
+ {"floor", kMathFloor, number_fn1_type}, |
+ {"fround", kMathFround, fround_type}, |
+ {"pow", kMathPow, double_fn2_type}, |
+ {"exp", kMathExp, double_fn1_type}, |
+ {"log", kMathLog, double_fn1_type}, |
+ {"min", kMathMin, number_fn2_type}, |
+ {"max", kMathMax, number_fn2_type}, |
+ {"sqrt", kMathSqrt, number_fn1_type}, |
+ {"cos", kMathCos, double_fn1_type}, |
+ {"sin", kMathSin, double_fn1_type}, |
+ {"tan", kMathTan, double_fn1_type}, |
+ {"acos", kMathAcos, double_fn1_type}, |
+ {"asin", kMathAsin, double_fn1_type}, |
+ {"atan", kMathAtan, double_fn1_type}, |
+ {"atan2", kMathAtan2, double_fn2_type}}; |
for (unsigned i = 0; i < arraysize(math); ++i) { |
stdlib_math_types_[math[i].name] = new (zone()) VariableInfo(math[i].type); |
+ stdlib_math_types_[math[i].name]->standard_member = math[i].standard_member; |
} |
stdlib_math_types_["fround"]->is_check_function = true; |
stdlib_types_["Infinity"] = new (zone()) VariableInfo(double_type); |
+ stdlib_types_["Infinity"]->standard_member = kInfinity; |
stdlib_types_["NaN"] = new (zone()) VariableInfo(double_type); |
+ stdlib_types_["NaN"]->standard_member = kNaN; |
Type* buffer_type = Type::Any(zone()); |
#define TYPED_ARRAY(TypeName, type_name, TYPE_NAME, ctype, size) \ |
stdlib_types_[#TypeName "Array"] = new (zone()) VariableInfo( \ |
@@ -1326,6 +1386,8 @@ AsmTyper::VariableInfo* AsmTyper::GetVariableInfo(Variable* variable, |
if (!entry && in_function_) { |
entry = |
global_variable_type_.Lookup(variable, ComputePointerHash(variable)); |
+ if (entry && entry->value) { |
+ } |
} |
} |
if (!entry) return NULL; |
@@ -1340,9 +1402,17 @@ AsmTyper::VariableInfo* AsmTyper::GetVariableInfo(Variable* variable, |
void AsmTyper::SetVariableInfo(Variable* variable, const VariableInfo* info) { |
VariableInfo* dest = GetVariableInfo(variable, true); |
dest->type = info->type; |
- dest->is_stdlib_object = info->is_stdlib_object; |
dest->is_check_function = info->is_check_function; |
dest->is_constructor_function = info->is_constructor_function; |
+ dest->standard_member = info->standard_member; |
+} |
+ |
+ |
+AsmTyper::StandardMember AsmTyper::VariableAsStandardMember( |
+ Variable* variable) { |
+ VariableInfo* info = GetVariableInfo(variable, false); |
+ if (!info) return kNone; |
+ return info->standard_member; |
} |