Skip to content

Commit 0ce4905

Browse files
committed
Type check binary expressions
Fixes #188 [email protected] Review URL: https://codereview.chromium.org/1137543005
1 parent 772f6f6 commit 0ce4905

File tree

10 files changed

+107
-46
lines changed

10 files changed

+107
-46
lines changed

pkg/dev_compiler/lib/runtime/dart/_interceptors.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -446,8 +446,8 @@ var _js_embedded_names = dart.import(_js_embedded_names);
446446
}
447447
static _bitCount(i) {
448448
i = dart.as(dart.dsend(JSInt._shru(i, 0), '-', dart.dsend(JSInt._shru(i, 1), '&', 1431655765)), core.int);
449-
i = (dart.notNull(i) & 858993459)['+'](dart.dsend(JSInt._shru(i, 2), '&', 858993459));
450-
i = 252645135 & i['+'](JSInt._shru(i, 4));
449+
i = (dart.notNull(i) & 858993459)['+'](dart.as(dart.dsend(JSInt._shru(i, 2), '&', 858993459), core.num));
450+
i = 252645135 & dart.notNull(dart.notNull(i) + dart.notNull(dart.as(JSInt._shru(i, 4), core.num)));
451451
i = dart.notNull(i) + dart.notNull(dart.as(JSInt._shru(i, 8), core.int));
452452
i = dart.notNull(i) + dart.notNull(dart.as(JSInt._shru(i, 16), core.int));
453453
return dart.notNull(i) & 63;

pkg/dev_compiler/lib/runtime/dart/_js_helper.js

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ var _isolate_helper = dart.lazyImport(_isolate_helper);
123123
forEach(f) {
124124
dart.as(f, dart.functionType(dart.void, [K, V]));
125125
let keys = this[_keys];
126-
for (let i = 0; i['<'](dart.dload(keys, 'length')); i = dart.notNull(i) + 1) {
126+
for (let i = 0; dart.notNull(i) < dart.notNull(dart.as(dart.dload(keys, 'length'), core.num)); i = dart.notNull(i) + 1) {
127127
let key = dart.dindex(keys, i);
128128
f(dart.as(key, K), dart.as(this[_fetch](key), V));
129129
}
@@ -432,7 +432,7 @@ var _isolate_helper = dart.lazyImport(_isolate_helper);
432432
let context = window;
433433
let fun = function() {
434434
};
435-
for (let i = 0; i['<'](dart.dload(tags, 'length')); i = dart.notNull(i) + 1) {
435+
for (let i = 0; dart.notNull(i) < dart.notNull(dart.as(dart.dload(tags, 'length'), core.num)); i = dart.notNull(i) + 1) {
436436
let tag = dart.dindex(tags, i);
437437
let proto = dart.dcall(exports.prototypeForTagFunction, tag);
438438
if (proto != null) {
@@ -445,7 +445,7 @@ var _isolate_helper = dart.lazyImport(_isolate_helper);
445445
}
446446
}
447447
}
448-
for (let i = 0; i['<'](dart.dload(tags, 'length')); i = dart.notNull(i) + 1) {
448+
for (let i = 0; dart.notNull(i) < dart.notNull(dart.as(dart.dload(tags, 'length'), core.num)); i = dart.notNull(i) + 1) {
449449
let tag = tags[i];
450450
if (/^[A-Za-z_]/.test(tag)) {
451451
let interceptorClass = propertyGet(map, tag);
@@ -1318,7 +1318,7 @@ var _isolate_helper = dart.lazyImport(_isolate_helper);
13181318
if (hasNoField(s, `${_foreign_helper.JS_FUNCTION_TYPE_TAG()}`))
13191319
return false;
13201320
if (hasField(s, `${_foreign_helper.JS_FUNCTION_TYPE_VOID_RETURN_TAG()}`)) {
1321-
if (dart.dsend(hasNoField(t, `${_foreign_helper.JS_FUNCTION_TYPE_VOID_RETURN_TAG()}`), '&&', hasField(t, `${_foreign_helper.JS_FUNCTION_TYPE_RETURN_TYPE_TAG()}`))) {
1321+
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))) {
13221322
return false;
13231323
}
13241324
} else if (hasNoField(t, `${_foreign_helper.JS_FUNCTION_TYPE_VOID_RETURN_TAG()}`)) {
@@ -2010,8 +2010,8 @@ var _isolate_helper = dart.lazyImport(_isolate_helper);
20102010
if (dart.dsend(i, '<=', 65535)) {
20112011
a[core.$add](dart.as(i, core.int));
20122012
} else if (dart.dsend(i, '<=', 1114111)) {
2013-
a[core.$add]((55296)['+'](dart.dsend(dart.dsend(dart.dsend(i, '-', 65536), '>>', 10), '&', 1023)));
2014-
a[core.$add]((56320)['+'](dart.dsend(i, '&', 1023)));
2013+
a[core.$add]((55296)['+'](dart.as(dart.dsend(dart.dsend(dart.dsend(i, '-', 65536), '>>', 10), '&', 1023), core.num)));
2014+
a[core.$add]((56320)['+'](dart.as(dart.dsend(i, '&', 1023), core.num)));
20152015
} else {
20162016
throw new core.ArgumentError(i);
20172017
}
@@ -2030,14 +2030,14 @@ var _isolate_helper = dart.lazyImport(_isolate_helper);
20302030
return Primitives._fromCharCodeApply(dart.as(charCodes, core.List$(core.int)));
20312031
}
20322032
static stringFromCharCode(charCode) {
2033-
if ((0)['<='](charCode)) {
2033+
if (0 <= dart.notNull(dart.as(charCode, core.num))) {
20342034
if (dart.dsend(charCode, '<=', 65535)) {
20352035
return String.fromCharCode(charCode);
20362036
}
20372037
if (dart.dsend(charCode, '<=', 1114111)) {
20382038
let bits = dart.dsend(charCode, '-', 65536);
2039-
let low = (56320)['|'](dart.dsend(bits, '&', 1023));
2040-
let high = (55296)['|'](dart.dsend(bits, '>>', 10));
2039+
let low = (56320)['|'](dart.as(dart.dsend(bits, '&', 1023), core.int));
2040+
let high = (55296)['|'](dart.as(dart.dsend(bits, '>>', 10), core.int));
20412041
return String.fromCharCode(high, low);
20422042
}
20432043
}
@@ -2082,10 +2082,10 @@ var _isolate_helper = dart.lazyImport(_isolate_helper);
20822082
} else {
20832083
value = new Date(years, jsMonth, day, hours, minutes, seconds, milliseconds).valueOf();
20842084
}
2085-
if (dart.dsend(dart.dload(value, 'isNaN'), '||', dart.dsend(value, '<', -dart.notNull(MAX_MILLISECONDS_SINCE_EPOCH)))['||'](dart.dsend(value, '>', MAX_MILLISECONDS_SINCE_EPOCH))) {
2085+
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))) {
20862086
return null;
20872087
}
2088-
if (dart.dsend(dart.dsend(years, '<=', 0), '||', dart.dsend(years, '<', 100)))
2088+
if (dart.notNull(dart.as(dart.dsend(years, '<=', 0), core.bool)) || dart.notNull(dart.as(dart.dsend(years, '<', 100), core.bool)))
20892089
return Primitives.patchUpY2K(value, years, isUtc);
20902090
return value;
20912091
}
@@ -3642,7 +3642,7 @@ var _isolate_helper = dart.lazyImport(_isolate_helper);
36423642
static listToRti(list) {
36433643
list = list;
36443644
let result = [];
3645-
for (let i = 0; i['<'](dart.dload(list, 'length')); i = dart.notNull(i) + 1) {
3645+
for (let i = 0; dart.notNull(i) < dart.notNull(dart.as(dart.dload(list, 'length'), core.num)); i = dart.notNull(i) + 1) {
36463646
result.push(dart.dsend(dart.dindex(list, i), 'toRti'));
36473647
}
36483648
return result;
@@ -3721,7 +3721,7 @@ var _isolate_helper = dart.lazyImport(_isolate_helper);
37213721
dart.fn(buildNamedFunctionType, RuntimeFunctionType, [dart.dynamic, dart.dynamic, dart.dynamic]);
37223722
function buildInterfaceType(rti, typeArguments) {
37233723
let name = dart.as(rti.name, core.String);
3724-
if ((typeArguments == null)['||'](dart.dload(typeArguments, 'isEmpty'))) {
3724+
if (dart.notNull(typeArguments == null) || dart.notNull(dart.as(dart.dload(typeArguments, 'isEmpty'), core.bool))) {
37253725
return new RuntimeTypePlain(name);
37263726
}
37273727
return new RuntimeTypeGeneric(name, dart.as(typeArguments, core.List$(RuntimeType)), null);

pkg/dev_compiler/lib/runtime/dart/core.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,7 +1073,7 @@ var convert = dart.lazyImport(convert);
10731073
}
10741074
return report;
10751075
}
1076-
if (offset != -1 && (dart.notNull(offset) < 0 || offset['>'](dart.dload(this.source, 'length')))) {
1076+
if (offset != -1 && (dart.notNull(offset) < 0 || dart.notNull(offset) > dart.notNull(dart.as(dart.dload(this.source, 'length'), num)))) {
10771077
offset = -1;
10781078
}
10791079
if (offset == -1) {
@@ -1106,7 +1106,7 @@ var convert = dart.lazyImport(convert);
11061106
report = dart.notNull(report) + ` (at character ${dart.notNull(offset) + 1})\n`;
11071107
}
11081108
let lineEnd = dart.as(dart.dload(this.source, 'length'), int);
1109-
for (let i = offset; i['<'](dart.dload(this.source, 'length')); i = dart.notNull(i) + 1) {
1109+
for (let i = offset; dart.notNull(i) < dart.notNull(dart.as(dart.dload(this.source, 'length'), num)); i = dart.notNull(i) + 1) {
11101110
let char = dart.as(dart.dsend(this.source, 'codeUnitAt', i), int);
11111111
if (char == 10 || char == 13) {
11121112
lineEnd = i;

pkg/dev_compiler/lib/src/checker/checker.dart

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -705,14 +705,57 @@ class CodeChecker extends RecursiveAstVisitor {
705705
node.visitChildren(this);
706706
}
707707

708+
visitBinaryExpression(BinaryExpression node) {
709+
var op = node.operator;
710+
if (op.isUserDefinableOperator) {
711+
if (_rules.isDynamicTarget(node.leftOperand)) {
712+
// Dynamic invocation
713+
// TODO(vsm): Move this logic to the resolver?
714+
if (op.type != TokenType.EQ_EQ && op.type != TokenType.BANG_EQ) {
715+
_recordDynamicInvoke(node);
716+
}
717+
} else {
718+
var element = node.staticElement;
719+
// Method invocation.
720+
if (element is MethodElement) {
721+
var type = element.type as FunctionType;
722+
assert(type.normalParameterTypes.length == 1);
723+
node.rightOperand =
724+
checkArgument(node.rightOperand, type.normalParameterTypes[0]);
725+
} else {
726+
// TODO(vsm): Assert that the analyzer found an error here?
727+
}
728+
}
729+
} else {
730+
// Non-method operator.
731+
switch (op.type) {
732+
case TokenType.AMPERSAND_AMPERSAND:
733+
case TokenType.BAR_BAR:
734+
var boolType = _rules.provider.boolType;
735+
node.leftOperand = checkArgument(node.leftOperand, boolType);
736+
node.rightOperand = checkArgument(node.rightOperand, boolType);
737+
break;
738+
case TokenType.BANG_EQ:
739+
break;
740+
default:
741+
assert(false);
742+
}
743+
}
744+
node.visitChildren(this);
745+
}
746+
708747
DartType getType(TypeName name) {
709748
return (name == null) ? _rules.provider.dynamicType : name.type;
710749
}
711750

712751
Expression checkAssignment(Expression expr, DartType type) {
713-
final staticInfo = _rules.checkAssignment(expr, type, _constantContext);
714-
_recordMessage(staticInfo);
715-
if (staticInfo is Conversion) expr = staticInfo;
752+
if (expr is ParenthesizedExpression) {
753+
expr.expression = checkAssignment(expr.expression, type);
754+
} else {
755+
final staticInfo = _rules.checkAssignment(expr, type, _constantContext);
756+
_recordMessage(staticInfo);
757+
if (staticInfo is Conversion) expr = staticInfo;
758+
}
716759
return expr;
717760
}
718761

pkg/dev_compiler/lib/src/dart_sdk.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,18 +113,22 @@ final Map<String, String> mockSdkSources = {
113113
int get hashCode {}
114114
Type get runtimeType {}
115115
String toString(){}
116+
bool ==(other){}
116117
}
117118
class Function {}
118119
class StackTrace {}
119120
class Symbol {}
120121
class Type {}
121122
122-
class String {}
123+
class String {
124+
String operator +(String other) {}
125+
}
123126
class bool {}
124127
class num {
125128
num operator +(num other) {}
126129
}
127130
class int extends num {
131+
bool operator<(num other) {}
128132
int operator-() {}
129133
}
130134
class double extends num {}

pkg/dev_compiler/test/checker/checker_test.dart

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,8 @@ void main() {
108108
class A {
109109
String x = "hello world";
110110
111-
void baz1(y) => x + y;
112-
static baz2(y) => y + y;
111+
void baz1(y) => x + /*info:DynamicCast*/y;
112+
static baz2(y) => /*info:DynamicInvoke*/y + y;
113113
}
114114
115115
void foo(String str) {
@@ -979,43 +979,43 @@ void main() {
979979
f = /*severe:StaticTypeError*/new B();
980980
f = i2i;
981981
f = /*warning:DownCastComposite*/n2n;
982-
f = /*warning:DownCastComposite*/(i2i as Object);
983-
f = /*warning:DownCastComposite*/(n2n as Function);
982+
f = /*warning:DownCastComposite*/i2i as Object;
983+
f = /*warning:DownCastComposite*/n2n as Function;
984984
}
985985
{
986986
N2N f;
987987
f = /*severe:StaticTypeError*/new A();
988988
f = new B();
989989
f = /*warning:DownCastComposite*/i2i;
990990
f = n2n;
991-
f = /*warning:DownCastComposite*/(i2i as Object);
992-
f = /*warning:DownCastComposite*/(n2n as Function);
991+
f = /*warning:DownCastComposite*/i2i as Object;
992+
f = /*warning:DownCastComposite*/n2n as Function;
993993
}
994994
{
995995
A f;
996996
f = new A();
997997
f = /*severe:StaticTypeError*/new B();
998998
f = /*severe:StaticTypeError*/i2i;
999999
f = /*severe:StaticTypeError*/n2n;
1000-
f = /*warning:DownCastImplicit*/(i2i as Object);
1001-
f = /*warning:DownCastImplicit*/(n2n as Function);
1000+
f = /*warning:DownCastImplicit*/i2i as Object;
1001+
f = /*warning:DownCastImplicit*/n2n as Function;
10021002
}
10031003
{
10041004
B f;
10051005
f = /*severe:StaticTypeError*/new A();
10061006
f = new B();
10071007
f = /*severe:StaticTypeError*/i2i;
10081008
f = /*severe:StaticTypeError*/n2n;
1009-
f = /*warning:DownCastImplicit*/(i2i as Object);
1010-
f = /*warning:DownCastImplicit*/(n2n as Function);
1009+
f = /*warning:DownCastImplicit*/i2i as Object;
1010+
f = /*warning:DownCastImplicit*/n2n as Function;
10111011
}
10121012
{
10131013
Function f;
10141014
f = new A();
10151015
f = new B();
10161016
f = i2i;
10171017
f = n2n;
1018-
f = /*warning:DownCastImplicit*/(i2i as Object);
1018+
f = /*warning:DownCastImplicit*/i2i as Object;
10191019
f = (n2n as Function);
10201020
}
10211021
}
@@ -1042,10 +1042,10 @@ void main() {
10421042
typedef dynamic D(t1, t2);
10431043
10441044
void main() {
1045-
F f1 = (x, y) => x + y;
1046-
F<int> f2 = /*warning:ClosureWrapLiteral*/(x, y) => x + y;
1047-
D f3 = (x, y) => x + y;
1048-
Function f4 = (x, y) => x + y;
1045+
F f1 = (x, y) => /*info:DynamicInvoke*/x + y;
1046+
F<int> f2 = /*warning:ClosureWrapLiteral*/(x, y) => /*info:DynamicInvoke*/x + y;
1047+
D f3 = (x, y) => /*info:DynamicInvoke*/x + y;
1048+
Function f4 = (x, y) => /*info:DynamicInvoke*/x + y;
10491049
f2 = /*warning:ClosureWrap*/f1;
10501050
f1 = (int x, int y) => x + y;
10511051
f2 = /*severe:StaticTypeError*/(int x) => -x;
@@ -1955,20 +1955,34 @@ void main() {
19551955
B b = new B();
19561956
var c = foo();
19571957
a = a * b;
1958-
a = a * /*pass should be warning:DownCastImplicit*/c;
1958+
a = a * /*info:DynamicCast*/c;
19591959
a = a / b;
19601960
a = a ~/ b;
19611961
a = a % b;
19621962
a = a + b;
1963-
a = a + /*pass should be severe:StaticTypeError*/a;
1963+
a = a + /*severe:StaticTypeError*/a;
19641964
a = a - b;
19651965
b = /*severe:StaticTypeError*/b - b;
19661966
a = a << b;
19671967
a = a >> b;
19681968
a = a & b;
19691969
a = a ^ b;
19701970
a = a | b;
1971-
c = (/*pass should be info:DynamicInvoke*/c + b);
1971+
c = (/*info:DynamicInvoke*/c + b);
1972+
1973+
String x = 'hello';
1974+
int y = 42;
1975+
x = x + x;
1976+
x = x + /*info:DynamicCast*/c;
1977+
x = x + /*severe:StaticTypeError*/y;
1978+
1979+
bool p = true;
1980+
p = p && p;
1981+
p = p && /*info:DynamicCast*/c;
1982+
p = (/*info:DynamicCast*/c) && p;
1983+
p = (/*info:DynamicCast*/c) && /*info:DynamicCast*/c;
1984+
p = (/*severe:StaticTypeError*/y) && p;
1985+
p = c == y;
19721986
}
19731987
'''
19741988
});

pkg/dev_compiler/test/checker/inferred_type_test.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -669,7 +669,7 @@ void main() {
669669
dynamic a = new A();
670670
A b = /*info:DynamicCast*/a;
671671
print(/*info:DynamicInvoke*/a.x);
672-
print((/*info:DynamicInvoke*/a.x) + 2);
672+
print(/*info:DynamicInvoke*/(/*info:DynamicInvoke*/a.x) + 2);
673673
}
674674
'''
675675
});
@@ -1232,7 +1232,7 @@ void main() {
12321232
}
12331233
{
12341234
int f(int x) {};
1235-
A<int> = new A(f);
1235+
A<int> a = /*info:InferredTypeAllocation*/new A(f);
12361236
}
12371237
}
12381238
'''
@@ -1507,7 +1507,7 @@ void main() {
15071507
}
15081508
{
15091509
Function2<int, int> l0 = /*info:InferredTypeClosure*/(x) => x;
1510-
Function2<int, int> l1 = /*info:InferredTypeClosure*/(x) => x+1;
1510+
Function2<int, int> l1 = /*info:InferredTypeClosure*/(x) => /*info:DynamicInvoke should be pass*/x+1;
15111511
Function2<int, String> l2 = /*info:InferredTypeClosure should be severe:StaticTypeError*/(x) => x;
15121512
Function2<int, String> l3 = /*info:InferredTypeClosure should be severe:StaticTypeError*/(x) => /*info:DynamicInvoke should be pass*/x.substring(3);
15131513
Function2<String, String> l4 = /*info:InferredTypeClosure*/(x) => /*info:DynamicInvoke should be pass*/x.substring(3);

pkg/dev_compiler/test/codegen/expect/fieldtest.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ var core = dart.import(core);
7373
class Generic extends core.Object {
7474
foo(t) {
7575
dart.as(t, T);
76-
return core.print(dart.notNull(Generic$().bar) + dart.notNull(t));
76+
return core.print(dart.notNull(Generic$().bar) + dart.notNull(dart.as(t, core.String)));
7777
}
7878
}
7979
dart.setSignature(Generic, {

pkg/dev_compiler/test/codegen/fieldtest.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ class Derived extends BaseWithGetter {
4646
}
4747

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

5151
static String bar = 'hello';
5252
}

pkg/dev_compiler/test/dart_codegen/expect/core/exceptions.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ if (offset != -1) {
2424
}
2525
return report;
2626
}
27-
if (offset != -1 && (offset < 0 || offset > source.length)) {
27+
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))) {
2828
offset = -1;
2929
}
3030
if (offset == -1) {
@@ -59,7 +59,7 @@ report += " (at line $lineNum, character ${offset - lineStart + 1})\n";
5959
report += " (at character ${offset + 1})\n";
6060
}
6161
int lineEnd = DEVC$RT.cast(source.length, dynamic, int, "DynamicCast", """line 141, column 19 of dart:core/exceptions.dart: """, source.length is int, true);
62-
for (int i = offset; i < source.length; i++) {
62+
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++) {
6363
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));
6464
if (char == 0x0a || char == 0x0d) {
6565
lineEnd = i;

0 commit comments

Comments
 (0)