Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(466)

Side by Side Diff: frog/value.dart

Issue 8746005: Fix a bunch of issues with 'hidden' DOM types. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: removed dead code Created 9 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, 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 /** 5 /**
6 * Represents a meta-value for code generation. 6 * Represents a meta-value for code generation.
7 */ 7 */
8 class Value { 8 class Value {
9 /** The [Type] of the [Value]. */ 9 /** The [Type] of the [Value]. */
10 Type type; 10 Type type;
(...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after
286 return this; 286 return this;
287 } 287 }
288 288
289 if (checked && !toType.isSubtypeOf(type)) { 289 if (checked && !toType.isSubtypeOf(type)) {
290 // According to the static types, this conversion can't work. 290 // According to the static types, this conversion can't work.
291 convertWarning(toType, node); 291 convertWarning(toType, node);
292 } 292 }
293 293
294 // Generate a runtime checks if they're turned on, otherwise skip it. 294 // Generate a runtime checks if they're turned on, otherwise skip it.
295 if (options.enableTypeChecks) { 295 if (options.enableTypeChecks) {
296 return _typeAssert(context, toType, node); 296 return _typeAssert(context, toType, node, isDynamic);
297 } else { 297 } else {
298 return this; 298 return this;
299 } 299 }
300 } 300 }
301 301
302 /** 302 /**
303 * Checks whether [toType] is a callback function, and it is defined in the 303 * Checks whether [toType] is a callback function, and it is defined in the
304 * dom library. 304 * dom library.
305 */ 305 */
306 bool _isDomCallback(toType) { 306 bool _isDomCallback(toType) {
(...skipping 17 matching lines...) Expand all
324 world.gen.corejs.useWrap1 = true; 324 world.gen.corejs.useWrap1 = true;
325 } 325 }
326 return new Value(toType, '\$wrap_call\$$arity($code)', span); 326 return new Value(toType, '\$wrap_call\$$arity($code)', span);
327 } 327 }
328 328
329 /** 329 /**
330 * Generates a run time type assertion for the given value. This works like 330 * Generates a run time type assertion for the given value. This works like
331 * [instanceOf], but it allows null since Dart types are nullable. 331 * [instanceOf], but it allows null since Dart types are nullable.
332 * Also it will throw a TypeError if it gets the wrong type. 332 * Also it will throw a TypeError if it gets the wrong type.
333 */ 333 */
334 Value _typeAssert(MethodGenerator context, Type toType, Node node) { 334 Value _typeAssert(MethodGenerator context, Type toType, Node node,
335 bool isDynamic) {
335 if (toType is ParameterType) { 336 if (toType is ParameterType) {
336 ParameterType p = toType; 337 ParameterType p = toType;
337 toType = p.extendsType; 338 toType = p.extendsType;
338 } 339 }
339 340
340 // TODO(jmesserly): fix checking of function types, and DOM objects 341 if (toType.isObject || toType.isVar) {
341 // For now, don't generate a broken check. 342 world.internalError(
342 // (For DOM types to work right, we need to lazily patch the "is$DOMWindow" 343 'We thought ${type.name} is not a subtype of ${toType.name}?');
343 // check methods, by catching it on Object.prototype like VarMember does)
344 if (toType.getCallMethod() != null || toType.library == world.dom) {
345 return this;
346 } 344 }
347 345
348 if (toType.isObject || toType.isVar) { 346 final typeError = world.corelib.types['TypeError'];
349 world.internalError('We thought ${type.name} is not a subtype of ${toType. name}?'); 347 final typeErrorCtor = typeError.getConstructor('_internal');
350 } 348 world.gen.corejs.ensureTypeNameOf();
349 final result = typeErrorCtor.invoke(context, node,
350 new Value.type(typeError, null),
351 new Arguments(null, [
352 new Value(world.objectType, 'this', null),
353 new Value(world.stringType, '"${toType.name}"', null)]),
354 isDynamic);
355 world.gen.corejs.useThrow = true;
356 final throwTypeError = '\$throw(${result.code})';
351 357
352 // TODO(jmesserly): better assert for integers? 358 // TODO(jmesserly): better assert for integers?
353 if (toType.isNum) toType = world.numType; 359 if (toType.isNum) toType = world.numType;
354 360
355 // Generate a check like these: 361 // Generate a check like these:
356 // obj && obj.is$TypeName() 362 // obj && obj.is$TypeName()
357 // $assert_int(obj) 363 // $assert_int(obj)
358 // 364 //
359 // We rely on the fact that calling an undefined method produces a JS 365 // We rely on the fact that calling an undefined method produces a JS
360 // TypeError. Alternatively we could define fallbacks on Object that throw. 366 // TypeError. Alternatively we could define fallbacks on Object that throw.
361 String check; 367 String check;
362 if (toType.isVoid) { 368 if (toType.isVoid) {
363 check = '\$assert_void($code)'; 369 check = '\$assert_void($code)';
364 if (toType.typeCheckCode == null) { 370 if (toType.typeCheckCode == null) {
365 toType.typeCheckCode = ''' 371 toType.typeCheckCode = '''
366 function \$assert_void(x) { 372 function \$assert_void(x) {
367 return x == null ? x : x.is\$void(); // throws TypeError 373 if (x == null) return null;
374 $throwTypeError
368 }'''; 375 }''';
369 } 376 }
370 } else if (toType == world.nonNullBool) { 377 } else if (toType == world.nonNullBool) {
371 // This could be made less of a special case 378 // This could be made less of a special case
372 world.gen.corejs.useNotNullBool = true; 379 world.gen.corejs.useNotNullBool = true;
373 check = '\$notnull_bool($code)'; 380 check = '\$notnull_bool($code)';
374 381
375 } else if (toType.library.isCore && toType.typeofName != null) { 382 } else if (toType.library.isCore && toType.typeofName != null) {
376 check = '\$assert_${toType.name}($code)'; 383 check = '\$assert_${toType.name}($code)';
377 384
378 if (toType.typeCheckCode == null) { 385 if (toType.typeCheckCode == null) {
379 toType.typeCheckCode = ''' 386 toType.typeCheckCode = '''
380 function \$assert_${toType.name}(x) { 387 function \$assert_${toType.name}(x) {
381 if (x == null || typeof(x) == "${toType.typeofName}") return x; 388 if (x == null || typeof(x) == "${toType.typeofName}") return x;
382 throw new TypeError("'" + x + "' is not a ${toType.name}."); 389 $throwTypeError
383 }'''; 390 }''';
384 } 391 }
385 } else { 392 } else {
386 toType.isTested = true; 393 toType.isChecked = true;
394
395 String checkName = 'assert\$' + toType.jsname;
387 396
388 // If we track nullability, we could simplify this check. 397 // If we track nullability, we could simplify this check.
389 var temp = context.getTemp(this); 398 var temp = context.getTemp(this);
390 check = '(${context.assignTemp(temp, this).code} &&'; 399 check = '(${context.assignTemp(temp, this).code} == null ? null :';
391 check += ' ${temp.code}.is\$${toType.jsname}())'; 400 check += ' ${temp.code}.$checkName())';
392 if (this != temp) context.freeTemp(temp); 401 if (this != temp) context.freeTemp(temp);
402
403 // Generate the fallback on Object (that throws a TypeError)
404 if (!world.objectType.varStubs.containsKey(checkName)) {
405 world.objectType.varStubs[checkName] =
406 new VarMethodStub(checkName, null, Arguments.EMPTY, throwTypeError);
407 }
393 } 408 }
394 409
395 return new Value(toType, check, span); 410 return new Value(toType, check, span);
396 } 411 }
397 412
398 /** 413 /**
399 * Test to see if value is an instance of this type. 414 * Test to see if value is an instance of this type.
400 * 415 *
401 * - If a primitive type, then uses the JavaScript typeof. 416 * - If a primitive type, then uses the JavaScript typeof.
402 * - If it's a non-generic class, use instanceof. 417 * - If it's a non-generic class, use instanceof.
(...skipping 18 matching lines...) Expand all
421 return new EvaluatedValue(world.nonNullBool, true, 'true', null); 436 return new EvaluatedValue(world.nonNullBool, true, 'true', null);
422 } 437 }
423 } 438 }
424 439
425 if (toType.library.isCore) { 440 if (toType.library.isCore) {
426 var typeofName = toType.typeofName; 441 var typeofName = toType.typeofName;
427 if (typeofName != null) { 442 if (typeofName != null) {
428 testCode = "(typeof($code) ${isTrue ? '==' : '!='} '$typeofName')"; 443 testCode = "(typeof($code) ${isTrue ? '==' : '!='} '$typeofName')";
429 } 444 }
430 } 445 }
431 if (toType.isClass && toType is !ConcreteType) { 446 if (toType.isClass && toType is !ConcreteType
447 && !toType.isHiddenNativeType) {
432 toType.markUsed(); 448 toType.markUsed();
433 testCode = '($code instanceof ${toType.jsname})'; 449 testCode = '($code instanceof ${toType.jsname})';
434 if (!isTrue) { 450 if (!isTrue) {
435 testCode = '!' + testCode; 451 testCode = '!' + testCode;
436 } 452 }
437 } 453 }
438 if (testCode == null) { 454 if (testCode == null) {
439 toType.isTested = true; 455 toType.isTested = true;
440 456
441 // If we track nullability, we could simplify this check. 457 // If we track nullability, we could simplify this check.
442 var temp = context.getTemp(this); 458 var temp = context.getTemp(this);
443 459
460 String checkName = 'is\$${toType.jsname}';
444 testCode = '(${context.assignTemp(temp, this).code} &&'; 461 testCode = '(${context.assignTemp(temp, this).code} &&';
445 testCode += ' ${temp.code}.is\$${toType.jsname})'; 462 testCode += ' ${temp.code}.$checkName())';
446 if (isTrue) { 463 if (isTrue) {
447 // Add !! to convert to boolean. 464 // Add !! to convert to boolean.
448 // TODO(jimhug): only do this if needed 465 // TODO(jimhug): only do this if needed
449 testCode = '!!' + testCode; 466 testCode = '!!' + testCode;
450 } else { 467 } else {
451 // The single ! here nicely converts undefined to false and function 468 // The single ! here nicely converts undefined to false and function
452 // to true. 469 // to true.
453 testCode = '!' + testCode; 470 testCode = '!' + testCode;
454 } 471 }
455 if (this != temp) context.freeTemp(temp); 472 if (this != temp) context.freeTemp(temp);
473
474 // Generate the fallback on Object (that returns false)
475 if (!world.objectType.varStubs.containsKey(checkName)) {
476 world.objectType.varStubs[checkName] =
477 new VarMethodStub(checkName, null, Arguments.EMPTY, 'return false');
478 }
456 } 479 }
457 return new Value(world.nonNullBool, testCode, span); 480 return new Value(world.nonNullBool, testCode, span);
458 } 481 }
459 482
460 void convertWarning(Type toType, Node node) { 483 void convertWarning(Type toType, Node node) {
461 // TODO(jmesserly): better error messages for type conversion failures 484 // TODO(jmesserly): better error messages for type conversion failures
462 world.warning('type "${type.name}" is not assignable to "${toType.name}"', 485 world.warning('type "${type.name}" is not assignable to "${toType.name}"',
463 node.span); 486 node.span);
464 } 487 }
465 488
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after
726 // Then look for members in my library. 749 // Then look for members in my library.
727 member = home.library.lookup(name, span); 750 member = home.library.lookup(name, span);
728 if (member != null) { 751 if (member != null) {
729 return member; 752 return member;
730 } 753 }
731 754
732 _ensureCode(); 755 _ensureCode();
733 return null; 756 return null;
734 } 757 }
735 } 758 }
OLDNEW
« frog/lib/corelib.dart ('K') | « frog/type.dart ('k') | frog/var_member.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698