blob: a3253b4fd8717c1b9a058b0b66f4231f7e525a17 [file] [log] [blame]
// Copyright (c) 2012, 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.
import 'dart:uri';
import '../../../sdk/lib/_internal/compiler/implementation/js_backend/js_backend.dart';
import '../../../sdk/lib/_internal/compiler/implementation/ssa/ssa.dart';
import '../../../sdk/lib/_internal/compiler/implementation/scanner/scannerlib.dart';
import 'compiler_helper.dart';
import 'parser_helper.dart';
void compileAndFind(String code,
String className,
String memberName,
bool disableInlining,
check(compiler, element)) {
Uri uri = new Uri.fromComponents(scheme: 'source');
var compiler = compilerFor(code, uri);
compiler.runCompiler(uri);
compiler.disableInlining = disableInlining;
var cls = findElement(compiler, className);
var member = cls.lookupMember(buildSourceString(memberName));
return check(compiler.backend, member);
}
const String TEST_1 = r"""
class A {
int f;
}
main() { new A(); }
""";
const String TEST_2 = r"""
class A {
int f1;
int f2 = 1;
}
main() { new A(); }
""";
const String TEST_3 = r"""
class A {
int f1;
int f2;
A() : f1 = 1;
}
main() { new A().f2 = 2; }
""";
const String TEST_4 = r"""
class A {
int f1;
int f2;
A() : f1 = 1;
}
main() {
A a = new A();
a.f1 = "a";
a.f2 = "a";
}
""";
const String TEST_5 = r"""
class A {
int f1 = 1;
int f2 = 1;
A(x) {
f1 = "1";
if (x) {
f2 = "1";
} else {
f2 = "2";
}
}
}
main() {
new A(true);
new A(false);
}
""";
const String TEST_6 = r"""
class A {
int f1 = 1;
int f2 = 1;
A(x) {
f1 = "1";
if (x) {
f2 = "1";
} else {
f2 = "2";
}
if (x) {
f2 = new List();
} else {
f2 = new List();
}
}
}
main() {
new A(true);
new A(false);
}
""";
const String TEST_7 = r"""
class A {
int f1 = 1;
int f2 = 1;
A(x) {
f1 = "1";
if (x) {
f2 = "1";
} else {
f2 = "2";
}
if (x) {
f1 = new List();
f2 = new List();
} else {
f2 = new List();
}
}
}
main() {
new A(true);
new A(false);
}
""";
const String TEST_8 = r"""
class A {
int f;
A(x) {
if (x) {
f = "1";
} else {
}
}
}
main() {
new A(true);
new A(false);
}
""";
const String TEST_9 = r"""
class A {
int f;
A(x) {
if (x) {
} else {
f = "1";
}
}
}
main() {
new A(true);
new A(false);
}
""";
const String TEST_10 = r"""
class A {
int f;
A() {
f = 1;
}
m() => f + 1;
}
void f(x) { x.f = "2"; }
main() {
A a;
f(a);
a = new A();
a.m();
}
""";
const String TEST_11 = r"""
class S {
int fs = 1;
ms() { fs = 1; }
}
class A extends S {
m() { ms(); }
}
main() {
A a = new A();
a.m();
}
""";
const String TEST_12 = r"""
class S {
int fs = 1;
S() { fs = "2"; }
}
class A extends S {
}
main() {
A a = new A();
}
""";
const String TEST_13 = r"""
class S {
int fs;
S() { fs = 1; }
}
class A extends S {
A() { fs = 1; }
}
main() {
A a = new A();
}
""";
const String TEST_14 = r"""
class A {
var f;
A() { f = 1; }
A.other() { f = 2; }
}
main() {
A a = new A();
a = new A.other();
}
""";
const String TEST_15 = r"""
class A {
var f;
A() { f = "1"; }
A.other() { f = new List(); }
}
main() {
A a = new A();
a = new A.other();
}
""";
const String TEST_16 = r"""
class A {
var f;
A() { f = "1"; }
A.other() : f = 1 { }
}
main() {
A a = new A();
a = new A.other();
}
""";
const String TEST_17 = r"""
g([p]) => p.f = 1;
class A {
var f;
A(x) {
var a;
if (x) {
a = this;
} else {
a = g;
}
a();
}
}
main() {
new A(true);
new A(false);
}
""";
// In this test this is only used in a field set (f3 = a) and therefore we infer
// types for f1, f2 and f3.
const String TEST_18 = r"""
class A {
var f1;
var f2;
var f3;
A(x) {
f1 = 1;
var a;
if (x) {
f2 = "1";
a = this;
} else {
a = 1;
f2 = "1";
}
f3 = a;
}
}
main() {
new A(true);
new A(false);
}
""";
// In this test this is exposed through a(), and therefore we don't infer
// any types.
const String TEST_19 = r"""
class A {
var f1;
var f2;
var f3;
A(x) {
f1 = 1;
var a;
if (x) {
f2 = "1";
a = this;
} else {
a = 1;
f2 = "1";
}
f3 = a;
a();
}
}
main() {
new A(true);
new A(false);
}
""";
void doTest(String test, bool disableInlining, Map<String, HType> fields) {
fields.forEach((String name, HType type) {
compileAndFind(
test,
'A',
name,
disableInlining,
(backend, field) {
HType inferredType = backend.optimisticFieldType(field);
Expect.equals(type, inferredType);
});
});
}
void runTest(String test, Map<String, HType> fields) {
doTest(test, false, fields);
doTest(test, true, fields);
}
void test() {
runTest(TEST_1, {'f': HType.NULL});
runTest(TEST_2, {'f1': HType.NULL, 'f2': HType.INTEGER});
runTest(TEST_3, {'f1': HType.INTEGER, 'f2': HType.INTEGER_OR_NULL});
runTest(TEST_4, {'f1': HType.UNKNOWN, 'f2': HType.STRING_OR_NULL});
runTest(TEST_5, {'f1': HType.STRING, 'f2': HType.STRING});
runTest(TEST_6, {'f1': HType.STRING, 'f2': HType.EXTENDABLE_ARRAY});
runTest(TEST_7, {'f1': HType.INDEXABLE_PRIMITIVE,
'f2': HType.EXTENDABLE_ARRAY});
runTest(TEST_8, {'f': HType.UNKNOWN});
runTest(TEST_9, {'f': HType.UNKNOWN});
runTest(TEST_10, {'f': HType.UNKNOWN});
runTest(TEST_11, {'fs': HType.INTEGER});
runTest(TEST_12, {'fs': HType.STRING});
// TODO(sgjesse): We should actually infer int.
runTest(TEST_13, {'fs': HType.UNKNOWN});
// TODO(sgjesse): We should actually infer int.
runTest(TEST_14, {'f': HType.UNKNOWN});
runTest(TEST_15, {'f': HType.UNKNOWN});
runTest(TEST_16, {'f': HType.UNKNOWN});
runTest(TEST_17, {'f': HType.UNKNOWN});
runTest(TEST_18, {'f1': HType.INTEGER,
'f2': HType.STRING,
'f3': HType.UNKNOWN});
runTest(TEST_19, {'f1': HType.UNKNOWN,
'f2': HType.UNKNOWN,
'f3': HType.UNKNOWN});
}
void main() {
test();
}