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

Side by Side Diff: pkg/kernel/lib/verifier.dart

Issue 2531873002: Add --verify-ir flag to dartk and test.py. (Closed)
Patch Set: Minor fixes Created 4 years 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 unified diff | Download patch
« no previous file with comments | « pkg/kernel/lib/transformations/flags.dart ('k') | pkg/kernel/test/baseline_tester.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2016, 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 library kernel.checks;
5
6 import 'ast.dart';
7 import 'transformations/flags.dart';
8
9 void verifyProgram(Program program) {
10 VerifyingVisitor.check(program);
11 }
12
13 /// Checks that a kernel program is well-formed.
14 ///
15 /// This does not include any kind of type checking.
16 class VerifyingVisitor extends RecursiveVisitor {
17 final Set<Class> classes = new Set<Class>();
18 final Set<TypeParameter> typeParameters = new Set<TypeParameter>();
19 final List<VariableDeclaration> variableStack = <VariableDeclaration>[];
20 bool classTypeParametersAreInScope = false;
21
22 Member currentMember;
23 Class currentClass;
24 TreeNode currentParent;
25
26 TreeNode get context => currentMember ?? currentClass;
27
28 static void check(Program program) {
29 program.accept(new VerifyingVisitor());
30 }
31
32 defaultTreeNode(TreeNode node) {
33 visitChildren(node);
34 }
35
36 TreeNode enterParent(TreeNode node) {
37 if (!identical(node.parent, currentParent)) {
38 throw 'Incorrect parent pointer on ${node.runtimeType} in $context. '
39 'Parent pointer is ${node.parent.runtimeType}, '
40 'actual parent is ${currentParent.runtimeType}.';
41 }
42 var oldParent = currentParent;
43 currentParent = node;
44 return oldParent;
45 }
46
47 void exitParent(TreeNode oldParent) {
48 currentParent = oldParent;
49 }
50
51 int enterLocalScope() => variableStack.length;
52
53 void exitLocalScope(int stackHeight) {
54 for (int i = stackHeight; i < variableStack.length; ++i) {
55 undeclareVariable(variableStack[i]);
56 }
57 variableStack.length = stackHeight;
58 }
59
60 void visitChildren(TreeNode node) {
61 var oldParent = enterParent(node);
62 node.visitChildren(this);
63 exitParent(oldParent);
64 }
65
66 void visitWithLocalScope(TreeNode node) {
67 int stackHeight = enterLocalScope();
68 visitChildren(node);
69 exitLocalScope(stackHeight);
70 }
71
72 void declareMember(Member member) {
73 if (member.transformerFlags & TransformerFlag.seenByVerifier != 0) {
74 throw '$member has been declared more than once (${member.location})';
75 }
76 member.transformerFlags |= TransformerFlag.seenByVerifier;
77 }
78
79 void undeclareMember(Member member) {
80 member.transformerFlags &= ~TransformerFlag.seenByVerifier;
81 }
82
83 void declareVariable(VariableDeclaration variable) {
84 if (variable.flags & VariableDeclaration.FlagInScope != 0) {
85 throw '$variable declared more than once (${variable.location})';
86 }
87 variable.flags |= VariableDeclaration.FlagInScope;
88 variableStack.add(variable);
89 }
90
91 void undeclareVariable(VariableDeclaration variable) {
92 variable.flags &= ~VariableDeclaration.FlagInScope;
93 }
94
95 void checkVariableInScope(VariableDeclaration variable, TreeNode where) {
96 if (variable.flags & VariableDeclaration.FlagInScope == 0) {
97 throw 'Variable $variable used out of scope in $context '
98 '(${where.location})';
99 }
100 }
101
102 visitProgram(Program program) {
103 for (var library in program.libraries) {
104 classes.addAll(library.classes);
105 library.members.forEach(declareMember);
106 for (var class_ in library.classes) {
107 class_.members.forEach(declareMember);
108 }
109 }
110 visitChildren(program);
111 for (var library in program.libraries) {
112 library.members.forEach(undeclareMember);
113 for (var class_ in library.classes) {
114 class_.members.forEach(undeclareMember);
115 }
116 }
117 }
118
119 visitField(Field node) {
120 currentMember = node;
121 var oldParent = enterParent(node);
122 classTypeParametersAreInScope = !node.isStatic;
123 node.initializer?.accept(this);
124 classTypeParametersAreInScope = false;
125 visitList(node.annotations, this);
126 exitParent(oldParent);
127 currentMember = null;
128 }
129
130 visitProcedure(Procedure node) {
131 currentMember = node;
132 var oldParent = enterParent(node);
133 classTypeParametersAreInScope = !node.isStatic;
134 node.function.accept(this);
135 classTypeParametersAreInScope = false;
136 visitList(node.annotations, this);
137 exitParent(oldParent);
138 currentMember = null;
139 }
140
141 visitConstructor(Constructor node) {
142 currentMember = node;
143 classTypeParametersAreInScope = true;
144 // The constructor member needs special treatment due to parameters being
145 // in scope in the initializer list.
146 var oldParent = enterParent(node);
147 int stackHeight = enterLocalScope();
148 visitChildren(node.function);
149 visitList(node.initializers, this);
150 exitLocalScope(stackHeight);
151 classTypeParametersAreInScope = false;
152 visitList(node.annotations, this);
153 exitParent(oldParent);
154 classTypeParametersAreInScope = false;
155 currentMember = null;
156 }
157
158 visitClass(Class node) {
159 currentClass = node;
160 typeParameters.addAll(node.typeParameters);
161 var oldParent = enterParent(node);
162 classTypeParametersAreInScope = false;
163 visitList(node.annotations, this);
164 classTypeParametersAreInScope = true;
165 visitList(node.typeParameters, this);
166 visitList(node.fields, this);
167 visitList(node.constructors, this);
168 visitList(node.procedures, this);
169 exitParent(oldParent);
170 typeParameters.removeAll(node.typeParameters);
171 currentClass = null;
172 }
173
174 visitFunctionNode(FunctionNode node) {
175 typeParameters.addAll(node.typeParameters);
176 visitWithLocalScope(node);
177 typeParameters.removeAll(node.typeParameters);
178 }
179
180 visitFunctionType(FunctionType node) {
181 for (int i = 1; i < node.namedParameters.length; ++i) {
182 if (node.namedParameters[i - 1].compareTo(node.namedParameters[i]) >= 0) {
183 throw 'Named parameters are not sorted on function type found in '
184 '$context';
185 }
186 }
187 typeParameters.addAll(node.typeParameters);
188 for (var typeParameter in node.typeParameters) {
189 typeParameter.bound?.accept(this);
190 }
191 visitList(node.positionalParameters, this);
192 visitList(node.namedParameters, this);
193 node.returnType.accept(this);
194 typeParameters.removeAll(node.typeParameters);
195 }
196
197 visitBlock(Block node) {
198 visitWithLocalScope(node);
199 }
200
201 visitForStatement(ForStatement node) {
202 visitWithLocalScope(node);
203 }
204
205 visitForInStatement(ForInStatement node) {
206 visitWithLocalScope(node);
207 }
208
209 visitLet(Let node) {
210 visitWithLocalScope(node);
211 }
212
213 visitCatch(Catch node) {
214 visitWithLocalScope(node);
215 }
216
217 visitVariableDeclaration(VariableDeclaration node) {
218 visitChildren(node);
219 declareVariable(node);
220 }
221
222 visitVariableGet(VariableGet node) {
223 checkVariableInScope(node.variable, node);
224 }
225
226 visitVariableSet(VariableSet node) {
227 checkVariableInScope(node.variable, node);
228 visitChildren(node);
229 }
230
231 @override
232 defaultMemberReference(Member node) {
233 if (node.transformerFlags & TransformerFlag.seenByVerifier == 0) {
234 throw 'Dangling reference to $node found in $context.\n'
235 'Parent pointer is set to ${node.parent}';
236 }
237 }
238
239 @override
240 visitClassReference(Class node) {
241 if (!classes.contains(node)) {
242 throw 'Dangling reference to $node found in $context.\n'
243 'Parent pointer is set to ${node.parent}';
244 }
245 }
246
247 @override
248 visitTypeParameterType(TypeParameterType node) {
249 var parameter = node.parameter;
250 if (!typeParameters.contains(parameter)) {
251 throw 'Type parameter $parameter referenced out of scope in $context.\n'
252 'Parent pointer is set to ${parameter.parent}';
253 }
254 if (parameter.parent is Class && !classTypeParametersAreInScope) {
255 throw 'Type parameter $parameter referenced from static context '
256 'in $context.\n'
257 'Parent pointer is set to ${parameter.parent}';
258 }
259 }
260
261 @override
262 visitInterfaceType(InterfaceType node) {
263 node.visitChildren(this);
264 if (node.typeArguments.length != node.classNode.typeParameters.length) {
265 throw 'Type $node provides ${node.typeArguments.length} type arguments '
266 'but the class declares ${node.classNode.typeParameters.length} '
267 'parameters. Found in $context.';
268 }
269 }
270 }
271
272 class CheckParentPointers extends Visitor {
273 static void check(TreeNode node) {
274 node.accept(new CheckParentPointers(node.parent));
275 }
276
277 TreeNode parent;
278
279 CheckParentPointers([this.parent]);
280
281 defaultTreeNode(TreeNode node) {
282 if (node.parent != parent) {
283 throw 'Parent pointer on ${node.runtimeType} '
284 'is ${node.parent.runtimeType} '
285 'but should be ${parent.runtimeType}';
286 }
287 var oldParent = parent;
288 parent = node;
289 node.visitChildren(this);
290 parent = oldParent;
291 }
292 }
OLDNEW
« no previous file with comments | « pkg/kernel/lib/transformations/flags.dart ('k') | pkg/kernel/test/baseline_tester.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698