Skip to content

Commit

Permalink
Type check binary expressions
Browse files Browse the repository at this point in the history
Fixes #188

R=leafp@google.com

Review URL: https://codereview.chromium.org/1137543005
  • Loading branch information
vsmenon committed May 20, 2015
1 parent 772f6f6 commit 0ce4905
Show file tree
Hide file tree
Showing 10 changed files with 107 additions and 46 deletions.
4 changes: 2 additions & 2 deletions pkg/dev_compiler/lib/runtime/dart/_interceptors.js
Original file line number Diff line number Diff line change
Expand Up @@ -446,8 +446,8 @@ var _js_embedded_names = dart.import(_js_embedded_names);
}
static _bitCount(i) {
i = dart.as(dart.dsend(JSInt._shru(i, 0), '-', dart.dsend(JSInt._shru(i, 1), '&', 1431655765)), core.int);
i = (dart.notNull(i) & 858993459)['+'](dart.dsend(JSInt._shru(i, 2), '&', 858993459));
i = 252645135 & i['+'](JSInt._shru(i, 4));
i = (dart.notNull(i) & 858993459)['+'](dart.as(dart.dsend(JSInt._shru(i, 2), '&', 858993459), core.num));
i = 252645135 & dart.notNull(dart.notNull(i) + dart.notNull(dart.as(JSInt._shru(i, 4), core.num)));
i = dart.notNull(i) + dart.notNull(dart.as(JSInt._shru(i, 8), core.int));
i = dart.notNull(i) + dart.notNull(dart.as(JSInt._shru(i, 16), core.int));
return dart.notNull(i) & 63;
Expand Down
26 changes: 13 additions & 13 deletions pkg/dev_compiler/lib/runtime/dart/_js_helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ var _isolate_helper = dart.lazyImport(_isolate_helper);
forEach(f) {
dart.as(f, dart.functionType(dart.void, [K, V]));
let keys = this[_keys];
for (let i = 0; i['<'](dart.dload(keys, 'length')); i = dart.notNull(i) + 1) {
for (let i = 0; dart.notNull(i) < dart.notNull(dart.as(dart.dload(keys, 'length'), core.num)); i = dart.notNull(i) + 1) {
let key = dart.dindex(keys, i);
f(dart.as(key, K), dart.as(this[_fetch](key), V));
}
Expand Down Expand Up @@ -432,7 +432,7 @@ var _isolate_helper = dart.lazyImport(_isolate_helper);
let context = window;
let fun = function() {
};
for (let i = 0; i['<'](dart.dload(tags, 'length')); i = dart.notNull(i) + 1) {
for (let i = 0; dart.notNull(i) < dart.notNull(dart.as(dart.dload(tags, 'length'), core.num)); i = dart.notNull(i) + 1) {
let tag = dart.dindex(tags, i);
let proto = dart.dcall(exports.prototypeForTagFunction, tag);
if (proto != null) {
Expand All @@ -445,7 +445,7 @@ var _isolate_helper = dart.lazyImport(_isolate_helper);
}
}
}
for (let i = 0; i['<'](dart.dload(tags, 'length')); i = dart.notNull(i) + 1) {
for (let i = 0; dart.notNull(i) < dart.notNull(dart.as(dart.dload(tags, 'length'), core.num)); i = dart.notNull(i) + 1) {
let tag = tags[i];
if (/^[A-Za-z_]/.test(tag)) {
let interceptorClass = propertyGet(map, tag);
Expand Down Expand Up @@ -1318,7 +1318,7 @@ var _isolate_helper = dart.lazyImport(_isolate_helper);
if (hasNoField(s, `${_foreign_helper.JS_FUNCTION_TYPE_TAG()}`))
return false;
if (hasField(s, `${_foreign_helper.JS_FUNCTION_TYPE_VOID_RETURN_TAG()}`)) {
if (dart.dsend(hasNoField(t, `${_foreign_helper.JS_FUNCTION_TYPE_VOID_RETURN_TAG()}`), '&&', hasField(t, `${_foreign_helper.JS_FUNCTION_TYPE_RETURN_TYPE_TAG()}`))) {
if (dart.notNull(dart.as(hasNoField(t, `${_foreign_helper.JS_FUNCTION_TYPE_VOID_RETURN_TAG()}`), core.bool)) && dart.notNull(dart.as(hasField(t, `${_foreign_helper.JS_FUNCTION_TYPE_RETURN_TYPE_TAG()}`), core.bool))) {
return false;
}
} else if (hasNoField(t, `${_foreign_helper.JS_FUNCTION_TYPE_VOID_RETURN_TAG()}`)) {
Expand Down Expand Up @@ -2010,8 +2010,8 @@ var _isolate_helper = dart.lazyImport(_isolate_helper);
if (dart.dsend(i, '<=', 65535)) {
a[core.$add](dart.as(i, core.int));
} else if (dart.dsend(i, '<=', 1114111)) {
a[core.$add]((55296)['+'](dart.dsend(dart.dsend(dart.dsend(i, '-', 65536), '>>', 10), '&', 1023)));
a[core.$add]((56320)['+'](dart.dsend(i, '&', 1023)));
a[core.$add]((55296)['+'](dart.as(dart.dsend(dart.dsend(dart.dsend(i, '-', 65536), '>>', 10), '&', 1023), core.num)));
a[core.$add]((56320)['+'](dart.as(dart.dsend(i, '&', 1023), core.num)));
} else {
throw new core.ArgumentError(i);
}
Expand All @@ -2030,14 +2030,14 @@ var _isolate_helper = dart.lazyImport(_isolate_helper);
return Primitives._fromCharCodeApply(dart.as(charCodes, core.List$(core.int)));
}
static stringFromCharCode(charCode) {
if ((0)['<='](charCode)) {
if (0 <= dart.notNull(dart.as(charCode, core.num))) {
if (dart.dsend(charCode, '<=', 65535)) {
return String.fromCharCode(charCode);
}
if (dart.dsend(charCode, '<=', 1114111)) {
let bits = dart.dsend(charCode, '-', 65536);
let low = (56320)['|'](dart.dsend(bits, '&', 1023));
let high = (55296)['|'](dart.dsend(bits, '>>', 10));
let low = (56320)['|'](dart.as(dart.dsend(bits, '&', 1023), core.int));
let high = (55296)['|'](dart.as(dart.dsend(bits, '>>', 10), core.int));
return String.fromCharCode(high, low);
}
}
Expand Down Expand Up @@ -2082,10 +2082,10 @@ var _isolate_helper = dart.lazyImport(_isolate_helper);
} else {
value = new Date(years, jsMonth, day, hours, minutes, seconds, milliseconds).valueOf();
}
if (dart.dsend(dart.dload(value, 'isNaN'), '||', dart.dsend(value, '<', -dart.notNull(MAX_MILLISECONDS_SINCE_EPOCH)))['||'](dart.dsend(value, '>', MAX_MILLISECONDS_SINCE_EPOCH))) {
if (dart.notNull(dart.as(dart.dload(value, 'isNaN'), core.bool)) || dart.notNull(dart.as(dart.dsend(value, '<', -dart.notNull(MAX_MILLISECONDS_SINCE_EPOCH)), core.bool)) || dart.notNull(dart.as(dart.dsend(value, '>', MAX_MILLISECONDS_SINCE_EPOCH), core.bool))) {
return null;
}
if (dart.dsend(dart.dsend(years, '<=', 0), '||', dart.dsend(years, '<', 100)))
if (dart.notNull(dart.as(dart.dsend(years, '<=', 0), core.bool)) || dart.notNull(dart.as(dart.dsend(years, '<', 100), core.bool)))
return Primitives.patchUpY2K(value, years, isUtc);
return value;
}
Expand Down Expand Up @@ -3642,7 +3642,7 @@ var _isolate_helper = dart.lazyImport(_isolate_helper);
static listToRti(list) {
list = list;
let result = [];
for (let i = 0; i['<'](dart.dload(list, 'length')); i = dart.notNull(i) + 1) {
for (let i = 0; dart.notNull(i) < dart.notNull(dart.as(dart.dload(list, 'length'), core.num)); i = dart.notNull(i) + 1) {
result.push(dart.dsend(dart.dindex(list, i), 'toRti'));
}
return result;
Expand Down Expand Up @@ -3721,7 +3721,7 @@ var _isolate_helper = dart.lazyImport(_isolate_helper);
dart.fn(buildNamedFunctionType, RuntimeFunctionType, [dart.dynamic, dart.dynamic, dart.dynamic]);
function buildInterfaceType(rti, typeArguments) {
let name = dart.as(rti.name, core.String);
if ((typeArguments == null)['||'](dart.dload(typeArguments, 'isEmpty'))) {
if (dart.notNull(typeArguments == null) || dart.notNull(dart.as(dart.dload(typeArguments, 'isEmpty'), core.bool))) {
return new RuntimeTypePlain(name);
}
return new RuntimeTypeGeneric(name, dart.as(typeArguments, core.List$(RuntimeType)), null);
Expand Down
4 changes: 2 additions & 2 deletions pkg/dev_compiler/lib/runtime/dart/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -1073,7 +1073,7 @@ var convert = dart.lazyImport(convert);
}
return report;
}
if (offset != -1 && (dart.notNull(offset) < 0 || offset['>'](dart.dload(this.source, 'length')))) {
if (offset != -1 && (dart.notNull(offset) < 0 || dart.notNull(offset) > dart.notNull(dart.as(dart.dload(this.source, 'length'), num)))) {
offset = -1;
}
if (offset == -1) {
Expand Down Expand Up @@ -1106,7 +1106,7 @@ var convert = dart.lazyImport(convert);
report = dart.notNull(report) + ` (at character ${dart.notNull(offset) + 1})\n`;
}
let lineEnd = dart.as(dart.dload(this.source, 'length'), int);
for (let i = offset; i['<'](dart.dload(this.source, 'length')); i = dart.notNull(i) + 1) {
for (let i = offset; dart.notNull(i) < dart.notNull(dart.as(dart.dload(this.source, 'length'), num)); i = dart.notNull(i) + 1) {
let char = dart.as(dart.dsend(this.source, 'codeUnitAt', i), int);
if (char == 10 || char == 13) {
lineEnd = i;
Expand Down
49 changes: 46 additions & 3 deletions pkg/dev_compiler/lib/src/checker/checker.dart
Original file line number Diff line number Diff line change
Expand Up @@ -705,14 +705,57 @@ class CodeChecker extends RecursiveAstVisitor {
node.visitChildren(this);
}

visitBinaryExpression(BinaryExpression node) {
var op = node.operator;
if (op.isUserDefinableOperator) {
if (_rules.isDynamicTarget(node.leftOperand)) {
// Dynamic invocation
// TODO(vsm): Move this logic to the resolver?
if (op.type != TokenType.EQ_EQ && op.type != TokenType.BANG_EQ) {
_recordDynamicInvoke(node);
}
} else {
var element = node.staticElement;
// Method invocation.
if (element is MethodElement) {
var type = element.type as FunctionType;
assert(type.normalParameterTypes.length == 1);
node.rightOperand =
checkArgument(node.rightOperand, type.normalParameterTypes[0]);
} else {
// TODO(vsm): Assert that the analyzer found an error here?
}
}
} else {
// Non-method operator.
switch (op.type) {
case TokenType.AMPERSAND_AMPERSAND:
case TokenType.BAR_BAR:
var boolType = _rules.provider.boolType;
node.leftOperand = checkArgument(node.leftOperand, boolType);
node.rightOperand = checkArgument(node.rightOperand, boolType);
break;
case TokenType.BANG_EQ:
break;
default:
assert(false);
}
}
node.visitChildren(this);
}

DartType getType(TypeName name) {
return (name == null) ? _rules.provider.dynamicType : name.type;
}

Expression checkAssignment(Expression expr, DartType type) {
final staticInfo = _rules.checkAssignment(expr, type, _constantContext);
_recordMessage(staticInfo);
if (staticInfo is Conversion) expr = staticInfo;
if (expr is ParenthesizedExpression) {
expr.expression = checkAssignment(expr.expression, type);
} else {
final staticInfo = _rules.checkAssignment(expr, type, _constantContext);
_recordMessage(staticInfo);
if (staticInfo is Conversion) expr = staticInfo;
}
return expr;
}

Expand Down
6 changes: 5 additions & 1 deletion pkg/dev_compiler/lib/src/dart_sdk.dart
Original file line number Diff line number Diff line change
Expand Up @@ -113,18 +113,22 @@ final Map<String, String> mockSdkSources = {
int get hashCode {}
Type get runtimeType {}
String toString(){}
bool ==(other){}
}
class Function {}
class StackTrace {}
class Symbol {}
class Type {}
class String {}
class String {
String operator +(String other) {}
}
class bool {}
class num {
num operator +(num other) {}
}
class int extends num {
bool operator<(num other) {}
int operator-() {}
}
class double extends num {}
Expand Down
50 changes: 32 additions & 18 deletions pkg/dev_compiler/test/checker/checker_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,8 @@ void main() {
class A {
String x = "hello world";
void baz1(y) => x + y;
static baz2(y) => y + y;
void baz1(y) => x + /*info:DynamicCast*/y;
static baz2(y) => /*info:DynamicInvoke*/y + y;
}
void foo(String str) {
Expand Down Expand Up @@ -979,43 +979,43 @@ void main() {
f = /*severe:StaticTypeError*/new B();
f = i2i;
f = /*warning:DownCastComposite*/n2n;
f = /*warning:DownCastComposite*/(i2i as Object);
f = /*warning:DownCastComposite*/(n2n as Function);
f = /*warning:DownCastComposite*/i2i as Object;
f = /*warning:DownCastComposite*/n2n as Function;
}
{
N2N f;
f = /*severe:StaticTypeError*/new A();
f = new B();
f = /*warning:DownCastComposite*/i2i;
f = n2n;
f = /*warning:DownCastComposite*/(i2i as Object);
f = /*warning:DownCastComposite*/(n2n as Function);
f = /*warning:DownCastComposite*/i2i as Object;
f = /*warning:DownCastComposite*/n2n as Function;
}
{
A f;
f = new A();
f = /*severe:StaticTypeError*/new B();
f = /*severe:StaticTypeError*/i2i;
f = /*severe:StaticTypeError*/n2n;
f = /*warning:DownCastImplicit*/(i2i as Object);
f = /*warning:DownCastImplicit*/(n2n as Function);
f = /*warning:DownCastImplicit*/i2i as Object;
f = /*warning:DownCastImplicit*/n2n as Function;
}
{
B f;
f = /*severe:StaticTypeError*/new A();
f = new B();
f = /*severe:StaticTypeError*/i2i;
f = /*severe:StaticTypeError*/n2n;
f = /*warning:DownCastImplicit*/(i2i as Object);
f = /*warning:DownCastImplicit*/(n2n as Function);
f = /*warning:DownCastImplicit*/i2i as Object;
f = /*warning:DownCastImplicit*/n2n as Function;
}
{
Function f;
f = new A();
f = new B();
f = i2i;
f = n2n;
f = /*warning:DownCastImplicit*/(i2i as Object);
f = /*warning:DownCastImplicit*/i2i as Object;
f = (n2n as Function);
}
}
Expand All @@ -1042,10 +1042,10 @@ void main() {
typedef dynamic D(t1, t2);
void main() {
F f1 = (x, y) => x + y;
F<int> f2 = /*warning:ClosureWrapLiteral*/(x, y) => x + y;
D f3 = (x, y) => x + y;
Function f4 = (x, y) => x + y;
F f1 = (x, y) => /*info:DynamicInvoke*/x + y;
F<int> f2 = /*warning:ClosureWrapLiteral*/(x, y) => /*info:DynamicInvoke*/x + y;
D f3 = (x, y) => /*info:DynamicInvoke*/x + y;
Function f4 = (x, y) => /*info:DynamicInvoke*/x + y;
f2 = /*warning:ClosureWrap*/f1;
f1 = (int x, int y) => x + y;
f2 = /*severe:StaticTypeError*/(int x) => -x;
Expand Down Expand Up @@ -1955,20 +1955,34 @@ void main() {
B b = new B();
var c = foo();
a = a * b;
a = a * /*pass should be warning:DownCastImplicit*/c;
a = a * /*info:DynamicCast*/c;
a = a / b;
a = a ~/ b;
a = a % b;
a = a + b;
a = a + /*pass should be severe:StaticTypeError*/a;
a = a + /*severe:StaticTypeError*/a;
a = a - b;
b = /*severe:StaticTypeError*/b - b;
a = a << b;
a = a >> b;
a = a & b;
a = a ^ b;
a = a | b;
c = (/*pass should be info:DynamicInvoke*/c + b);
c = (/*info:DynamicInvoke*/c + b);
String x = 'hello';
int y = 42;
x = x + x;
x = x + /*info:DynamicCast*/c;
x = x + /*severe:StaticTypeError*/y;
bool p = true;
p = p && p;
p = p && /*info:DynamicCast*/c;
p = (/*info:DynamicCast*/c) && p;
p = (/*info:DynamicCast*/c) && /*info:DynamicCast*/c;
p = (/*severe:StaticTypeError*/y) && p;
p = c == y;
}
'''
});
Expand Down
6 changes: 3 additions & 3 deletions pkg/dev_compiler/test/checker/inferred_type_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -669,7 +669,7 @@ void main() {
dynamic a = new A();
A b = /*info:DynamicCast*/a;
print(/*info:DynamicInvoke*/a.x);
print((/*info:DynamicInvoke*/a.x) + 2);
print(/*info:DynamicInvoke*/(/*info:DynamicInvoke*/a.x) + 2);
}
'''
});
Expand Down Expand Up @@ -1232,7 +1232,7 @@ void main() {
}
{
int f(int x) {};
A<int> = new A(f);
A<int> a = /*info:InferredTypeAllocation*/new A(f);
}
}
'''
Expand Down Expand Up @@ -1507,7 +1507,7 @@ void main() {
}
{
Function2<int, int> l0 = /*info:InferredTypeClosure*/(x) => x;
Function2<int, int> l1 = /*info:InferredTypeClosure*/(x) => x+1;
Function2<int, int> l1 = /*info:InferredTypeClosure*/(x) => /*info:DynamicInvoke should be pass*/x+1;
Function2<int, String> l2 = /*info:InferredTypeClosure should be severe:StaticTypeError*/(x) => x;
Function2<int, String> l3 = /*info:InferredTypeClosure should be severe:StaticTypeError*/(x) => /*info:DynamicInvoke should be pass*/x.substring(3);
Function2<String, String> l4 = /*info:InferredTypeClosure*/(x) => /*info:DynamicInvoke should be pass*/x.substring(3);
Expand Down
2 changes: 1 addition & 1 deletion pkg/dev_compiler/test/codegen/expect/fieldtest.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ var core = dart.import(core);
class Generic extends core.Object {
foo(t) {
dart.as(t, T);
return core.print(dart.notNull(Generic$().bar) + dart.notNull(t));
return core.print(dart.notNull(Generic$().bar) + dart.notNull(dart.as(t, core.String)));
}
}
dart.setSignature(Generic, {
Expand Down
2 changes: 1 addition & 1 deletion pkg/dev_compiler/test/codegen/fieldtest.dart
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class Derived extends BaseWithGetter {
}

class Generic<T> {
foo(T t) => print(bar + t);
foo(T t) => print(bar + (t as String));

static String bar = 'hello';
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ if (offset != -1) {
}
return report;
}
if (offset != -1 && (offset < 0 || offset > source.length)) {
if (offset != -1 && (offset < 0 || offset > DEVC$RT.cast(source.length, dynamic, num, "DynamicCast", """line 108, column 49 of dart:core/exceptions.dart: """, source.length is num, true))) {
offset = -1;
}
if (offset == -1) {
Expand Down Expand Up @@ -59,7 +59,7 @@ report += " (at line $lineNum, character ${offset - lineStart + 1})\n";
report += " (at character ${offset + 1})\n";
}
int lineEnd = DEVC$RT.cast(source.length, dynamic, int, "DynamicCast", """line 141, column 19 of dart:core/exceptions.dart: """, source.length is int, true);
for (int i = offset; i < source.length; i++) {
for (int i = offset; i < DEVC$RT.cast(source.length, dynamic, num, "DynamicCast", """line 142, column 30 of dart:core/exceptions.dart: """, source.length is num, true); i++) {
int char = ((__x5) => DEVC$RT.cast(__x5, dynamic, int, "DynamicCast", """line 143, column 18 of dart:core/exceptions.dart: """, __x5 is int, true))(source.codeUnitAt(i));
if (char == 0x0a || char == 0x0d) {
lineEnd = i;
Expand Down

0 comments on commit 0ce4905

Please sign in to comment.