blob: cfd0ba89bffcff072f67a4208506ea2270234bf7 [file] [log] [blame]
// 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.
import 'package:expect/expect.dart';
import
'../../../sdk/lib/_internal/compiler/implementation/types/types.dart'
show TypeMask;
import 'compiler_helper.dart';
import 'parser_helper.dart';
const String TEST = """
returnNum1(a) {
if (a) return 1;
else return 2.0;
}
returnNum2(a) {
if (a) return 1.0;
else return 2;
}
returnInt1(a) {
if (a) return 1;
else return 2;
}
returnDouble(a) {
if (a) return 1.0;
else return 2.0;
}
returnGiveUp(a) {
if (a) return 1;
else return 'foo';
}
returnInt2() {
var a = 42;
return a++;
}
returnInt5() {
var a = 42;
return ++a;
}
returnInt6() {
var a = 42;
a++;
return a;
}
returnIntOrNull(a) {
if (a) return 42;
}
returnInt3(a) {
if (a) return 42;
throw 42;
}
returnInt4() {
return (42);
}
returnInt7() {
return 42.abs();
}
returnInt8() {
return 42.remainder(54);
}
returnDynamic1() {
// Ensure that we don't intrisify a wrong call to [int.remainder].
return 42.remainder();
}
returnDynamic2() {
// Ensure that we don't intrisify a wrong call to [int.abs].
return 42.abs(42);
}
testIsCheck1(a) {
if (a is int) {
return a;
} else {
return 42;
}
}
testIsCheck2(a) {
if (a is !int) {
return 0;
} else {
return a;
}
}
testIsCheck3(a) {
if (a is !int) {
print('hello');
} else {
return a;
}
}
testIsCheck4(a) {
if (a is int) {
return a;
} else {
return 42;
}
}
testIsCheck5(a) {
if (a is !int) {
return 42;
} else {
return a;
}
}
testIsCheck6(a) {
if (a is !int) {
return a;
} else {
return 42;
}
}
testIsCheck7(a) {
if (a == 'foo' && a is int) {
return a;
} else {
return 42;
}
}
testIsCheck8(a) {
if (a == 'foo' || a is int) {
return a;
} else {
return 42;
}
}
testIsCheck9(a) {
return a is int ? a : 42;
}
testIsCheck10(a) {
return a is !int ? a : 42;
}
testIsCheck11(a) {
return a is !int ? 42 : a;
}
testIsCheck12(a) {
return a is int ? 42 : a;
}
testIsCheck13(a) {
while (a is int) {
return a;
}
return 42;
}
testIsCheck14(a) {
while (a is !int) {
return 42;
}
return a;
}
testIsCheck15(a) {
var c = 42;
do {
if (a) return c;
c = topLevelGetter();
} while (c is int);
return 42;
}
testIsCheck16(a) {
var c = 42;
do {
if (a) return c;
c = topLevelGetter();
} while (c is !int);
return 42;
}
testIsCheck17(a) {
var c = 42;
for (; c is int;) {
if (a) return c;
c = topLevelGetter();
}
return 42;
}
testIsCheck18(a) {
var c = 42;
for (; c is int;) {
if (a) return c;
c = topLevelGetter();
}
return c;
}
testIsCheck19(a) {
var c = 42;
for (; c is !int;) {
if (a) return c;
c = topLevelGetter();
}
return 42;
}
testIsCheck20() {
var c = topLevelGetter();
if (c != null && c is! bool && c is! int) {
return 42;
} else if (c is String) {
return c;
} else {
return 68;
}
}
returnAsString() {
return topLevelGetter() as String;
}
returnIntAsNum() {
return 0 as num;
}
typedef int Foo();
returnAsTypedef() {
return topLevelGetter() as Foo;
}
testDeadCode() {
return 42;
return 'foo';
}
testLabeledIf(a) {
var c;
L1: if (a > 1) {
if (a == 2) {
break L1;
}
c = 42;
} else {
c = 38;
}
return c;
}
testSwitch1() {
var a = null;
switch (topLevelGetter) {
case 100: a = 42.5; break;
case 200: a = 42; break;
}
return a;
}
testSwitch2() {
var a = null;
switch (topLevelGetter) {
case 100: a = 42; break;
case 200: a = 42; break;
default:
a = 43;
}
return a;
}
testSwitch3() {
var a = 42;
var b;
switch (topLevelGetter) {
L1: case 1: b = a + 42; break;
case 2: a = 'foo'; continue L1;
}
return b;
}
testSwitch4() {
switch(topLevelGetter) {
case 1: break;
default: break;
}
return 42;
}
testContinue1() {
var a = 42;
var b;
while (true) {
b = a + 54;
if (b == 42) continue;
a = 'foo';
}
return b;
}
testBreak1() {
var a = 42;
var b;
while (true) {
b = a + 54;
if (b == 42) break;
b = 'foo';
}
return b;
}
testContinue2() {
var a = 42;
var b;
while (true) {
b = a + 54;
if (b == 42) {
b = 'foo';
continue;
}
}
return b;
}
testBreak2() {
var a = 42;
var b;
while (true) {
b = a + 54;
if (b == 42) {
a = 'foo';
break;
}
}
return b;
}
testReturnInvokeDynamicGetter() => new A().myFactory();
get topLevelGetter => 42;
returnDynamic() => topLevelGetter(42);
returnTopLevelGetter() => topLevelGetter;
class A {
factory A() = A.generative;
A.generative();
operator==(other) => 42;
get myField => 42;
set myField(a) {}
returnInt1() => ++myField;
returnInt2() => ++this.myField;
returnInt3() => this.myField += 42;
returnInt4() => myField += 42;
operator[](index) => 42;
operator[]= (index, value) {}
returnInt5() => ++this[0];
returnInt6() => this[0] += 1;
get myFactory => () => 42;
}
class B extends A {
B() : super.generative();
returnInt1() => ++new A().myField;
returnInt2() => new A().myField += 4;
returnInt3() => ++new A()[0];
returnInt4() => new A()[0] += 42;
returnInt5() => ++super.myField;
returnInt6() => super.myField += 4;
returnInt7() => ++super[0];
returnInt8() => super[0] += 54;
returnInt9() => super.myField;
}
main() {
// Ensure a function class is being instantiated.
() => 42;
returnNum1(true);
returnNum2(true);
returnInt1(true);
returnInt2(true);
returnInt3(true);
returnInt4();
returnDouble(true);
returnGiveUp(true);
returnInt5();
returnInt6();
returnInt7();
returnInt8();
returnIntOrNull(true);
returnDynamic();
returnDynamic1();
returnDynamic2();
testIsCheck1(topLevelGetter());
testIsCheck2(topLevelGetter());
testIsCheck3(topLevelGetter());
testIsCheck4(topLevelGetter());
testIsCheck5(topLevelGetter());
testIsCheck6(topLevelGetter());
testIsCheck7(topLevelGetter());
testIsCheck8(topLevelGetter());
testIsCheck9(topLevelGetter());
testIsCheck10(topLevelGetter());
testIsCheck11(topLevelGetter());
testIsCheck12(topLevelGetter());
testIsCheck13(topLevelGetter());
testIsCheck14(topLevelGetter());
testIsCheck15(topLevelGetter());
testIsCheck16(topLevelGetter());
testIsCheck17(topLevelGetter());
testIsCheck18(topLevelGetter());
testIsCheck19(topLevelGetter());
testIsCheck20();
returnAsString();
returnIntAsNum();
returnAsTypedef();
returnTopLevelGetter();
testDeadCode();
testLabeledIf();
testSwitch1();
testSwitch2();
testSwitch3();
testSwitch4();
testContinue1();
testBreak1();
testContinue2();
testBreak2();
new A() == null;
new A()..returnInt1()
..returnInt2()
..returnInt3()
..returnInt4()
..returnInt5()
..returnInt6();
new B()..returnInt1()
..returnInt2()
..returnInt3()
..returnInt4()
..returnInt5()
..returnInt6()
..returnInt7()
..returnInt8()
..returnInt9();
testReturnInvokeDynamicGetter();
}
""";
void main() {
Uri uri = new Uri(scheme: 'source');
var compiler = compilerFor(TEST, uri);
compiler.runCompiler(uri);
var typesInferrer = compiler.typesTask.typesInferrer;
checkReturn(String name, type) {
var element = findElement(compiler, name);
Expect.equals(
type,
typesInferrer.internal.returnTypeOf[element].simplify(compiler),
name);
}
var interceptorType =
findTypeMask(compiler, 'Interceptor', 'nonNullSubclass');
checkReturn('returnNum1', typesInferrer.numType);
checkReturn('returnNum2', typesInferrer.numType);
checkReturn('returnInt1', typesInferrer.intType);
checkReturn('returnInt2', typesInferrer.intType);
checkReturn('returnDouble', typesInferrer.doubleType);
checkReturn('returnGiveUp', interceptorType);
checkReturn('returnInt5', typesInferrer.intType);
checkReturn('returnInt6', typesInferrer.intType);
checkReturn('returnIntOrNull', typesInferrer.intType.nullable());
checkReturn('returnInt3', typesInferrer.intType);
checkReturn('returnDynamic', typesInferrer.dynamicType);
checkReturn('returnInt4', typesInferrer.intType);
checkReturn('returnInt7', typesInferrer.intType);
checkReturn('returnInt8', typesInferrer.intType);
checkReturn('returnDynamic1', typesInferrer.dynamicType);
checkReturn('returnDynamic2', typesInferrer.dynamicType);
TypeMask intType = new TypeMask.nonNullSubtype(compiler.intClass.rawType);
checkReturn('testIsCheck1', intType);
checkReturn('testIsCheck2', intType);
checkReturn('testIsCheck3', intType.nullable());
checkReturn('testIsCheck4', intType);
checkReturn('testIsCheck5', intType);
checkReturn('testIsCheck6', typesInferrer.dynamicType);
checkReturn('testIsCheck7', intType);
checkReturn('testIsCheck8', typesInferrer.dynamicType);
checkReturn('testIsCheck9', intType);
checkReturn('testIsCheck10', typesInferrer.dynamicType);
checkReturn('testIsCheck11', intType);
checkReturn('testIsCheck12', typesInferrer.dynamicType);
checkReturn('testIsCheck13', intType);
checkReturn('testIsCheck14', typesInferrer.dynamicType);
checkReturn('testIsCheck15', intType);
checkReturn('testIsCheck16', typesInferrer.dynamicType);
checkReturn('testIsCheck17', intType);
checkReturn('testIsCheck18', typesInferrer.dynamicType);
checkReturn('testIsCheck19', typesInferrer.dynamicType);
checkReturn('testIsCheck20', typesInferrer.dynamicType.nonNullable());
checkReturn('returnAsString',
new TypeMask.subtype(compiler.stringClass.computeType(compiler)));
checkReturn('returnIntAsNum', typesInferrer.intType);
checkReturn('returnAsTypedef', typesInferrer.functionType.nullable());
checkReturn('returnTopLevelGetter', typesInferrer.intType);
checkReturn('testDeadCode', typesInferrer.intType);
checkReturn('testLabeledIf', typesInferrer.intType.nullable());
checkReturn('testSwitch1', typesInferrer.intType
.union(typesInferrer.doubleType, compiler).nullable().simplify(compiler));
checkReturn('testSwitch2', typesInferrer.intType);
checkReturn('testSwitch3', interceptorType.nullable());
checkReturn('testSwitch4', typesInferrer.intType);
checkReturn('testContinue1', interceptorType.nullable());
checkReturn('testBreak1', interceptorType.nullable());
checkReturn('testContinue2', interceptorType.nullable());
checkReturn('testBreak2', typesInferrer.intType.nullable());
checkReturn('testReturnInvokeDynamicGetter', typesInferrer.dynamicType);
checkReturnInClass(String className, String methodName, type) {
var cls = findElement(compiler, className);
var element = cls.lookupLocalMember(buildSourceString(methodName));
Expect.equals(type,
typesInferrer.internal.returnTypeOf[element].simplify(compiler));
}
checkReturnInClass('A', 'returnInt1', typesInferrer.intType);
checkReturnInClass('A', 'returnInt2', typesInferrer.intType);
checkReturnInClass('A', 'returnInt3', typesInferrer.intType);
checkReturnInClass('A', 'returnInt4', typesInferrer.intType);
checkReturnInClass('A', 'returnInt5', typesInferrer.intType);
checkReturnInClass('A', 'returnInt6', typesInferrer.intType);
checkReturnInClass('A', '==', interceptorType);
checkReturnInClass('B', 'returnInt1', typesInferrer.intType);
checkReturnInClass('B', 'returnInt2', typesInferrer.intType);
checkReturnInClass('B', 'returnInt3', typesInferrer.intType);
checkReturnInClass('B', 'returnInt4', typesInferrer.intType);
checkReturnInClass('B', 'returnInt5', typesInferrer.intType);
checkReturnInClass('B', 'returnInt6', typesInferrer.intType);
checkReturnInClass('B', 'returnInt7', typesInferrer.intType);
checkReturnInClass('B', 'returnInt8', typesInferrer.intType);
checkReturnInClass('B', 'returnInt9', typesInferrer.intType);
checkFactoryConstructor(String className) {
var cls = findElement(compiler, className);
var element = cls.localLookup(buildSourceString(className));
Expect.equals(new TypeMask.nonNullExact(cls.rawType),
typesInferrer.internal.returnTypeOf[element]);
}
checkFactoryConstructor('A');
}