| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "lib/error.h" | 5 #include "lib/error.h" |
| 6 | 6 |
| 7 #include "vm/bootstrap_natives.h" | 7 #include "vm/bootstrap_natives.h" |
| 8 #include "vm/exceptions.h" | 8 #include "vm/exceptions.h" |
| 9 #include "vm/object_store.h" | 9 #include "vm/object_store.h" |
| 10 #include "vm/runtime_entry.h" | 10 #include "vm/runtime_entry.h" |
| 11 #include "vm/stack_frame.h" | 11 #include "vm/stack_frame.h" |
| 12 | 12 |
| 13 namespace dart { | 13 namespace dart { |
| 14 | 14 |
| 15 DEFINE_FLAG(bool, trace_type_checks, false, "Trace runtime type checks."); | 15 DEFINE_FLAG(bool, trace_type_checks, false, "Trace runtime type checks."); |
| 16 DECLARE_FLAG(bool, print_stack_trace_at_throw); | |
| 17 | |
| 18 | |
| 19 // Static helpers for allocating, initializing, and throwing an error instance. | |
| 20 | |
| 21 // Return the script of the Dart function that called the native entry or the | |
| 22 // runtime entry. The frame iterator points to the callee. | |
| 23 static RawScript* GetCallerScript(DartFrameIterator* iterator) { | |
| 24 DartFrame* caller_frame = iterator->NextFrame(); | |
| 25 ASSERT(caller_frame != NULL); | |
| 26 const Function& caller = Function::Handle(caller_frame->LookupDartFunction()); | |
| 27 ASSERT(!caller.IsNull()); | |
| 28 const Class& caller_class = Class::Handle(caller.owner()); | |
| 29 return caller_class.script(); | |
| 30 } | |
| 31 | |
| 32 | |
| 33 // Allocate a new instance of the given class name. | |
| 34 // TODO(hausner): Rename this NewCoreInstance to call out the fact that | |
| 35 // the class name is resolved in the core library implicitly? | |
| 36 static RawInstance* NewInstance(const char* class_name) { | |
| 37 const String& cls_name = String::Handle(String::NewSymbol(class_name)); | |
| 38 const Library& core_lib = Library::Handle(Library::CoreLibrary()); | |
| 39 Class& cls = Class::Handle(core_lib.LookupClass(cls_name)); | |
| 40 ASSERT(!cls.IsNull()); | |
| 41 // There are no parameterized error types, so no need to set type arguments. | |
| 42 return Instance::New(cls); | |
| 43 } | |
| 44 | |
| 45 | |
| 46 // Assign the value to the field given by its name in the given instance. | |
| 47 static void SetField(const Instance& instance, | |
| 48 const Class& cls, | |
| 49 const char* field_name, | |
| 50 const Object& value) { | |
| 51 const Field& field = Field::Handle(cls.LookupInstanceField( | |
| 52 String::Handle(String::NewSymbol(field_name)))); | |
| 53 ASSERT(!field.IsNull()); | |
| 54 instance.SetField(field, value); | |
| 55 } | |
| 56 | |
| 57 | |
| 58 // Initialize the fields 'url', 'line', and 'column' in the given instance | |
| 59 // according to the given token location in the given script. | |
| 60 static void SetLocationFields(const Instance& instance, | |
| 61 const Class& cls, | |
| 62 const Script& script, | |
| 63 intptr_t location) { | |
| 64 SetField(instance, cls, "url", String::Handle(script.url())); | |
| 65 intptr_t line, column; | |
| 66 script.GetTokenLocation(location, &line, &column); | |
| 67 SetField(instance, cls, "line", Smi::Handle(Smi::New(line))); | |
| 68 SetField(instance, cls, "column", Smi::Handle(Smi::New(column))); | |
| 69 } | |
| 70 | |
| 71 | 16 |
| 72 // Allocate and throw a new AssertionError. | 17 // Allocate and throw a new AssertionError. |
| 73 // Arg0: index of the first token of the failed assertion. | 18 // Arg0: index of the first token of the failed assertion. |
| 74 // Arg1: index of the first token after the failed assertion. | 19 // Arg1: index of the first token after the failed assertion. |
| 75 // Return value: none, throws an exception. | 20 // Return value: none, throws an exception. |
| 76 DEFINE_NATIVE_ENTRY(AssertionError_throwNew, 2) { | 21 DEFINE_NATIVE_ENTRY(AssertionError_throwNew, 2) { |
| 77 intptr_t assertion_start = Smi::CheckedHandle(arguments->At(0)).Value(); | 22 intptr_t assertion_start = Smi::CheckedHandle(arguments->At(0)).Value(); |
| 78 intptr_t assertion_end = Smi::CheckedHandle(arguments->At(1)).Value(); | 23 intptr_t assertion_end = Smi::CheckedHandle(arguments->At(1)).Value(); |
| 79 | 24 |
| 80 // Allocate a new instance of type AssertionError. | 25 // Allocate a new instance of type AssertionError. |
| 81 const Instance& assertion_error = Instance::Handle( | 26 const Instance& assertion_error = Instance::Handle( |
| 82 NewInstance("AssertionError")); | 27 Exceptions::NewInstance("AssertionError")); |
| 83 | 28 |
| 84 // Initialize 'url', 'line', and 'column' fields. | 29 // Initialize 'url', 'line', and 'column' fields. |
| 85 DartFrameIterator iterator; | 30 DartFrameIterator iterator; |
| 86 iterator.NextFrame(); // Skip native call. | 31 iterator.NextFrame(); // Skip native call. |
| 87 const Script& script = Script::Handle(GetCallerScript(&iterator)); | 32 const Script& script = Script::Handle(Exceptions::GetCallerScript(&iterator)); |
| 88 const Class& cls = Class::Handle(assertion_error.clazz()); | 33 const Class& cls = Class::Handle(assertion_error.clazz()); |
| 89 SetLocationFields(assertion_error, cls, script, assertion_start); | 34 Exceptions::SetLocationFields(assertion_error, cls, script, assertion_start); |
| 90 | 35 |
| 91 // Initialize field 'failed_assertion' with source snippet. | 36 // Initialize field 'failed_assertion' with source snippet. |
| 92 intptr_t from_line, from_column; | 37 intptr_t from_line, from_column; |
| 93 script.GetTokenLocation(assertion_start, &from_line, &from_column); | 38 script.GetTokenLocation(assertion_start, &from_line, &from_column); |
| 94 intptr_t to_line, to_column; | 39 intptr_t to_line, to_column; |
| 95 script.GetTokenLocation(assertion_end, &to_line, &to_column); | 40 script.GetTokenLocation(assertion_end, &to_line, &to_column); |
| 96 SetField(assertion_error, cls, "failedAssertion", String::Handle( | 41 Exceptions::SetField(assertion_error, cls, "failedAssertion", String::Handle( |
| 97 script.GetSnippet(from_line, from_column, to_line, to_column))); | 42 script.GetSnippet(from_line, from_column, to_line, to_column))); |
| 98 | 43 |
| 99 // Throw AssertionError instance. | 44 // Throw AssertionError instance. |
| 100 Exceptions::Throw(assertion_error); | 45 Exceptions::Throw(assertion_error); |
| 101 UNREACHABLE(); | 46 UNREACHABLE(); |
| 102 } | 47 } |
| 103 | 48 |
| 104 | 49 |
| 105 // Allocate, initialize, and throw a TypeError. | |
| 106 static void ThrowTypeError(intptr_t location, | |
| 107 const String& src_type_name, | |
| 108 const String& dst_type_name, | |
| 109 const String& dst_name, | |
| 110 const String& malformed_error) { | |
| 111 // Allocate a new instance of TypeError. | |
| 112 const Instance& type_error = Instance::Handle(NewInstance("TypeError")); | |
| 113 | |
| 114 // Initialize 'url', 'line', and 'column' fields. | |
| 115 DartFrameIterator iterator; | |
| 116 const Script& script = Script::Handle(GetCallerScript(&iterator)); | |
| 117 const Class& cls = Class::Handle(type_error.clazz()); | |
| 118 // Location fields are defined in AssertionError, the superclass of TypeError. | |
| 119 const Class& assertion_error_class = Class::Handle(cls.SuperClass()); | |
| 120 SetLocationFields(type_error, assertion_error_class, script, location); | |
| 121 | |
| 122 // Initialize field 'failedAssertion' in AssertionError superclass. | |
| 123 // Printing the src_obj value would be possible, but ToString() is expensive | |
| 124 // and not meaningful for all classes, so we just print '$expr instanceof...'. | |
| 125 // Users should look at TypeError.ToString(), which contains more useful | |
| 126 // information than AssertionError.failedAssertion. | |
| 127 String& failed_assertion = String::Handle(String::New("$expr instanceof ")); | |
| 128 failed_assertion = String::Concat(failed_assertion, dst_type_name); | |
| 129 SetField(type_error, | |
| 130 assertion_error_class, | |
| 131 "failedAssertion", | |
| 132 failed_assertion); | |
| 133 | |
| 134 // Initialize field 'srcType'. | |
| 135 SetField(type_error, cls, "srcType", src_type_name); | |
| 136 | |
| 137 // Initialize field 'dstType'. | |
| 138 SetField(type_error, cls, "dstType", dst_type_name); | |
| 139 | |
| 140 // Initialize field 'dstName'. | |
| 141 SetField(type_error, cls, "dstName", dst_name); | |
| 142 | |
| 143 // Initialize field 'malformedError'. | |
| 144 SetField(type_error, cls, "malformedError", malformed_error); | |
| 145 | |
| 146 // Type errors in the core library may be difficult to diagnose. | |
| 147 // Print type error information before throwing the error when debugging. | |
| 148 if (FLAG_print_stack_trace_at_throw) { | |
| 149 if (!malformed_error.IsNull()) { | |
| 150 OS::Print("%s", malformed_error.ToCString()); | |
| 151 } else { | |
| 152 intptr_t line, column; | |
| 153 script.GetTokenLocation(location, &line, &column); | |
| 154 OS::Print("'%s': Failed type check: line %d pos %d: " | |
| 155 "type '%s' is not assignable to type '%s' of '%s'.\n", | |
| 156 String::Handle(script.url()).ToCString(), | |
| 157 line, column, | |
| 158 src_type_name.ToCString(), | |
| 159 dst_type_name.ToCString(), | |
| 160 dst_name.ToCString()); | |
| 161 } | |
| 162 } | |
| 163 // Throw TypeError instance. | |
| 164 Exceptions::Throw(type_error); | |
| 165 UNREACHABLE(); | |
| 166 } | |
| 167 | |
| 168 | |
| 169 // Allocate and throw a new TypeError. | 50 // Allocate and throw a new TypeError. |
| 170 // Arg0: index of the token of the failed type check. | 51 // Arg0: index of the token of the failed type check. |
| 171 // Arg1: src value. | 52 // Arg1: src value. |
| 172 // Arg2: dst type name. | 53 // Arg2: dst type name. |
| 173 // Arg3: dst name. | 54 // Arg3: dst name. |
| 174 // Arg4: malformed type error message. | 55 // Arg4: malformed type error message. |
| 175 // Return value: none, throws an exception. | 56 // Return value: none, throws an exception. |
| 176 DEFINE_NATIVE_ENTRY(TypeError_throwNew, 5) { | 57 DEFINE_NATIVE_ENTRY(TypeError_throwNew, 5) { |
| 177 intptr_t location = Smi::CheckedHandle(arguments->At(0)).Value(); | 58 intptr_t location = Smi::CheckedHandle(arguments->At(0)).Value(); |
| 178 const Instance& src_value = Instance::CheckedHandle(arguments->At(1)); | 59 const Instance& src_value = Instance::CheckedHandle(arguments->At(1)); |
| 179 const String& dst_type_name = String::CheckedHandle(arguments->At(2)); | 60 const String& dst_type_name = String::CheckedHandle(arguments->At(2)); |
| 180 const String& dst_name = String::CheckedHandle(arguments->At(3)); | 61 const String& dst_name = String::CheckedHandle(arguments->At(3)); |
| 181 const String& malformed_error = String::CheckedHandle(arguments->At(4)); | 62 const String& malformed_error = String::CheckedHandle(arguments->At(4)); |
| 182 const String& src_type_name = | 63 const String& src_type_name = |
| 183 String::Handle(Type::Handle(src_value.GetType()).Name()); | 64 String::Handle(Type::Handle(src_value.GetType()).Name()); |
| 184 ThrowTypeError(location, src_type_name, | 65 Exceptions::CreateAndThrowTypeError(location, src_type_name, |
| 185 dst_type_name, dst_name, malformed_error); | 66 dst_type_name, dst_name, malformed_error); |
| 186 } | 67 } |
| 187 | 68 |
| 188 | 69 |
| 189 // Allocate and throw a new FallThroughError. | 70 // Allocate and throw a new FallThroughError. |
| 190 // Arg0: index of the case clause token into which we fall through. | 71 // Arg0: index of the case clause token into which we fall through. |
| 191 // Return value: none, throws an exception. | 72 // Return value: none, throws an exception. |
| 192 DEFINE_NATIVE_ENTRY(FallThroughError_throwNew, 1) { | 73 DEFINE_NATIVE_ENTRY(FallThroughError_throwNew, 1) { |
| 193 GET_NATIVE_ARGUMENT(Smi, smi_pos, arguments->At(0)); | 74 GET_NATIVE_ARGUMENT(Smi, smi_pos, arguments->At(0)); |
| 194 intptr_t fallthrough_pos = smi_pos.Value(); | 75 intptr_t fallthrough_pos = smi_pos.Value(); |
| 195 | 76 |
| 196 // Allocate a new instance of type FallThroughError. | 77 // Allocate a new instance of type FallThroughError. |
| 197 const Instance& fallthrough_error = | 78 const Instance& fallthrough_error = |
| 198 Instance::Handle(NewInstance("FallThroughError")); | 79 Instance::Handle(Exceptions::NewInstance("FallThroughError")); |
| 199 ASSERT(!fallthrough_error.IsNull()); | 80 ASSERT(!fallthrough_error.IsNull()); |
| 200 | 81 |
| 201 // Initialize 'url' and 'line' fields. | 82 // Initialize 'url' and 'line' fields. |
| 202 DartFrameIterator iterator; | 83 DartFrameIterator iterator; |
| 203 iterator.NextFrame(); // Skip native call. | 84 iterator.NextFrame(); // Skip native call. |
| 204 const Script& script = Script::Handle(GetCallerScript(&iterator)); | 85 const Script& script = Script::Handle(Exceptions::GetCallerScript(&iterator)); |
| 205 const Class& cls = Class::Handle(fallthrough_error.clazz()); | 86 const Class& cls = Class::Handle(fallthrough_error.clazz()); |
| 206 SetField(fallthrough_error, cls, "url", String::Handle(script.url())); | 87 Exceptions::SetField(fallthrough_error, cls, "url", |
| 88 String::Handle(script.url())); |
| 207 intptr_t line, column; | 89 intptr_t line, column; |
| 208 script.GetTokenLocation(fallthrough_pos, &line, &column); | 90 script.GetTokenLocation(fallthrough_pos, &line, &column); |
| 209 SetField(fallthrough_error, cls, "line", Smi::Handle(Smi::New(line))); | 91 Exceptions::SetField(fallthrough_error, cls, "line", |
| 92 Smi::Handle(Smi::New(line))); |
| 210 | 93 |
| 211 // Throw FallThroughError instance. | 94 // Throw FallThroughError instance. |
| 212 Exceptions::Throw(fallthrough_error); | 95 Exceptions::Throw(fallthrough_error); |
| 213 UNREACHABLE(); | 96 UNREACHABLE(); |
| 214 } | 97 } |
| 215 | 98 |
| 216 | 99 |
| 217 // Allocate and throw StaticResolutionException. | 100 // Allocate and throw StaticResolutionException. |
| 218 // Arg0: index of the static call that was not resolved at compile time. | 101 // Arg0: index of the static call that was not resolved at compile time. |
| 219 // Return value: none, throws an exception. | 102 // Return value: none, throws an exception. |
| 220 DEFINE_NATIVE_ENTRY(StaticResolutionException_throwNew, 1) { | 103 DEFINE_NATIVE_ENTRY(StaticResolutionException_throwNew, 1) { |
| 221 GET_NATIVE_ARGUMENT(Smi, smi_pos, arguments->At(0)); | 104 GET_NATIVE_ARGUMENT(Smi, smi_pos, arguments->At(0)); |
| 222 intptr_t call_pos = smi_pos.Value(); | 105 intptr_t call_pos = smi_pos.Value(); |
| 223 // Allocate a new instance of type StaticResolutionException. | 106 // Allocate a new instance of type StaticResolutionException. |
| 224 const Instance& resolution_exception = | 107 const Instance& resolution_exception = |
| 225 Instance::Handle(NewInstance("StaticResolutionException")); | 108 Instance::Handle(Exceptions::NewInstance("StaticResolutionException")); |
| 226 ASSERT(!resolution_exception.IsNull()); | 109 ASSERT(!resolution_exception.IsNull()); |
| 227 | 110 |
| 228 // Initialize 'url', 'line', and 'column' fields. | 111 // Initialize 'url', 'line', and 'column' fields. |
| 229 DartFrameIterator iterator; | 112 DartFrameIterator iterator; |
| 230 iterator.NextFrame(); // Skip native call. | 113 iterator.NextFrame(); // Skip native call. |
| 231 const Script& script = Script::Handle(GetCallerScript(&iterator)); | 114 const Script& script = Script::Handle(Exceptions::GetCallerScript(&iterator)); |
| 232 const Class& cls = Class::Handle(resolution_exception.clazz()); | 115 const Class& cls = Class::Handle(resolution_exception.clazz()); |
| 233 SetLocationFields(resolution_exception, cls, script, call_pos); | 116 Exceptions::SetLocationFields(resolution_exception, cls, script, call_pos); |
| 234 | 117 |
| 235 intptr_t line, column; | 118 intptr_t line, column; |
| 236 script.GetTokenLocation(call_pos, &line, &column); | 119 script.GetTokenLocation(call_pos, &line, &column); |
| 237 SetField(resolution_exception, cls, "failedResolutionLine", | 120 Exceptions::SetField(resolution_exception, cls, "failedResolutionLine", |
| 238 String::Handle(script.GetLine(line))); | 121 String::Handle(script.GetLine(line))); |
| 239 | 122 |
| 240 Exceptions::Throw(resolution_exception); | 123 Exceptions::Throw(resolution_exception); |
| 241 UNREACHABLE(); | 124 UNREACHABLE(); |
| 242 } | 125 } |
| 243 | 126 |
| 244 | |
| 245 // Check that the type of the given instance is assignable to the given type. | |
| 246 // Arg0: index of the token of the assignment (source location). | |
| 247 // Arg1: instance being assigned. | |
| 248 // Arg2: type being assigned to. | |
| 249 // Arg3: type arguments of the instantiator of the type being assigned to. | |
| 250 // Arg4: name of instance being assigned to. | |
| 251 // Return value: instance if assignable, otherwise throw a TypeError. | |
| 252 DEFINE_RUNTIME_ENTRY(TypeCheck, 5) { | |
| 253 ASSERT(arguments.Count() == kTypeCheckRuntimeEntry.argument_count()); | |
| 254 intptr_t location = Smi::CheckedHandle(arguments.At(0)).Value(); | |
| 255 const Instance& src_instance = Instance::CheckedHandle(arguments.At(1)); | |
| 256 const AbstractType& dst_type = AbstractType::CheckedHandle(arguments.At(2)); | |
| 257 const AbstractTypeArguments& dst_type_instantiator = | |
| 258 AbstractTypeArguments::CheckedHandle(arguments.At(3)); | |
| 259 const String& dst_name = String::CheckedHandle(arguments.At(4)); | |
| 260 ASSERT(!dst_type.IsDynamicType()); // No need to check assignment. | |
| 261 ASSERT(!src_instance.IsNull()); // Already checked in inlined code. | |
| 262 | |
| 263 const bool is_assignable = | |
| 264 src_instance.IsAssignableTo(dst_type, dst_type_instantiator); | |
| 265 | |
| 266 if (FLAG_trace_type_checks) { | |
| 267 const Type& src_type = Type::Handle(src_instance.GetType()); | |
| 268 if (dst_type.IsInstantiated()) { | |
| 269 OS::Print("TypeCheck: '%s' %s assignable to '%s' of '%s'.\n", | |
| 270 String::Handle(src_type.Name()).ToCString(), | |
| 271 is_assignable ? "is" : "is not", | |
| 272 String::Handle(dst_type.Name()).ToCString(), | |
| 273 dst_name.ToCString()); | |
| 274 } else { | |
| 275 // Instantiate dst_type before printing. | |
| 276 const AbstractType& instantiated_dst_type = AbstractType::Handle( | |
| 277 dst_type.InstantiateFrom(dst_type_instantiator)); | |
| 278 OS::Print("TypeCheck: '%s' %s assignable to '%s' of '%s' " | |
| 279 "instantiated from '%s'.\n", | |
| 280 String::Handle(src_type.Name()).ToCString(), | |
| 281 is_assignable ? "is" : "is not", | |
| 282 String::Handle(instantiated_dst_type.Name()).ToCString(), | |
| 283 dst_name.ToCString(), | |
| 284 String::Handle(dst_type.Name()).ToCString()); | |
| 285 } | |
| 286 DartFrameIterator iterator; | |
| 287 DartFrame* caller_frame = iterator.NextFrame(); | |
| 288 ASSERT(caller_frame != NULL); | |
| 289 const Function& function = Function::Handle( | |
| 290 caller_frame->LookupDartFunction()); | |
| 291 OS::Print(" -> Function %s\n", function.ToFullyQualifiedCString()); | |
| 292 } | |
| 293 if (!is_assignable) { | |
| 294 const Type& src_type = Type::Handle(src_instance.GetType()); | |
| 295 const String& src_type_name = String::Handle(src_type.Name()); | |
| 296 String& dst_type_name = String::Handle(); | |
| 297 if (!dst_type.IsInstantiated()) { | |
| 298 // Instantiate dst_type before reporting the error. | |
| 299 const AbstractType& instantiated_dst_type = AbstractType::Handle( | |
| 300 dst_type.InstantiateFrom(dst_type_instantiator)); | |
| 301 dst_type_name = instantiated_dst_type.Name(); | |
| 302 } else { | |
| 303 dst_type_name = dst_type.Name(); | |
| 304 } | |
| 305 const String& no_malformed_type_error = String::Handle(); | |
| 306 ThrowTypeError(location, src_type_name, dst_type_name, dst_name, | |
| 307 no_malformed_type_error); | |
| 308 UNREACHABLE(); | |
| 309 } | |
| 310 arguments.SetReturn(src_instance); | |
| 311 } | |
| 312 | |
| 313 | |
| 314 // Report that the type of the given object is not bool in conditional context. | |
| 315 // Arg0: index of the token of the assignment (source location). | |
| 316 // Arg1: bad object. | |
| 317 // Return value: none, throws a TypeError. | |
| 318 DEFINE_RUNTIME_ENTRY(ConditionTypeError, 2) { | |
| 319 ASSERT(arguments.Count() == | |
| 320 kConditionTypeErrorRuntimeEntry.argument_count()); | |
| 321 intptr_t location = Smi::CheckedHandle(arguments.At(0)).Value(); | |
| 322 const Instance& src_instance = Instance::CheckedHandle(arguments.At(1)); | |
| 323 ASSERT(src_instance.IsNull() || !src_instance.IsBool()); | |
| 324 const Type& bool_interface = Type::Handle(Type::BoolInterface()); | |
| 325 const Type& src_type = Type::Handle(src_instance.GetType()); | |
| 326 const String& src_type_name = String::Handle(src_type.Name()); | |
| 327 const String& bool_type_name = String::Handle(bool_interface.Name()); | |
| 328 const String& expr = String::Handle(String::NewSymbol("boolean expression")); | |
| 329 const String& no_malformed_type_error = String::Handle(); | |
| 330 ThrowTypeError(location, src_type_name, bool_type_name, expr, | |
| 331 no_malformed_type_error); | |
| 332 UNREACHABLE(); | |
| 333 } | |
| 334 | |
| 335 | |
| 336 // Report that the type of the type check is malformed. | |
| 337 // Arg0: index of the token of the failed type check. | |
| 338 // Arg1: src value. | |
| 339 // Arg2: malformed type error message. | |
| 340 // Return value: none, throws an exception. | |
| 341 DEFINE_RUNTIME_ENTRY(MalformedTypeError, 3) { | |
| 342 ASSERT(arguments.Count() == | |
| 343 kMalformedTypeErrorRuntimeEntry.argument_count()); | |
| 344 intptr_t location = Smi::CheckedHandle(arguments.At(0)).Value(); | |
| 345 const Instance& src_value = Instance::CheckedHandle(arguments.At(1)); | |
| 346 const String& malformed_error = String::CheckedHandle(arguments.At(2)); | |
| 347 const String& dst_type_name = | |
| 348 String::Handle(String::NewSymbol("malformed type")); | |
| 349 const String& dst_name = String::Handle(String::NewSymbol("")); | |
| 350 const String& src_type_name = | |
| 351 String::Handle(Type::Handle(src_value.GetType()).Name()); | |
| 352 ThrowTypeError(location, src_type_name, | |
| 353 dst_type_name, dst_name, malformed_error); | |
| 354 UNREACHABLE(); | |
| 355 } | |
| 356 | |
| 357 | |
| 358 // Check that the type of each element of the given array is assignable to the | |
| 359 // given type. | |
| 360 // Arg0: index of the token of the rest argument declaration (source location). | |
| 361 // Arg1: rest argument array. | |
| 362 // Arg2: element declaration type. | |
| 363 // Arg3: type arguments of the instantiator of the element declaration type. | |
| 364 // Arg4: name of object being assigned to, i.e. name of rest argument. | |
| 365 // Return value: null if assignable, otherwise allocate and throw a TypeError. | |
| 366 DEFINE_RUNTIME_ENTRY(RestArgumentTypeCheck, 5) { | |
| 367 ASSERT(arguments.Count() == | |
| 368 kRestArgumentTypeCheckRuntimeEntry.argument_count()); | |
| 369 intptr_t location = Smi::CheckedHandle(arguments.At(0)).Value(); | |
| 370 const Array& rest_array = Array::CheckedHandle(arguments.At(1)); | |
| 371 const AbstractType& element_type = | |
| 372 AbstractType::CheckedHandle(arguments.At(2)); | |
| 373 const AbstractTypeArguments& element_type_instantiator = | |
| 374 AbstractTypeArguments::CheckedHandle(arguments.At(3)); | |
| 375 const String& rest_name = String::CheckedHandle(arguments.At(4)); | |
| 376 ASSERT(!element_type.IsDynamicType()); // No need to check assignment. | |
| 377 ASSERT(!rest_array.IsNull()); | |
| 378 | |
| 379 Instance& elem = Instance::Handle(); | |
| 380 for (intptr_t i = 0; i < rest_array.Length(); i++) { | |
| 381 elem ^= rest_array.At(i); | |
| 382 if (!elem.IsNull() && | |
| 383 !elem.IsAssignableTo(element_type, element_type_instantiator)) { | |
| 384 // Allocate and throw a new instance of TypeError. | |
| 385 char buf[256]; | |
| 386 OS::SNPrint(buf, sizeof(buf), "%s[%d]", | |
| 387 rest_name.ToCString(), static_cast<int>(i)); | |
| 388 const String& src_type_name = | |
| 389 String::Handle(Type::Handle(elem.GetType()).Name()); | |
| 390 String& dst_type_name = String::Handle(); | |
| 391 if (!element_type.IsInstantiated()) { | |
| 392 // Instantiate element_type before reporting the error. | |
| 393 const AbstractType& instantiated_element_type = AbstractType::Handle( | |
| 394 element_type.InstantiateFrom(element_type_instantiator)); | |
| 395 dst_type_name = instantiated_element_type.Name(); | |
| 396 } else { | |
| 397 dst_type_name = element_type.Name(); | |
| 398 } | |
| 399 const String& dst_name = String::Handle(String::New(buf)); | |
| 400 const String& no_malformed_type_error = String::Handle(); | |
| 401 ThrowTypeError(location, src_type_name, dst_type_name, dst_name, | |
| 402 no_malformed_type_error); | |
| 403 UNREACHABLE(); | |
| 404 } | |
| 405 } | |
| 406 } | |
| 407 | |
| 408 } // namespace dart | 127 } // namespace dart |
| OLD | NEW |