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

Unified Diff: tests/compiler/dart2js/type_checker_test.dart

Issue 13084013: Handle assignability for Send and SendSet (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Debug code removed. Created 7 years, 7 months 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 side-by-side diff with in-line comments
Download patch
Index: tests/compiler/dart2js/type_checker_test.dart
diff --git a/tests/compiler/dart2js/type_checker_test.dart b/tests/compiler/dart2js/type_checker_test.dart
index 1381be8a03a56f82fbae12d4f2a28dc5ac82f137..46a162104e19fa116038bb1aa391c3acb584e4b2 100644
--- a/tests/compiler/dart2js/type_checker_test.dart
+++ b/tests/compiler/dart2js/type_checker_test.dart
@@ -3,14 +3,16 @@
// BSD-style license that can be found in the LICENSE file.
import "package:expect/expect.dart";
+import '../../../sdk/lib/_internal/compiler/compiler.dart' as api;
import '../../../sdk/lib/_internal/compiler/implementation/elements/elements.dart';
import '../../../sdk/lib/_internal/compiler/implementation/tree/tree.dart';
import '../../../sdk/lib/_internal/compiler/implementation/util/util.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/source_file.dart';
import 'mock_compiler.dart';
import 'parser_helper.dart';
import '../../../sdk/lib/_internal/compiler/implementation/elements/modelx.dart'
- show ElementX;
+ show ElementX, CompilationUnitElementX;
import '../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart'
hide SourceString;
@@ -38,7 +40,8 @@ main() {
// testNewExpression,
testConditionalExpression,
testIfStatement,
- testThis];
+ testThis,
+ testOperatorsAssignability];
for (Function test in tests) {
setup();
test();
@@ -111,19 +114,22 @@ testOperators() {
analyze("{ var i = 1 ${op} 2; }");
analyze("{ var i = 1; i ${op}= 2; }");
analyze("{ int i; var j = (i = true) ${op} 2; }",
- MessageKind.NOT_ASSIGNABLE);
+ [MessageKind.NOT_ASSIGNABLE, MessageKind.OPERATOR_NOT_FOUND]);
analyze("{ int i; var j = 1 ${op} (i = true); }",
- MessageKind.NOT_ASSIGNABLE);
+ [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE]);
}
for (final op in ['-', '~']) {
analyze("{ var i = ${op}1; }");
- analyze("{ int i; var j = ${op}(i = true); }", MessageKind.NOT_ASSIGNABLE);
+ analyze("{ int i; var j = ${op}(i = true); }",
+ [MessageKind.NOT_ASSIGNABLE, MessageKind.OPERATOR_NOT_FOUND]);
}
for (final op in ['++', '--']) {
analyze("{ int i = 1; int j = i${op}; }");
analyze("{ int i = 1; bool j = i${op}; }", MessageKind.NOT_ASSIGNABLE);
- analyze("{ bool b = true; bool j = b${op}; }");
- analyze("{ bool b = true; int j = ${op}b; }");
+ analyze("{ bool b = true; bool j = b${op}; }",
+ MessageKind.OPERATOR_NOT_FOUND);
+ analyze("{ bool b = true; int j = ${op}b; }",
+ MessageKind.OPERATOR_NOT_FOUND);
}
for (final op in ['||', '&&']) {
analyze("{ bool b = (true ${op} false); }");
@@ -131,13 +137,21 @@ testOperators() {
analyze("{ bool b = (1 ${op} false); }", MessageKind.NOT_ASSIGNABLE);
analyze("{ bool b = (true ${op} 2); }", MessageKind.NOT_ASSIGNABLE);
}
- for (final op in ['>', '<', '<=', '>=', '==', '!=']) {
+ for (final op in ['>', '<', '<=', '>=']) {
analyze("{ bool b = 1 ${op} 2; }");
analyze("{ int i = 1 ${op} 2; }", MessageKind.NOT_ASSIGNABLE);
analyze("{ int i; bool b = (i = true) ${op} 2; }",
- MessageKind.NOT_ASSIGNABLE);
+ [MessageKind.NOT_ASSIGNABLE, MessageKind.OPERATOR_NOT_FOUND]);
analyze("{ int i; bool b = 1 ${op} (i = true); }",
- MessageKind.NOT_ASSIGNABLE);
+ [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE]);
+ }
+ for (final op in ['==', '!=']) {
+ analyze("{ bool b = 1 ${op} 2; }");
+ analyze("{ int i = 1 ${op} 2; }", MessageKind.NOT_ASSIGNABLE);
+ analyze("{ int i; bool b = (i = true) ${op} 2; }",
+ MessageKind.NOT_ASSIGNABLE);
+ analyze("{ int i; bool b = 1 ${op} (i = true); }",
+ MessageKind.NOT_ASSIGNABLE);
}
}
@@ -495,6 +509,277 @@ testThis() {
analyzeIn(foo, "{ Foo f = this; }");
}
+const String CLASSES_WITH_OPERATORS = '''
+class Operators {
+ Operators operator+(Operators other) => this;
karlklose 2013/05/17 09:36:53 Add a space between 'operator' and the symbol.
Johnni Winther 2013/05/17 11:46:33 Done.
+ Operators operator-(Operators other) => this;
+ Operators operator-() => this;
+ Operators operator*(Operators other) => this;
+ Operators operator/(Operators other) => this;
+ Operators operator%(Operators other) => this;
+ Operators operator~/(Operators other) => this;
+
+ Operators operator&(Operators other) => this;
+ Operators operator|(Operators other) => this;
+ Operators operator^(Operators other) => this;
+
+ Operators operator~() => this;
+
+ Operators operator<(Operators other) => true;
+ Operators operator>(Operators other) => false;
+ Operators operator<=(Operators other) => this;
+ Operators operator>=(Operators other) => this;
+
+ Operators operator<<(Operators other) => this;
+ Operators operator>>(Operators other) => this;
+
+ bool operator==(Operators other) => true;
+
+ Operators operator[](Operators key) => this;
+ void operator[]=(Operators key, Operators value) {}
+}
+
+class MismatchA {
+ int operator+(MismatchA other) => 0;
+ MismatchA operator-(int other) => this;
+
+ MismatchA operator[](int key) => this;
+ void operator[]=(int key, MismatchA value) {}
+}
+
+class MismatchB {
+ MismatchB operator+(MismatchB other) => this;
+
+ MismatchB operator[](int key) => this;
+ void operator[]=(String key, MismatchB value) {}
+}
+
+class MismatchC {
+ MismatchC operator+(MismatchC other) => this;
+
+ MismatchC operator[](int key) => this;
+ void operator[]=(int key, String value) {}
+}
+''';
+
+testOperatorsAssignability() {
+ compiler.parseScript(CLASSES_WITH_OPERATORS);
+
+ // Tests against Operators.
+
+ String header = """{
+ bool z;
karlklose 2013/05/17 09:36:53 It would be nice if the name 'b' was available for
+ Operators a = new Operators();
karlklose 2013/05/17 09:36:53 Why do we need the 'new Operator()'?
Johnni Winther 2013/05/17 11:46:33 We don't.
+ Operators b = new Operators();
+ Operators c;
+ """;
+
+ // Positive tests on operators.
+
+ analyze('$header c = a + b; }');
karlklose 2013/05/17 09:36:53 Perhaps add a local function check(text) => anal
Johnni Winther 2013/05/17 11:46:33 Done.
+ analyze('$header c = a - b; }');
+ analyze('$header c = -a; }');
+ analyze('$header c = a * b; }');
+ analyze('$header c = a / b; }');
+ analyze('$header c = a % b; }');
+ analyze('$header c = a ~/ b; }');
+
+ analyze('$header c = a & b; }');
+ analyze('$header c = a | b; }');
+ analyze('$header c = a ^ b; }');
+
+ analyze('$header c = ~a; }');
+
+ analyze('$header c = a < b; }');
+ analyze('$header c = a > b; }');
+ analyze('$header c = a <= b; }');
+ analyze('$header c = a >= b; }');
+
+ analyze('$header c = a << b; }');
+ analyze('$header c = a >> b; }');
+
+ analyze('$header c = a[b]; }');
+
+ analyze('$header a[b] = c; }');
+ analyze('$header a[b] += c; }');
+ analyze('$header a[b] -= c; }');
+ analyze('$header a[b] *= c; }');
+ analyze('$header a[b] /= c; }');
+ analyze('$header a[b] %= c; }');
+ analyze('$header a[b] ~/= c; }');
+ analyze('$header a[b] <<= c; }');
+ analyze('$header a[b] >>= c; }');
+ analyze('$header a[b] &= c; }');
+ analyze('$header a[b] |= c; }');
+ analyze('$header a[b] ^= c; }');
+
+ analyze('$header a += b; }');
+ analyze('$header a -= b; }');
+ analyze('$header a *= b; }');
+ analyze('$header a /= b; }');
+ analyze('$header a %= b; }');
+ analyze('$header a ~/= b; }');
+
+ analyze('$header a <<= b; }');
+ analyze('$header a >>= b; }');
+
+ analyze('$header a &= b; }');
+ analyze('$header a |= b; }');
+ analyze('$header a ^= b; }');
+
+ // Negative tests on operators.
+
+ // `0` is not assignable to operator+ on `a`.
karlklose 2013/05/17 09:36:53 Actually "The type of `0` is not assignable to the
Johnni Winther 2013/05/17 11:46:33 Added a comment on the terminology.
+ analyze('$header c = a + 0; }', MessageKind.NOT_ASSIGNABLE);
+ // `a + b` is not assignable to `z`.
+ analyze('$header z = a + b; }', MessageKind.NOT_ASSIGNABLE);
+
+ // `-a` is not assignable to `z`.
+ analyze('$header z = -a; }', MessageKind.NOT_ASSIGNABLE);
+
+ // `0` is not assignable to operator[] on `a`.
+ analyze('$header c = a[0]; }', MessageKind.NOT_ASSIGNABLE);
+ // `a[b]` is not assignable to `z`.
+ analyze('$header z = a[b]; }', MessageKind.NOT_ASSIGNABLE);
+
+ // `0` is not assignable to operator[] on `a`.
+ // Warning suppressed for `0` is not assignable to operator[]= on `a`.
+ analyze('$header a[0] *= c; }', MessageKind.NOT_ASSIGNABLE);
+ // `z` is not assignable to operator* on `a[0]`.
+ analyze('$header a[b] *= z; }', MessageKind.NOT_ASSIGNABLE);
+
+ analyze('$header b = a++; }', MessageKind.NOT_ASSIGNABLE);
+ analyze('$header b = ++a; }', MessageKind.NOT_ASSIGNABLE);
+ analyze('$header b = a--; }', MessageKind.NOT_ASSIGNABLE);
+ analyze('$header b = --a; }', MessageKind.NOT_ASSIGNABLE);
+
+ analyze('$header c = a[b]++; }', MessageKind.NOT_ASSIGNABLE);
+ analyze('$header c = ++a[b]; }', MessageKind.NOT_ASSIGNABLE);
+ analyze('$header c = a[b]--; }', MessageKind.NOT_ASSIGNABLE);
+ analyze('$header c = --a[b]; }', MessageKind.NOT_ASSIGNABLE);
+
+ analyze('$header z = a == b; }');
+ analyze('$header z = a != b; }');
+
+ analyze('$header z = z && z; }');
+ analyze('$header z = a && z; }', MessageKind.NOT_ASSIGNABLE);
+ analyze('$header z = z && b; }', MessageKind.NOT_ASSIGNABLE);
+ analyze('$header z = a && b; }',
+ [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE]);
+ analyze('$header a = a && b; }',
+ [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE,
+ MessageKind.NOT_ASSIGNABLE]);
+
+ analyze('$header z = z || z; }');
karlklose 2013/05/17 09:36:53 Perhaps you can combine l.664-671 and l.673-680 in
Johnni Winther 2013/05/17 11:46:33 Done.
+ analyze('$header z = a || z; }', MessageKind.NOT_ASSIGNABLE);
+ analyze('$header z = z || b; }', MessageKind.NOT_ASSIGNABLE);
+ analyze('$header z = a || b; }',
+ [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE]);
+ analyze('$header a = a || b; }',
+ [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE,
+ MessageKind.NOT_ASSIGNABLE]);
+
+ analyze('$header z = !z; }');
+ analyze('$header z = !a; }', MessageKind.NOT_ASSIGNABLE);
+ analyze('$header a = !z; }', MessageKind.NOT_ASSIGNABLE);
+ analyze('$header a = !a; }',
+ [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE]);
+
+
+ // Tests against MismatchA.
+
+ header = """{
+ MismatchA a = new MismatchA();
+ MismatchA b = new MismatchA();
+ MismatchA c;
+ """;
+
+ // Tests against int operator+(MismatchA other) => 0;
+
+ // `a + b` is not assignable to `c`.
+ analyze('$header c = a + b; }', MessageKind.NOT_ASSIGNABLE);
+ // `a + b` is not assignable to `a`.
+ analyze('$header a += b; }', MessageKind.NOT_ASSIGNABLE);
+ // `a[0] + b` is not assignable to `a[0]`.
+ analyze('$header a[0] += b; }', MessageKind.NOT_ASSIGNABLE);
+
+ // 1 is not applicable to operator+
+ analyze('$header b = a++; }', MessageKind.NOT_ASSIGNABLE);
+ // 1 is not applicable to operator+.
+ // `++a` of type int is not assignable to `b`.
+ analyze('$header b = ++a; }',
+ [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE]);
+
+ // 1 is not applicable to operator+.
+ analyze('$header b = a[0]++; }', MessageKind.NOT_ASSIGNABLE);
+ // 1 is not applicable to operator+.
+ // `++a[0]` of type int is not assignable to `b`.
+ analyze('$header b = ++a[0]; }',
+ [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE]);
+
+ // Tests against: MismatchA operator-(int other) => this;
+
+ // `a - b` is not assignable to `c`.
+ analyze('$header c = a + b; }', MessageKind.NOT_ASSIGNABLE);
+ // `a - b` is not assignable to `a`.
+ analyze('$header a += b; }', MessageKind.NOT_ASSIGNABLE);
+ // `a[0] - b` is not assignable to `a[0]`.
+ analyze('$header a[0] += b; }', MessageKind.NOT_ASSIGNABLE);
+
+ analyze('$header b = a--; }');
+ analyze('$header b = --a; }');
+
+ analyze('$header b = a[0]--; }');
+ analyze('$header b = --a[0]; }');
+
+ // Tests against MismatchB.
+
+ header = """{
+ MismatchB a = new MismatchB();
+ MismatchB b = new MismatchB();
+ MismatchB c;
+ """;
+
+ // Tests against:
+ // MismatchB operator[](int key) => this;
+ // void operator[]=(String key, MismatchB value) {}
+
+ // `0` is not applicable to operator[]= on `a`.
+ analyze('$header a[0] = b; }', MessageKind.NOT_ASSIGNABLE);
+
+ // `0` is not applicable to operator[]= on `a`.
+ analyze('$header a[0] += b; }', MessageKind.NOT_ASSIGNABLE);
+ // `""` is not applicable to operator[] on `a`.
+ analyze('$header a[""] += b; }', MessageKind.NOT_ASSIGNABLE);
+ // `c` is not applicable to operator[] on `a`.
+ // `c` is not applicable to operator[]= on `a`.
+ analyze('$header a[c] += b; }',
+ [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE]);
+
+
+ // Tests against MismatchB.
+
+ header = """{
+ MismatchC a = new MismatchC();
+ MismatchC b = new MismatchC();
+ MismatchC c;
+ """;
+
+ // Tests against:
+ // MismatchC operator[](int key) => this;
+ // void operator[]=(int key, String value) {}
+
+ // `b` is not assignable to `a[0]`.
+ analyze('$header a[0] += b; }', MessageKind.NOT_ASSIGNABLE);
+ // `0` is not applicable to operator+ on `a[0]`.
+ analyze('$header a[0] += ""; }',
+ [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE]);
+ // `true` is not applicable to operator+ on `a[0]`.
+ // `true` is not assignable to `a[0]`.
+ analyze('$header a[0] += true; }',
+ [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE]);
+}
+
const CLASS_WITH_METHODS = '''
class ClassWithMethods {
untypedNoArgumentMethod() {}
@@ -531,8 +816,45 @@ String returnWithType(String type, expression) {
Node parseExpression(String text) =>
parseBodyCode(text, (parser, token) => parser.parseExpression(token));
+const String NUM_SOURCE = '''
+abstract class num {
+ num operator +(num other);
+ num operator -(num other);
+ num operator *(num other);
+ num operator %(num other);
+ double operator /(num other);
+ int operator ~/(num other);
+ num operator -();
+ bool operator <(num other);
+ bool operator <=(num other);
+ bool operator >(num other);
+ bool operator >=(num other);
+}
+''';
+
+const String INT_SOURCE = '''
+abstract class int extends num {
+ int operator &(int other);
+ int operator |(int other);
+ int operator ^(int other);
+ int operator ~();
+ int operator <<(int shiftAmount);
+ int operator >>(int shiftAmount);
+ int operator -();
+}
+''';
+
void setup() {
- compiler = new MockCompiler();
+ RegExp classNum = new RegExp(r'abstract class num {}');
+ Expect.isTrue(DEFAULT_CORELIB.contains(classNum));
+ RegExp classInt = new RegExp(r'abstract class int extends num { }');
+ Expect.isTrue(DEFAULT_CORELIB.contains(classInt));
+
+ String CORE_SOURCE = DEFAULT_CORELIB
karlklose 2013/05/17 09:36:53 Should we make sure that classNum and ClassInt are
Johnni Winther 2013/05/17 11:46:33 We do - in the lines above.
+ .replaceAll(classNum, NUM_SOURCE)
+ .replaceAll(classInt, INT_SOURCE);
+
+ compiler = new MockCompiler(coreSource: CORE_SOURCE);
types = compiler.types;
voidType = compiler.types.voidType;
intType = compiler.intClass.computeType(compiler);
@@ -570,23 +892,56 @@ analyzeTopLevel(String text, [expectedWarnings]) {
}
}
+api.DiagnosticHandler createHandler(String text) {
+ return (uri, int begin, int end, String message, kind) {
+ SourceFile sourceFile;
+ if (uri == null) {
+ sourceFile = new SourceFile('analysis', text);
+ } else {
+ sourceFile = compiler.sourceFiles[uri.toString()];
+ }
+ if (sourceFile != null) {
+ print(sourceFile.getLocationMessage(message, begin, end, true, (x) => x));
+ } else {
+ print(message);
+ }
+ };
+}
+
analyze(String text, [expectedWarnings]) {
if (expectedWarnings == null) expectedWarnings = [];
if (expectedWarnings is !List) expectedWarnings = [expectedWarnings];
+ compiler.diagnosticHandler = createHandler(text);
+
Token tokens = scan(text);
NodeListener listener = new NodeListener(compiler, null);
Parser parser = new Parser(listener);
parser.parseStatement(tokens);
Node node = listener.popNode();
+ Element compilationUnit =
+ new CompilationUnitElementX(new Script(null, null), compiler.mainApp);
Element function = new ElementX(
- buildSourceString(''), ElementKind.FUNCTION, compiler.mainApp);
+ buildSourceString(''), ElementKind.FUNCTION, compilationUnit);
TreeElements elements = compiler.resolveNodeStatement(node, function);
TypeCheckerVisitor checker = new TypeCheckerVisitor(compiler, elements,
types);
compiler.clearWarnings();
checker.analyze(node);
compareWarningKinds(text, expectedWarnings, compiler.warnings);
+ compiler.diagnosticHandler = null;
+}
+
+void generateOutput(String text) {
+ for (WarningMessage message in compiler.warnings) {
+ var beginToken = message.node.getBeginToken();
+ var endToken = message.node.getEndToken();
+ int begin = beginToken.charOffset;
+ int end = endToken.charOffset+endToken.slowCharCount;
karlklose 2013/05/17 09:36:53 Add spaces around +.
Johnni Winther 2013/05/17 11:46:33 Done.
+ SourceFile sourceFile = new SourceFile('analysis', text);
+ print(sourceFile.getLocationMessage(message.message.toString(),
+ begin, end, true, (str) => str));
+ }
}
analyzeIn(ClassElement classElement, String text, [expectedWarnings]) {
@@ -603,7 +958,7 @@ analyzeIn(ClassElement classElement, String text, [expectedWarnings]) {
TypeCheckerVisitor checker = new TypeCheckerVisitor(compiler, elements,
types);
compiler.clearWarnings();
- checker.currentClass = classElement;
checker.analyze(node);
+ generateOutput(text);
compareWarningKinds(text, expectedWarnings, compiler.warnings);
}
« tests/compiler/dart2js/analyze_api_test.dart ('K') | « tests/compiler/dart2js/parser_helper.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698