Index: runtime/vm/object.cc |
=================================================================== |
--- runtime/vm/object.cc (revision 12003) |
+++ runtime/vm/object.cc (working copy) |
@@ -37,6 +37,9 @@ |
DEFINE_FLAG(bool, generate_gdb_symbols, false, |
"Generate symbols of generated dart functions for debugging with GDB"); |
+DEFINE_FLAG(bool, reject_named_argument_as_positional, false, |
+ "Enforce new rules for optional parameters and disallow passing of named " |
+ "arguments to optional positional formal parameters"); |
DEFINE_FLAG(bool, show_internal_names, false, |
"Show names of internal classes (e.g. \"OneByteString\") in error messages " |
"instead of showing the corresponding interface names (e.g. \"String\")"); |
@@ -3868,27 +3871,27 @@ |
} |
-void Function::set_is_static(bool is_static) const { |
+void Function::set_is_static(bool value) const { |
uword bits = raw_ptr()->kind_tag_; |
- raw_ptr()->kind_tag_ = StaticBit::update(is_static, bits); |
+ raw_ptr()->kind_tag_ = StaticBit::update(value, bits); |
} |
-void Function::set_is_const(bool is_const) const { |
+void Function::set_is_const(bool value) const { |
uword bits = raw_ptr()->kind_tag_; |
- raw_ptr()->kind_tag_ = ConstBit::update(is_const, bits); |
+ raw_ptr()->kind_tag_ = ConstBit::update(value, bits); |
} |
-void Function::set_is_external(bool is_external) const { |
+void Function::set_is_external(bool value) const { |
uword bits = raw_ptr()->kind_tag_; |
- raw_ptr()->kind_tag_ = ExternalBit::update(is_external, bits); |
+ raw_ptr()->kind_tag_ = ExternalBit::update(value, bits); |
} |
-void Function::set_token_pos(intptr_t pos) const { |
- ASSERT(pos >= 0); |
- raw_ptr()->token_pos_ = pos; |
+void Function::set_token_pos(intptr_t value) const { |
+ ASSERT(value >= 0); |
+ raw_ptr()->token_pos_ = value; |
} |
@@ -3897,18 +3900,30 @@ |
} |
-void Function::set_num_fixed_parameters(intptr_t n) const { |
- ASSERT(n >= 0); |
- raw_ptr()->num_fixed_parameters_ = n; |
+void Function::set_num_fixed_parameters(intptr_t value) const { |
+ ASSERT(value >= 0); |
+ raw_ptr()->num_fixed_parameters_ = value; |
} |
-void Function::set_num_optional_parameters(intptr_t n) const { |
- ASSERT(n >= 0); |
- raw_ptr()->num_optional_parameters_ = n; |
+void Function::set_num_optional_positional_parameters(intptr_t value) const { |
+ ASSERT(value >= 0); |
+ raw_ptr()->num_optional_positional_parameters_ = value; |
+ // Optional positional and optional named parameters are mutually exclusive. |
+ ASSERT((num_optional_positional_parameters() == 0) || |
+ (num_optional_named_parameters() == 0)); |
} |
+void Function::set_num_optional_named_parameters(intptr_t value) const { |
+ ASSERT(value >= 0); |
+ raw_ptr()->num_optional_named_parameters_ = value; |
+ // Optional positional and optional named parameters are mutually exclusive. |
+ ASSERT((num_optional_positional_parameters() == 0) || |
+ (num_optional_named_parameters() == 0)); |
+} |
+ |
+ |
bool Function::is_optimizable() const { |
return OptimizableBit::decode(raw_ptr()->kind_tag_) && |
(script() != Script::null()) && |
@@ -3941,7 +3956,8 @@ |
intptr_t Function::NumberOfParameters() const { |
- return num_fixed_parameters() + num_optional_parameters(); |
+ return num_fixed_parameters() + |
+ num_optional_positional_parameters() + num_optional_named_parameters(); |
} |
@@ -3964,9 +3980,79 @@ |
} |
+void Function::SetNumberOfParameters(intptr_t num_fixed_parameters, |
+ intptr_t num_optional_parameters, |
+ bool are_optional_positional) const { |
+ set_num_fixed_parameters(num_fixed_parameters); |
+ if (are_optional_positional) { |
+ set_num_optional_positional_parameters(num_optional_parameters); |
+ set_num_optional_named_parameters(0); |
+ } else { |
+ set_num_optional_positional_parameters(0); |
+ set_num_optional_named_parameters(num_optional_parameters); |
+ } |
+} |
+ |
+ |
bool Function::AreValidArgumentCounts(int num_arguments, |
int num_named_arguments, |
String* error_message) const { |
+ if (FLAG_reject_named_argument_as_positional) { |
+ if (num_named_arguments > num_optional_named_parameters()) { |
+ if (error_message != NULL) { |
+ const intptr_t kMessageBufferSize = 64; |
+ char message_buffer[kMessageBufferSize]; |
+ OS::SNPrint(message_buffer, |
+ kMessageBufferSize, |
+ "%d named passed, at most %"Pd" expected", |
+ num_named_arguments, |
+ num_optional_named_parameters()); |
+ *error_message = String::New(message_buffer); |
+ } |
+ return false; // Too many named arguments. |
+ } |
+ const int num_pos_args = num_arguments - num_named_arguments; |
+ const int num_opt_pos_params = num_optional_positional_parameters(); |
+ const int num_pos_params = num_fixed_parameters() + num_opt_pos_params; |
+ if (num_pos_args > num_pos_params) { |
+ if (error_message != NULL) { |
+ const intptr_t kMessageBufferSize = 64; |
+ char message_buffer[kMessageBufferSize]; |
+ // Hide implicit parameters to the user. |
+ const intptr_t num_hidden_params = NumberOfImplicitParameters(); |
+ OS::SNPrint(message_buffer, |
+ kMessageBufferSize, |
+ "%"Pd"%s passed, %s%"Pd" expected", |
+ num_pos_args - num_hidden_params, |
+ num_opt_pos_params > 0 ? " positional" : "", |
+ num_opt_pos_params > 0 ? "at most " : "", |
+ num_pos_params - num_hidden_params); |
+ *error_message = String::New(message_buffer); |
+ } |
+ return false; // Too many fixed and/or positional arguments. |
+ } |
+ if (num_pos_args < num_fixed_parameters()) { |
+ if (error_message != NULL) { |
+ const intptr_t kMessageBufferSize = 64; |
+ char message_buffer[kMessageBufferSize]; |
+ // Hide implicit parameters to the user. |
+ const intptr_t num_hidden_params = NumberOfImplicitParameters(); |
+ OS::SNPrint(message_buffer, |
+ kMessageBufferSize, |
+ "%"Pd"%s passed, %s%"Pd" expected", |
+ num_pos_args - num_hidden_params, |
+ num_opt_pos_params > 0 ? " positional" : "", |
+ num_opt_pos_params > 0 ? "at least " : "", |
+ num_fixed_parameters() - num_hidden_params); |
+ *error_message = String::New(message_buffer); |
+ } |
+ return false; // Too few fixed and/or positional arguments. |
+ } |
+ return true; |
+ } |
+ |
+ // TODO(regis): Remove the following code once the flag is removed. |
+ |
if (num_arguments > NumberOfParameters()) { |
if (error_message != NULL) { |
const intptr_t kMessageBufferSize = 64; |
@@ -3977,7 +4063,7 @@ |
kMessageBufferSize, |
"%"Pd" passed, %s%"Pd" expected", |
num_arguments - num_hidden_params, |
- num_optional_parameters() > 0 ? "at most " : "", |
+ HasOptionalParameters() ? "at most " : "", |
NumberOfParameters() - num_hidden_params); |
*error_message = String::New(message_buffer); |
} |
@@ -3994,7 +4080,7 @@ |
kMessageBufferSize, |
"%"Pd" %spassed, %"Pd" expected", |
num_positional_args - num_hidden_params, |
- num_optional_parameters() > 0 ? "positional " : "", |
+ HasOptionalParameters() ? "positional " : "", |
num_fixed_parameters() - num_hidden_params); |
*error_message = String::New(message_buffer); |
} |
@@ -4102,11 +4188,56 @@ |
bool Function::HasCompatibleParametersWith(const Function& other) const { |
- // The default values of optional parameters can differ. |
const intptr_t num_fixed_params = num_fixed_parameters(); |
- const intptr_t num_opt_params = num_optional_parameters(); |
+ const intptr_t num_opt_pos_params = num_optional_positional_parameters(); |
+ const intptr_t num_opt_named_params = num_optional_named_parameters(); |
const intptr_t other_num_fixed_params = other.num_fixed_parameters(); |
- const intptr_t other_num_opt_params = other.num_optional_parameters(); |
+ const intptr_t other_num_opt_pos_params = |
+ other.num_optional_positional_parameters(); |
+ const intptr_t other_num_opt_named_params = |
+ other.num_optional_named_parameters(); |
+ if (FLAG_reject_named_argument_as_positional) { |
+ // The default values of optional parameters can differ. |
+ if ((num_fixed_params != other_num_fixed_params) || |
+ (num_opt_pos_params < other_num_opt_pos_params) || |
+ (num_opt_named_params < other_num_opt_named_params)) { |
+ return false; |
+ } |
+ if (other_num_opt_named_params == 0) { |
+ return true; |
+ } |
+ // Check that for each optional named parameter of the other function there |
+ // exists an optional named parameter of this function with an identical |
+ // name. |
+ // Note that SetParameterNameAt() guarantees that names are symbols, so we |
+ // can compare their raw pointers. |
+ const int num_params = num_fixed_params + num_opt_named_params; |
+ const int other_num_params = |
+ other_num_fixed_params + other_num_opt_named_params; |
+ bool found_param_name; |
+ String& other_param_name = String::Handle(); |
+ for (intptr_t i = other_num_fixed_params; i < other_num_params; i++) { |
+ other_param_name = other.ParameterNameAt(i); |
+ found_param_name = false; |
+ for (intptr_t j = num_fixed_params; j < num_params; j++) { |
+ if (ParameterNameAt(j) == other_param_name.raw()) { |
+ found_param_name = true; |
+ break; |
+ } |
+ } |
+ if (!found_param_name) { |
+ return false; |
+ } |
+ } |
+ return true; |
+ } |
+ |
+ // TODO(regis): Remove the following code once the flag is removed. |
+ |
+ // The default values of optional parameters can differ. |
+ const intptr_t num_opt_params = num_opt_pos_params + num_opt_named_params; |
+ const intptr_t other_num_opt_params = |
+ other_num_opt_pos_params + other_num_opt_named_params; |
if ((num_fixed_params != other_num_fixed_params) || |
(num_opt_params < other_num_opt_params)) { |
return false; |
@@ -4119,6 +4250,8 @@ |
const int other_num_params = other_num_fixed_params + other_num_opt_params; |
for (intptr_t i = other_num_fixed_params; i < other_num_params; i++) { |
const String& other_param_name = String::Handle(other.ParameterNameAt(i)); |
+ ASSERT(other_param_name.IsSymbol()); |
+ ASSERT(String::Handle(ParameterNameAt(i)).IsSymbol()); |
if (ParameterNameAt(i) != other_param_name.raw()) { |
return false; |
} |
@@ -4128,22 +4261,23 @@ |
// If test_kind == kIsSubtypeOf, checks if the type of the specified parameter |
-// of this function is a subtype or a supertype of the type of the corresponding |
+// of this function is a subtype or a supertype of the type of the specified |
// parameter of the other function. |
// If test_kind == kIsMoreSpecificThan, checks if the type of the specified |
-// parameter of this function is more specific than the type of the |
-// corresponding parameter of the other function. |
+// parameter of this function is more specific than the type of the specified |
+// parameter of the other function. |
// Note that we do not apply contravariance of parameter types, but covariance |
// of both parameter types and result type. |
bool Function::TestParameterType( |
TypeTestKind test_kind, |
intptr_t parameter_position, |
+ intptr_t other_parameter_position, |
const AbstractTypeArguments& type_arguments, |
const Function& other, |
const AbstractTypeArguments& other_type_arguments, |
Error* malformed_error) const { |
AbstractType& other_param_type = |
- AbstractType::Handle(other.ParameterTypeAt(parameter_position)); |
+ AbstractType::Handle(other.ParameterTypeAt(other_parameter_position)); |
if (!other_param_type.IsInstantiated()) { |
other_param_type = other_param_type.InstantiateFrom(other_type_arguments); |
} |
@@ -4179,11 +4313,16 @@ |
const AbstractTypeArguments& other_type_arguments, |
Error* malformed_error) const { |
const intptr_t num_fixed_params = num_fixed_parameters(); |
- const intptr_t num_opt_params = num_optional_parameters(); |
+ const intptr_t num_opt_pos_params = num_optional_positional_parameters(); |
+ const intptr_t num_opt_named_params = num_optional_named_parameters(); |
const intptr_t other_num_fixed_params = other.num_fixed_parameters(); |
- const intptr_t other_num_opt_params = other.num_optional_parameters(); |
+ const intptr_t other_num_opt_pos_params = |
+ other.num_optional_positional_parameters(); |
+ const intptr_t other_num_opt_named_params = |
+ other.num_optional_named_parameters(); |
if ((num_fixed_params != other_num_fixed_params) || |
- (num_opt_params < other_num_opt_params)) { |
+ (num_opt_pos_params < other_num_opt_pos_params) || |
+ (num_opt_named_params < other_num_opt_named_params)) { |
return false; |
} |
// Check the result type. |
@@ -4211,10 +4350,60 @@ |
} |
} |
} |
+ if (FLAG_reject_named_argument_as_positional) { |
+ // Check the types of fixed and optional positional parameters. |
+ for (intptr_t i = 0; i < num_fixed_params + other_num_opt_pos_params; i++) { |
+ if (!TestParameterType(test_kind, |
+ i, i, type_arguments, other, other_type_arguments, |
+ malformed_error)) { |
+ return false; |
+ } |
+ } |
+ // Check the names and types of optional named parameters. |
+ if (other_num_opt_named_params == 0) { |
+ return true; |
+ } |
+ // Check that for each optional named parameter of type T of the other |
+ // function type, there exists an optional named parameter of this function |
+ // type with an identical name and with a type S that is a either a subtype |
+ // or supertype of T (if test_kind == kIsSubtypeOf) or that is more specific |
+ // than T (if test_kind == kIsMoreSpecificThan). |
+ // Note that SetParameterNameAt() guarantees that names are symbols, so we |
+ // can compare their raw pointers. |
+ const int num_params = num_fixed_params + num_opt_named_params; |
+ const int other_num_params = |
+ other_num_fixed_params + other_num_opt_named_params; |
+ bool found_param_name; |
+ String& other_param_name = String::Handle(); |
+ for (intptr_t i = other_num_fixed_params; i < other_num_params; i++) { |
+ other_param_name = other.ParameterNameAt(i); |
+ ASSERT(other_param_name.IsSymbol()); |
+ found_param_name = false; |
+ for (intptr_t j = num_fixed_params; j < num_params; j++) { |
+ ASSERT(String::Handle(ParameterNameAt(j)).IsSymbol()); |
+ if (ParameterNameAt(j) == other_param_name.raw()) { |
+ found_param_name = true; |
+ if (!TestParameterType(test_kind, |
+ j, i, |
+ type_arguments, other, other_type_arguments, |
+ malformed_error)) { |
+ return false; |
+ } |
+ break; |
+ } |
+ } |
+ if (!found_param_name) { |
+ return false; |
+ } |
+ } |
+ } |
+ |
+ // TODO(regis): Remove the following code once the flag is removed. |
+ |
// Check the types of fixed parameters. |
for (intptr_t i = 0; i < num_fixed_params; i++) { |
if (!TestParameterType(test_kind, |
- i, type_arguments, other, other_type_arguments, |
+ i, i, type_arguments, other, other_type_arguments, |
malformed_error)) { |
return false; |
} |
@@ -4227,14 +4416,16 @@ |
// or that is more specific than T (if test_kind == kIsMoreSpecificThan). |
// Note that SetParameterNameAt() guarantees that names are symbols, so we |
// can compare their raw pointers. |
- const intptr_t other_num_params = |
- other_num_fixed_params + other_num_opt_params; |
+ const intptr_t other_num_params = other_num_fixed_params + |
+ other_num_opt_pos_params + other_num_opt_named_params; |
String& other_param_name = String::Handle(); |
for (intptr_t i = other_num_fixed_params; i < other_num_params; i++) { |
other_param_name = other.ParameterNameAt(i); |
+ ASSERT(other_param_name.IsSymbol()); |
+ ASSERT(String::Handle(ParameterNameAt(i)).IsSymbol()); |
if ((ParameterNameAt(i) != other_param_name.raw()) || |
!TestParameterType(test_kind, |
- i, type_arguments, other, other_type_arguments, |
+ i, i, type_arguments, other, other_type_arguments, |
malformed_error)) { |
return false; |
} |
@@ -4285,7 +4476,8 @@ |
result.set_token_pos(token_pos); |
result.set_end_token_pos(token_pos); |
result.set_num_fixed_parameters(0); |
- result.set_num_optional_parameters(0); |
+ result.set_num_optional_positional_parameters(0); |
+ result.set_num_optional_named_parameters(0); |
result.set_usage_counter(0); |
result.set_deoptimization_counter(0); |
result.set_is_optimizable(true); |
@@ -4344,10 +4536,13 @@ |
// removing the receiver if this is an instance method. |
const int has_receiver = is_static() ? 0 : 1; |
const int num_fixed_params = num_fixed_parameters() - has_receiver; |
- const int num_optional_params = num_optional_parameters(); |
- const int num_params = num_fixed_params + num_optional_params; |
+ const int num_opt_pos_params = num_optional_positional_parameters(); |
+ const int num_opt_named_params = num_optional_named_parameters(); |
+ const int num_params = |
+ num_fixed_params + num_opt_pos_params + num_opt_named_params; |
closure_function.set_num_fixed_parameters(num_fixed_params); |
- closure_function.set_num_optional_parameters(num_optional_params); |
+ closure_function.set_num_optional_positional_parameters(num_opt_pos_params); |
+ closure_function.set_num_optional_named_parameters(num_opt_named_params); |
closure_function.set_parameter_types(Array::Handle(Array::New(num_params, |
Heap::kOld))); |
closure_function.set_parameter_names(Array::Handle(Array::New(num_params, |
@@ -4403,6 +4598,8 @@ |
const String& kRParen = String::Handle(Symbols::New(") => ")); |
const String& kLBracket = String::Handle(Symbols::New("[")); |
const String& kRBracket = String::Handle(Symbols::New("]")); |
+ const String& kLBrace = String::Handle(Symbols::New("{")); |
+ const String& kRBrace = String::Handle(Symbols::New("}")); |
String& name = String::Handle(); |
if (!instantiate && !is_static()) { |
// Prefix the signature with its type parameters, if any (e.g. "<K, V>"). |
@@ -4440,7 +4637,9 @@ |
AbstractType& param_type = AbstractType::Handle(); |
const intptr_t num_params = NumberOfParameters(); |
const intptr_t num_fixed_params = num_fixed_parameters(); |
- const intptr_t num_opt_params = num_optional_parameters(); |
+ const intptr_t num_opt_pos_params = num_optional_positional_parameters(); |
+ const intptr_t num_opt_named_params = num_optional_named_parameters(); |
+ const intptr_t num_opt_params = num_opt_pos_params + num_opt_named_params; |
ASSERT((num_fixed_params + num_opt_params) == num_params); |
pieces.Add(kLParen); |
for (intptr_t i = 0; i < num_fixed_params; i++) { |
@@ -4456,11 +4655,20 @@ |
} |
} |
if (num_opt_params > 0) { |
- pieces.Add(kLBracket); |
+ if (num_opt_pos_params > 0) { |
+ pieces.Add(kLBracket); |
+ } else { |
+ pieces.Add(kLBrace); |
+ } |
for (intptr_t i = num_fixed_params; i < num_params; i++) { |
- name = ParameterNameAt(i); |
- pieces.Add(name); |
- pieces.Add(kColonSpace); |
+ // The parameter name of an optional positional parameter does not need |
+ // to be part of the signature, since it is not used. |
+ if (!FLAG_reject_named_argument_as_positional || |
+ (num_opt_named_params > 0)) { |
+ name = ParameterNameAt(i); |
+ pieces.Add(name); |
+ pieces.Add(kColonSpace); |
+ } |
param_type = ParameterTypeAt(i); |
if (instantiate && !param_type.IsInstantiated()) { |
param_type = param_type.InstantiateFrom(instantiator); |
@@ -4472,7 +4680,11 @@ |
pieces.Add(kCommaSpace); |
} |
} |
- pieces.Add(kRBracket); |
+ if (num_opt_pos_params > 0) { |
+ pieces.Add(kRBracket); |
+ } else { |
+ pieces.Add(kRBrace); |
+ } |
} |
pieces.Add(kRParen); |
AbstractType& res_type = AbstractType::Handle(result_type()); |