Fix receiver refining optimization in the presence of null: any Object method can be called on the null object.

R=karlklose@google.com

Review URL: https://codereview.chromium.org//23353002

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@26418 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
ngeoffray@google.com 2013-08-21 07:30:19 +00:00
parent 87530aa003
commit 4e107aa0c0
7 changed files with 40 additions and 4 deletions

View file

@ -21,8 +21,6 @@ class FlatTypeMask implements TypeMask {
FlatTypeMask(DartType base, int kind, bool isNullable)
: this.internal(base, (kind << 1) | (isNullable ? 1 : 0));
FlatTypeMask.empty()
: this.internal(null, (EMPTY << 1) | 1);
FlatTypeMask.exact(DartType base)
: this.internal(base, (EXACT << 1) | 1);
FlatTypeMask.subclass(DartType base)
@ -31,6 +29,7 @@ class FlatTypeMask implements TypeMask {
: this.internal(base, (SUBTYPE << 1) | 1);
const FlatTypeMask.nonNullEmpty(): base = null, flags = 0;
const FlatTypeMask.empty() : base = null, flags = 1;
FlatTypeMask.nonNullExact(DartType base)
: this.internal(base, EXACT << 1);

View file

@ -13,7 +13,7 @@ abstract class TypeMask {
factory TypeMask(DartType base, int kind, bool isNullable)
=> new FlatTypeMask(base, kind, isNullable);
factory TypeMask.empty() => new FlatTypeMask.empty();
const factory TypeMask.empty() = FlatTypeMask.empty;
factory TypeMask.exact(DartType base) => new FlatTypeMask.exact(base);
factory TypeMask.subclass(DartType base) => new FlatTypeMask.subclass(base);

View file

@ -220,6 +220,9 @@ class FullFunctionSetQuery extends FunctionSetQuery {
: [cls];
})
.map((cls) {
if (compiler.backend.isNullImplementation(cls)) {
return const TypeMask.empty();
}
return compiler.world.hasSubclasses(cls)
? new TypeMask.nonNullSubclass(cls.rawType)
: new TypeMask.nonNullExact(cls.rawType);

View file

@ -365,7 +365,7 @@ class JSBool extends Interceptor implements bool {
/**
* The interceptor class for [Null].
*
* This class defines implementations for *all* methods on [Object] since the
* This class defines implementations for *all* methods on [Object] since
* the methods on Object assume the receiver is non-null. This means that
* JSNull will always be in the interceptor set for methods defined on Object.
*/

View file

@ -154,6 +154,8 @@ const String DEFAULT_INTERCEPTORSLIB = r'''
class JSNull extends Interceptor {
bool operator==(other) => identical(null, other);
get hashCode => throw "JSNull.hashCode not implemented.";
String toString() => 'Null';
Type get runtimeType => null;
}
class JSBool extends Interceptor implements bool {
}

View file

@ -441,6 +441,14 @@ testSpecialization2() {
return a;
}
testSpecialization3() {
var a = returnDynamic() ? null : 42;
a.toString();
// Test that calling an [Object] method on [a] will not lead to
// infer that [a] is not null;
return a;
}
testReturnInvokeDynamicGetter() => new A().myFactory();
var topLevelConstList = const [42];
@ -582,6 +590,7 @@ main() {
testCascade2();
testSpecialization1();
testSpecialization2();
testSpecialization3();
}
""";
@ -706,4 +715,5 @@ void main() {
typesTask.rawTypeOf(findElement(compiler, 'CascadeHelper'))));
checkReturn('testSpecialization1', typesTask.numType);
checkReturn('testSpecialization2', typesTask.dynamicType);
checkReturn('testSpecialization3', typesTask.intType.nullable());
}

View file

@ -0,0 +1,22 @@
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// Regression test for dart2js that used to infer that code following
// a dynamic call could assume the receiver is not null. This does not
// work for Object methods.
import "package:expect/expect.dart";
import "compiler_annotations.dart";
main() {
var a = true ? null : 42;
a.toString();
foo(a);
}
@DontInline()
foo(a) {
var f = () => 42;
Expect.throws(() => a + 42, (e) => e is NoSuchMethodError);
}