Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit f555ae5

Browse files
johnniwinthercommit-bot@chromium.org
authored andcommitted
Trust type annotations in strong mode
Change-Id: I59019ec56e432a71c52637307fa4dd346fa27c1f Reviewed-on: https://dart-review.googlesource.com/50240 Commit-Queue: Johnni Winther <[email protected]> Reviewed-by: Sigmund Cherem <[email protected]>
1 parent 0a4a3be commit f555ae5

19 files changed

+258
-27
lines changed

pkg/compiler/lib/src/options.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -392,9 +392,9 @@ class CompilerOptions implements DiagnosticOptions {
392392
librariesSpecificationUri = _resolveLibrariesSpecification(libraryRoot);
393393

394394
if (strongMode) {
395-
// Strong mode represents implicit downcasts explicitly, so assignments
396-
// checks provide no additional value.
397-
assignmentCheckPolicy = CheckPolicy.ignored;
395+
// Strong mode always trusts type annotations (inferred or explicit), so
396+
// assignments checks should be trusted.
397+
assignmentCheckPolicy = CheckPolicy.trusted;
398398
if (omitImplicitChecks) {
399399
parameterCheckPolicy = CheckPolicy.trusted;
400400
implicitDowncastCheckPolicy = CheckPolicy.trusted;

pkg/compiler/lib/src/ssa/type_builder.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,6 @@ abstract class TypeBuilder {
9898
HInstruction original, DartType type,
9999
{int kind: HTypeConversion.CHECKED_MODE_CHECK}) {
100100
if (type == null) return original;
101-
if (builder.options.strongMode) return original;
102101
HInstruction checkedOrTrusted = original;
103102
if (builder.options.assignmentCheckPolicy.isTrusted) {
104103
checkedOrTrusted = _trustType(original, type);

pkg/compiler/lib/src/ssa/types_propagation.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ class SsaTypePropagator extends HBaseVisitor implements OptimizationPhase {
5555
// the phi thinks it has because new optimizations may imply
5656
// changing it.
5757
// In theory we would need to mark
58-
// the type of all other incoming edges as "unitialized" and take this
58+
// the type of all other incoming edges as "uninitialized" and take this
5959
// into account when doing the propagation inside the phis. Just
6060
// setting the propagated type is however easier.
6161
phi.instructionType = phi.inputs[0].instructionType;

tests/compiler/dart2js/equivalence/id_equivalence_helper.dart

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,7 @@ Future checkTests(Directory dataDir, ComputeMemberDataFunction computeFromAst,
477477
if (shouldContinue) continued = true;
478478
List<String> testOptions = options.toList();
479479
bool strongModeOnlyTest = false;
480+
bool trustTypeAnnotations = false;
480481
if (name.endsWith('_ea.dart')) {
481482
testOptions.add(Flags.enableAsserts);
482483
} else if (name.endsWith('_strong.dart')) {
@@ -486,6 +487,8 @@ Future checkTests(Directory dataDir, ComputeMemberDataFunction computeFromAst,
486487
}
487488
} else if (name.endsWith('_checked.dart')) {
488489
testOptions.add(Flags.enableCheckedMode);
490+
} else if (name.endsWith('_trust.dart')) {
491+
trustTypeAnnotations = true;
489492
}
490493

491494
print('----------------------------------------------------------------');
@@ -537,11 +540,15 @@ Future checkTests(Directory dataDir, ComputeMemberDataFunction computeFromAst,
537540
print('--skipped for ast-----------------------------------------------');
538541
} else {
539542
print('--from ast------------------------------------------------------');
543+
List<String> options = [Flags.useOldFrontend]..addAll(testOptions);
544+
if (trustTypeAnnotations) {
545+
options.add(Flags.trustTypeAnnotations);
546+
}
540547
MemberAnnotations<IdValue> annotations = expectedMaps[astMarker];
541548
CompiledData compiledData1 = await computeData(
542549
entryPoint, memorySourceFiles, computeFromAst,
543550
computeClassData: computeClassDataFromAst,
544-
options: [Flags.useOldFrontend]..addAll(testOptions),
551+
options: options,
545552
verbose: verbose,
546553
forUserLibrariesOnly: forUserLibrariesOnly,
547554
globalIds: annotations.globalData.keys);
@@ -555,11 +562,15 @@ Future checkTests(Directory dataDir, ComputeMemberDataFunction computeFromAst,
555562
print('--skipped for kernel--------------------------------------------');
556563
} else {
557564
print('--from kernel---------------------------------------------------');
565+
List<String> options = []..addAll(testOptions);
566+
if (trustTypeAnnotations) {
567+
options.add(Flags.trustTypeAnnotations);
568+
}
558569
MemberAnnotations<IdValue> annotations = expectedMaps[kernelMarker];
559570
CompiledData compiledData2 = await computeData(
560571
entryPoint, memorySourceFiles, computeFromKernel,
561572
computeClassData: computeClassDataFromKernel,
562-
options: testOptions,
573+
options: options,
563574
verbose: verbose,
564575
forUserLibrariesOnly: forUserLibrariesOnly,
565576
globalIds: annotations.globalData.keys);
@@ -575,11 +586,12 @@ Future checkTests(Directory dataDir, ComputeMemberDataFunction computeFromAst,
575586
print('--skipped for kernel (strong mode)----------------------------');
576587
} else {
577588
print('--from kernel (strong mode)-----------------------------------');
589+
List<String> options = [Flags.strongMode]..addAll(testOptions);
578590
MemberAnnotations<IdValue> annotations = expectedMaps[strongMarker];
579591
CompiledData compiledData2 = await computeData(
580592
entryPoint, memorySourceFiles, computeFromKernel,
581593
computeClassData: computeClassDataFromKernel,
582-
options: [Flags.strongMode]..addAll(testOptions),
594+
options: options,
583595
verbose: verbose,
584596
forUserLibrariesOnly: forUserLibrariesOnly,
585597
globalIds: annotations.globalData.keys);
@@ -708,7 +720,7 @@ Spannable computeSpannable(
708720
} else if (id is ElementId) {
709721
String memberName = id.memberName;
710722
bool isSetter = false;
711-
if (memberName != '[]=' && memberName.endsWith('=')) {
723+
if (memberName != '[]=' && memberName != '==' && memberName.endsWith('=')) {
712724
isSetter = true;
713725
memberName = memberName.substring(0, memberName.length - 1);
714726
}

tests/compiler/dart2js/equivalence/show_helper.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ ArgParser createArgParser() {
2020
argParser.addFlag('all', negatable: false, defaultsTo: false);
2121
argParser.addFlag('use-kernel', negatable: false, defaultsTo: false);
2222
argParser.addFlag('strong', negatable: false, defaultsTo: false);
23+
argParser.addFlag('omit-implicit-checks',
24+
negatable: false, defaultsTo: false);
25+
argParser.addFlag('trust-type-annotations',
26+
negatable: false, defaultsTo: false);
2327
return argParser;
2428
}
2529

@@ -34,6 +38,8 @@ show(ArgResults argResults, ComputeMemberDataFunction computeAstData,
3438
bool verbose = argResults['verbose'];
3539
bool strongMode = argResults['strong'];
3640
bool useKernel = argResults['use-kernel'] || strongMode;
41+
bool omitImplicitChecks = argResults['omit-implicit-checks'];
42+
bool trustTypeAnnotations = argResults['trust-type-annotations'];
3743

3844
String file = argResults.rest.first;
3945
Uri entryPoint = Uri.base.resolve(nativeToUriPath(file));
@@ -53,6 +59,12 @@ show(ArgResults argResults, ComputeMemberDataFunction computeAstData,
5359
if (strongMode) {
5460
options.add(Flags.strongMode);
5561
}
62+
if (trustTypeAnnotations) {
63+
options.add(Flags.trustTypeAnnotations);
64+
}
65+
if (omitImplicitChecks) {
66+
options.add(Flags.omitImplicitChecks);
67+
}
5668
CompiledData data = await computeData(
5769
entryPoint, const {}, useKernel ? computeKernelData : computeAstData,
5870
computeClassData:

tests/compiler/dart2js/inference/data/await.dart

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@ main() {
1616
////////////////////////////////////////////////////////////////////////////////
1717
1818
/*element: _method1:[null]*/
19-
_method1(/*[null|subclass=Object]*/ o) {}
19+
_method1(
20+
/*ast.[null|subclass=Object]*/
21+
/*kernel.[null|subclass=Object]*/
22+
/*strong.[null|subclass=JSInt]*/
23+
o) {}
2024

2125
/*element: awaitOfFuture:[exact=_Future]*/
2226
awaitOfFuture() async {
@@ -30,7 +34,11 @@ awaitOfFuture() async {
3034
////////////////////////////////////////////////////////////////////////////////
3135
3236
/*element: _method2:[null]*/
33-
_method2(/*[null|subclass=Object]*/ o) {}
37+
_method2(
38+
/*ast.[null|subclass=Object]*/
39+
/*kernel.[null|subclass=Object]*/
40+
/*strong.[null|subclass=JSInt]*/
41+
o) {}
3442

3543
/*element: awaitOfInt:[exact=_Future]*/
3644
awaitOfInt() async {
@@ -47,7 +55,11 @@ _method3(
4755
/*Container([exact=JSExtendableArray], element: [exact=JSUInt31], length: 1)*/ o) {}
4856

4957
/*element: _method4:[null]*/
50-
_method4(/*[null|subclass=Object]*/ o) {}
58+
_method4(
59+
/*ast.[null|subclass=Object]*/
60+
/*kernel.[null|subclass=Object]*/
61+
/*strong.[null|subclass=JSInt]*/
62+
o) {}
5163

5264
/*element: awaitForOfStream:[exact=_Future]*/
5365
awaitForOfStream() async {

tests/compiler/dart2js/inference/data/closure_tracer_28919.dart

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,16 +56,23 @@ foo2(int /*[exact=JSUInt31]*/ choice) {
5656
methods. /*invoke: [exact=JSExtendableArray]*/ add(
5757
/*[null]*/ (int /*[null|subclass=Object]*/ x) {
5858
res = x;
59-
sum = x + i;
59+
sum = x /*strong.invoke: [null|subclass=JSInt]*/ + i;
6060
});
6161
}
6262
methods /*[exact=JSExtendableArray]*/ [0](499);
6363
probe2res(res);
6464
probe2methods(methods);
6565
}
6666

67-
/*element: probe2res:[null|subclass=Object]*/
68-
probe2res(/*[null|subclass=Object]*/ x) => x;
67+
/*ast.element: probe2res:[null|subclass=Object]*/
68+
/*kernel.element: probe2res:[null|subclass=Object]*/
69+
/*strong.element: probe2res:[null|subclass=JSInt]*/
70+
probe2res(
71+
/*ast.[null|subclass=Object]*/
72+
/*kernel.[null|subclass=Object]*/
73+
/*strong.[null|subclass=JSInt]*/
74+
x) =>
75+
x;
6976

7077
/*element: probe2methods:[exact=JSExtendableArray]*/
7178
probe2methods(/*[exact=JSExtendableArray]*/ x) => x;

tests/compiler/dart2js/inference/data/deferred_load_get.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import 'package:expect/expect.dart' deferred as expect;
66

77
// Synthetic getter added by kernel.
88
/*kernel.element: __loadLibrary_expect:[null|subclass=Object]*/
9-
/*strong.element: __loadLibrary_expect:[null|subclass=Object]*/
9+
/*strong.element: __loadLibrary_expect:[null|exact=_Future]*/
1010

1111
/*element: main:[null]*/
1212
main() {

tests/compiler/dart2js/inference/data/expose_this_closure.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,11 @@ exposeThis2() => new Class2();
5858
5959
abstract class SuperClass1 {
6060
/*element: SuperClass1.:[exact=Class3]*/
61-
SuperClass1(/*[null|subclass=Object]*/ o);
61+
SuperClass1(
62+
/*ast.[null|subclass=Object]*/
63+
/*kernel.[null|subclass=Object]*/
64+
/*strong.[null|subclass=JSInt]*/
65+
o);
6266
}
6367

6468
class Class3 extends SuperClass1 {

tests/compiler/dart2js/inference/data/field_type.dart

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,12 @@ class A24 {
608608
bar24();
609609

610610
/*element: A24.+:Value([exact=JSString], value: "foo")*/
611-
operator +(/*[exact=JSUInt31]*/ other) => 'foo';
611+
operator +(
612+
/*ast.[exact=JSUInt31]*/
613+
/*kernel.[exact=JSUInt31]*/
614+
/*strong.[empty]*/
615+
other) =>
616+
'foo';
612617

613618
/*element: A24.bar24:[exact=JSDouble]*/
614619
bar24() => 42.5;

tests/compiler/dart2js/inference/data/for_in.dart

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ main() {
88
forInReturn();
99
forInReturnMulti();
1010
forInReturnRefined();
11+
forInReturnRefinedDynamic();
1112
testInForIn();
1213
operatorInForIn();
1314
updateInForIn();
@@ -31,7 +32,9 @@ forInDirect() {
3132
// Return element from a for-in loop on a list literal.
3233
////////////////////////////////////////////////////////////////////////////////
3334
34-
/*element: forInReturn:[null|subclass=Object]*/
35+
/*ast.element: forInReturn:[null|subclass=Object]*/
36+
/*kernel.element: forInReturn:[null|subclass=Object]*/
37+
/*strong.element: forInReturn:[null|subclass=JSInt]*/
3538
forInReturn() {
3639
/*iterator: Container([exact=JSExtendableArray], element: [exact=JSUInt31], length: 3)*/
3740
/*current: [exact=ArrayIterator]*/
@@ -75,6 +78,25 @@ forInReturnRefined() {
7578
/*current: [exact=ArrayIterator]*/
7679
/*moveNext: [exact=ArrayIterator]*/
7780
for (var a in [1, 2, 3]) {
81+
// TODO(johnniwinther): We should know the type of [a] here. Even if [a] has
82+
// type `dynamic`.
83+
a. /*strong.[null|subclass=JSInt]*/ isEven;
84+
a. /*[subclass=JSInt]*/ isEven;
85+
return a;
86+
}
87+
}
88+
89+
////////////////////////////////////////////////////////////////////////////////
90+
// Sequentially refine element and return it from a for-in loop on known list
91+
// type with a dynamic variable.
92+
////////////////////////////////////////////////////////////////////////////////
93+
94+
/*element: forInReturnRefinedDynamic:[null|subclass=JSInt]*/
95+
forInReturnRefinedDynamic() {
96+
/*iterator: Container([exact=JSExtendableArray], element: [exact=JSUInt31], length: 3)*/
97+
/*current: [exact=ArrayIterator]*/
98+
/*moveNext: [exact=ArrayIterator]*/
99+
for (dynamic a in [1, 2, 3]) {
78100
// TODO(johnniwinther): We should know the type of [a] here.
79101
a.isEven;
80102
a. /*[subclass=JSInt]*/ isEven;

tests/compiler/dart2js/inference/data/general.dart

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -589,7 +589,10 @@ testSpecialization2() {
589589
var a = topLevelGetter();
590590
// Make [a] a captured variable. This should disable receiver
591591
// specialization on [a].
592-
(/*[null|subclass=Object]*/ () => a.toString())();
592+
(/*ast.[null|subclass=Object]*/
593+
/*kernel.[null|subclass=Object]*/
594+
/*strong.[null|exact=JSString]*/
595+
() => a.toString())();
593596
a - 42;
594597
return a;
595598
}
@@ -664,9 +667,13 @@ returnTopLevelGetter() => topLevelGetter;
664667

665668
class A {
666669
factory A() = A.generative;
670+
667671
/*element: A.generative:[exact=A]*/
668672
A.generative();
669-
/*element: A.==:Union([exact=JSBool], [exact=JSUInt31])*/
673+
674+
/*ast.element: A.==:Union([exact=JSBool], [exact=JSUInt31])*/
675+
/*kernel.element: A.==:Union([exact=JSBool], [exact=JSUInt31])*/
676+
/*strong.element: A.==:[exact=JSBool]*/
670677
operator ==(/*Union([exact=JSString], [exact=JSUInt31])*/ other) =>
671678
42 as dynamic;
672679

tests/compiler/dart2js/inference/data/js_interop.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,7 @@ class Class1 {
2020
{/*[exact=JSUInt31]*/ a, /*Value([exact=JSString], value: "")*/ b});
2121
}
2222

23-
/*element: anonymousClass:[null|subclass=Object]*/
23+
/*ast.element: anonymousClass:[null|subclass=Object]*/
24+
/*kernel.element: anonymousClass:[null|subclass=Object]*/
25+
/*strong.element: anonymousClass:[null|subclass=JavaScriptObject]*/
2426
anonymousClass() => new Class1(a: 1, b: '');
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
/*element: main:[null]*/
6+
main() {
7+
dontTrustLocals();
8+
dontTrustFunctions();
9+
inferFromFunctions();
10+
}
11+
12+
////////////////////////////////////////////////////////////////////////////////
13+
// Test that we don't trust the explicit type of a local, unless we are in
14+
// strong mode.
15+
////////////////////////////////////////////////////////////////////////////////
16+
17+
/*element: _dontTrustLocals:[exact=JSBool]*/ _dontTrustLocals(
18+
int Function(int) /*[null|subclass=Closure]*/ f) {
19+
int c = f(0);
20+
return c /*strong.invoke: [null|subclass=JSInt]*/ == 0;
21+
}
22+
23+
/*element: dontTrustLocals:[null]*/
24+
dontTrustLocals() {
25+
_dontTrustLocals(/*[exact=JSUInt31]*/ (/*[exact=JSUInt31]*/ o) => o);
26+
_dontTrustLocals(null);
27+
}
28+
29+
////////////////////////////////////////////////////////////////////////////////
30+
// Test that we don't infer the type of a dynamic local from the type of the
31+
// function.
32+
////////////////////////////////////////////////////////////////////////////////
33+
34+
/*element: _dontTrustFunctions:[exact=JSBool]*/
35+
_dontTrustFunctions(int Function(int) /*[null|subclass=Closure]*/ f) {
36+
dynamic c = f(0);
37+
return c == 0;
38+
}
39+
40+
/*element: dontTrustFunctions:[null]*/
41+
dontTrustFunctions() {
42+
_dontTrustFunctions(/*[exact=JSUInt31]*/ (/*[exact=JSUInt31]*/ o) => o);
43+
_dontTrustFunctions(null);
44+
}
45+
46+
////////////////////////////////////////////////////////////////////////////////
47+
// Test that we don't infer the type of a 'var' local from the type of the
48+
// function, unless we are in strong mode.
49+
////////////////////////////////////////////////////////////////////////////////
50+
51+
/*element: _inferFromFunctions:[exact=JSBool]*/
52+
_inferFromFunctions(int Function(int) /*[null|subclass=Closure]*/ f) {
53+
var c = f(0);
54+
return c /*strong.invoke: [null|subclass=JSInt]*/ == 0;
55+
}
56+
57+
/*element: inferFromFunctions:[null]*/
58+
inferFromFunctions() {
59+
_inferFromFunctions(/*[exact=JSUInt31]*/ (/*[exact=JSUInt31]*/ o) => o);
60+
_inferFromFunctions(null);
61+
}

0 commit comments

Comments
 (0)