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

Side by Side Diff: frog/leg/resolver.dart

Issue 9391004: Implement cycle-checking and code generation for redirecting constructors. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Refactor a function. Created 8 years, 10 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | frog/leg/ssa/builder.dart » ('j') | frog/leg/ssa/builder.dart » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 interface TreeElements { 5 interface TreeElements {
6 Element operator[](Node node); 6 Element operator[](Node node);
7 Selector getSelector(Send send); 7 Selector getSelector(Send send);
8 } 8 }
9 9
10 class TreeElementMapping implements TreeElements { 10 class TreeElementMapping implements TreeElements {
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
61 if (element.kind === ElementKind.GENERATIVE_CONSTRUCTOR && 61 if (element.kind === ElementKind.GENERATIVE_CONSTRUCTOR &&
62 constructorElements[element] !== null) { 62 constructorElements[element] !== null) {
63 return constructorElements[element]; 63 return constructorElements[element];
64 } 64 }
65 FunctionExpression tree = element.parseNode(compiler); 65 FunctionExpression tree = element.parseNode(compiler);
66 ResolverVisitor visitor = new ResolverVisitor(compiler, element); 66 ResolverVisitor visitor = new ResolverVisitor(compiler, element);
67 visitor.useElement(tree, element); 67 visitor.useElement(tree, element);
68 visitor.setupFunction(tree, element); 68 visitor.setupFunction(tree, element);
69 69
70 if (tree.initializers != null) { 70 if (tree.initializers != null) {
71 new InitializerResolver(visitor, element).resolveInitializers(tree); 71 InitializerResolver resolver = new InitializerResolver(visitor);
72 FunctionElement redirection = resolver.resolveInitializers(element, tree);
73 Set<FunctionElement> seen; // Initialized lazily.
74 while (redirection !== null) {
75 if (seen === null) {
76 seen = new Set<FunctionElement>();
77 seen.add(element);
kasperl 2012/02/14 14:24:47 Do you ever add more than one element to the |seen
karlklose 2012/02/14 15:44:42 Done, redirection should have been added after lin
78 }
79 if (seen.contains(redirection)) {
80 visitor.error(tree, MessageKind.REDIRECTING_CONSTRUCTOR_CYCLE);
81 break;
82 }
83 FunctionExpression functionNode = redirection.parseNode(compiler);
84 if (functionNode !== null) {
85 redirection = resolver.resolveRedirection(redirection, functionNode);
86 } else {
87 // A synthetic constructor does not have a node.
88 redirection = null;
89 }
90 }
72 } 91 }
73 visitor.visit(tree.body); 92 visitor.visit(tree.body);
74 93
75 // Resolve the type annotations encountered in the method. 94 // Resolve the type annotations encountered in the method.
76 Link<ClassElement> newResolvedClasses = const EmptyLink<ClassElement>(); 95 Link<ClassElement> newResolvedClasses = const EmptyLink<ClassElement>();
77 while (!toResolve.isEmpty()) { 96 while (!toResolve.isEmpty()) {
78 ClassElement classElement = toResolve.removeFirst(); 97 ClassElement classElement = toResolve.removeFirst();
79 if (!classElement.isResolved) { 98 if (!classElement.isResolved) {
80 classElement.resolve(compiler); 99 classElement.resolve(compiler);
81 } 100 }
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
133 // TODO(karlklose): check if type arguments match, if a classelement occurs 152 // TODO(karlklose): check if type arguments match, if a classelement occurs
134 // more than once in the supertypes. 153 // more than once in the supertypes.
135 if (classElement.allSupertypes !== null) return; 154 if (classElement.allSupertypes !== null) return;
136 final Type supertype = classElement.supertype; 155 final Type supertype = classElement.supertype;
137 if (seen.contains(classElement)) { 156 if (seen.contains(classElement)) {
138 error(classElement.parseNode(compiler), 157 error(classElement.parseNode(compiler),
139 MessageKind.CYCLIC_CLASS_HIERARCHY, 158 MessageKind.CYCLIC_CLASS_HIERARCHY,
140 [classElement.name]); 159 [classElement.name]);
141 classElement.allSupertypes = const EmptyLink<Type>(); 160 classElement.allSupertypes = const EmptyLink<Type>();
142 } else if (supertype != null) { 161 } else if (supertype != null) {
143 Type supertype = classElement.supertype;
144 seen.add(classElement); 162 seen.add(classElement);
145 Link<Type> superSupertypes = 163 Link<Type> superSupertypes =
146 getOrCalculateAllSupertypes(supertype.element, seen); 164 getOrCalculateAllSupertypes(supertype.element, seen);
147 Link<Type> supertypes = new Link<Type>(supertype, superSupertypes); 165 Link<Type> supertypes = new Link<Type>(supertype, superSupertypes);
148 for (Link<Type> interfaces = classElement.interfaces; 166 for (Link<Type> interfaces = classElement.interfaces;
149 !interfaces.isEmpty(); 167 !interfaces.isEmpty();
150 interfaces = interfaces.tail) { 168 interfaces = interfaces.tail) {
151 Element element = interfaces.head.element; 169 Element element = interfaces.head.element;
152 Link<Type> interfaceSupertypes = 170 Link<Type> interfaceSupertypes =
153 getOrCalculateAllSupertypes(element, seen); 171 getOrCalculateAllSupertypes(element, seen);
154 supertypes = supertypes.reversePrependAll(interfaceSupertypes); 172 supertypes = supertypes.reversePrependAll(interfaceSupertypes);
155 } 173 }
156 seen.remove(classElement); 174 seen.remove(classElement);
157 classElement.allSupertypes = supertypes; 175 classElement.allSupertypes = supertypes;
158 } else { 176 } else {
159 classElement.allSupertypes = const EmptyLink<Type>(); 177 classElement.allSupertypes = const EmptyLink<Type>();
160 } 178 }
161 } 179 }
162 180
163 error(Node node, MessageKind kind, [arguments = const []]) { 181 error(Node node, MessageKind kind, [arguments = const []]) {
164 ResolutionError error = new ResolutionError(kind, arguments); 182 ResolutionError message = new ResolutionError(kind, arguments);
165 compiler.reportError(node, error); 183 compiler.reportError(node, error);
166 } 184 }
167 } 185 }
168 186
169 class InitializerResolver { 187 class InitializerResolver {
170 final ResolverVisitor visitor; 188 final ResolverVisitor visitor;
171 final FunctionElement constructor;
172 final Map<SourceString, Node> initialized; 189 final Map<SourceString, Node> initialized;
173 Link<Node> initializers; 190 Link<Node> initializers;
174 bool hasSuper; 191 bool hasSuper;
175 192
176 InitializerResolver(this.visitor, this.constructor) 193 InitializerResolver(this.visitor)
177 : initialized = new Map<SourceString, Node>(), hasSuper = false; 194 : initialized = new Map<SourceString, Node>(), hasSuper = false;
178 195
179 error(Node node, MessageKind kind, [arguments = const []]) { 196 error(Node node, MessageKind kind, [arguments = const []]) {
180 visitor.error(node, kind, arguments); 197 visitor.error(node, kind, arguments);
181 } 198 }
182 199
183 warning(Node node, MessageKind kind, [arguments = const []]) { 200 warning(Node node, MessageKind kind, [arguments = const []]) {
184 visitor.warning(node, kind, arguments); 201 visitor.warning(node, kind, arguments);
185 } 202 }
186 203
187 bool isFieldInitializer(SendSet node) { 204 bool isFieldInitializer(SendSet node) {
188 if (node.selector.asIdentifier() == null) return false; 205 if (node.selector.asIdentifier() == null) return false;
189 if (node.receiver == null) return true; 206 if (node.receiver == null) return true;
190 if (node.receiver.asIdentifier() == null) return false; 207 if (node.receiver.asIdentifier() == null) return false;
191 return node.receiver.asIdentifier().isThis(); 208 return node.receiver.asIdentifier().isThis();
192 } 209 }
193 210
194 void resolveFieldInitializer(SendSet init) { 211 void resolveFieldInitializer(FunctionElement constructor, SendSet init) {
195 // init is of the form [this.]field = value. 212 // init is of the form [this.]field = value.
196 final Node selector = init.selector; 213 final Node selector = init.selector;
197 final SourceString name = selector.asIdentifier().source; 214 final SourceString name = selector.asIdentifier().source;
198 // Lookup target field. 215 // Lookup target field.
199 Element target; 216 Element target;
200 if (isFieldInitializer(init)) { 217 if (isFieldInitializer(init)) {
201 final ClassElement classElement = constructor.enclosingElement; 218 final ClassElement classElement = constructor.enclosingElement;
202 target = classElement.lookupLocalMember(name); 219 target = classElement.lookupLocalMember(name);
203 if (target === null) { 220 if (target === null) {
204 error(selector, MessageKind.CANNOT_RESOLVE, [name]); 221 error(selector, MessageKind.CANNOT_RESOLVE, [name]);
(...skipping 17 matching lines...) Expand all
222 } 239 }
223 240
224 SourceString getConstructorName(Send node) { 241 SourceString getConstructorName(Send node) {
225 if (node.receiver !== null) { 242 if (node.receiver !== null) {
226 return node.selector.asIdentifier().source; 243 return node.selector.asIdentifier().source;
227 } else { 244 } else {
228 return const SourceString(''); 245 return const SourceString('');
229 } 246 }
230 } 247 }
231 248
232 void resolveSuperOrThis(Send call) { 249 Element resolveSuperOrThis(FunctionElement constructor,
250 FunctionExpression functionNode,
251 Send call) {
233 noConstructor(e) { 252 noConstructor(e) {
234 if (e !== null) error(call, MessageKind.NO_CONSTRUCTOR, [e.name, e.kind]); 253 if (e !== null) error(call, MessageKind.NO_CONSTRUCTOR, [e.name, e.kind]);
235 } 254 }
236 255
237 ClassElement lookupTarget = constructor.enclosingElement; 256 ClassElement lookupTarget = constructor.enclosingElement;
238 bool validTarget = true; 257 bool validTarget = true;
258 FunctionElement result;
239 if (Initializers.isSuperConstructorCall(call)) { 259 if (Initializers.isSuperConstructorCall(call)) {
240 // Check for invalid initializers. 260 // Check for invalid initializers.
241 if (hasSuper) { 261 if (hasSuper) {
242 error(call, MessageKind.DUPLICATE_SUPER_INITIALIZER); 262 error(call, MessageKind.DUPLICATE_SUPER_INITIALIZER);
243 } 263 }
244 hasSuper = true; 264 hasSuper = true;
245 // Calculate correct lookup target and constructor name. 265 // Calculate correct lookup target and constructor name.
246 if (lookupTarget.name == Types.OBJECT) { 266 if (lookupTarget.name == Types.OBJECT) {
247 error(call, MessageKind.SUPER_INITIALIZER_IN_OBJECT); 267 error(call, MessageKind.SUPER_INITIALIZER_IN_OBJECT);
248 } else { 268 } else {
249 lookupTarget = lookupTarget.supertype.element; 269 lookupTarget = lookupTarget.supertype.element;
250 } 270 }
251 } else if (Initializers.isConstructorRedirect(call)) { 271 } else if (Initializers.isConstructorRedirect(call)) {
272 // Check that there is no body (Language specification 7.5.1).
273 if (functionNode.hasBody()) {
274 error(functionNode, MessageKind.REDIRECTING_CTOR_HAS_BODY);
275 }
252 // Check that there are no other initializers. 276 // Check that there are no other initializers.
253 if (!initializers.tail.isEmpty()) { 277 if (!initializers.tail.isEmpty()) {
254 error(call, MessageKind.REDIRECTING_CTOR_HAS_INITIALIZER); 278 error(call, MessageKind.REDIRECTING_CTOR_HAS_INITIALIZER);
255 } 279 }
256 } else { 280 } else {
257 visitor.error(call, MessageKind.CONSTRUCTOR_CALL_EXPECTED); 281 visitor.error(call, MessageKind.CONSTRUCTOR_CALL_EXPECTED);
258 validTarget = false; 282 validTarget = false;
259 } 283 }
260 284
261 if (validTarget) { 285 if (validTarget) {
262 final SourceString className = lookupTarget.name; 286 final SourceString className = lookupTarget.name;
263 final SourceString constructorName = getConstructorName(call); 287 final SourceString constructorName = getConstructorName(call);
264 FunctionElement target = 288 result = lookupTarget.lookupConstructor(className, constructorName,
265 lookupTarget.lookupConstructor(className, constructorName,
266 noConstructor); 289 noConstructor);
267 if (target === null && call.arguments.isEmpty()) { 290 if (result === null && call.arguments.isEmpty()) {
268 target = lookupTarget.getSynthesizedConstructor(); 291 result = lookupTarget.getSynthesizedConstructor();
269 } 292 }
270 if (target === null) { 293 if (result === null) {
271 String name = (constructorName === const SourceString('')) 294 String name = (constructorName === const SourceString(''))
272 ? className.stringValue 295 ? className.stringValue
273 : "$className.$constructorName"; 296 : "$className.$constructorName";
274 error(call, MessageKind.CANNOT_RESOLVE_CONSTRUCTOR, [name]); 297 error(call, MessageKind.CANNOT_RESOLVE_CONSTRUCTOR, [name]);
275 } else { 298 } else {
276 final Compiler compiler = visitor.compiler; 299 final Compiler compiler = visitor.compiler;
277 // TODO(karlklose): support optional arguments. 300 // TODO(karlklose): support optional arguments.
278 if (target.parameterCount(compiler) != call.argumentCount()) { 301 if (result.parameterCount(compiler) != call.argumentCount()) {
279 error(call, MessageKind.NO_MATCHING_CONSTRUCTOR); 302 error(call, MessageKind.NO_MATCHING_CONSTRUCTOR);
280 } 303 }
281 } 304 }
282 visitor.useElement(call, target); 305 visitor.useElement(call, result);
283 } 306 }
284 // Resolve the arguments of the call. 307 // Resolve the arguments of the call.
285 for (Link<Node> arguments = call.arguments; 308 for (Link<Node> arguments = call.arguments;
286 !arguments.isEmpty(); 309 !arguments.isEmpty();
287 arguments = arguments.tail) { 310 arguments = arguments.tail) {
288 visitor.visitInStaticContext(arguments.head); 311 visitor.visitInStaticContext(arguments.head);
289 } 312 }
313 return result;
290 } 314 }
291 315
292 void resolveInitializers(FunctionExpression node) { 316 FunctionElement resolveRedirection(FunctionElement constructor,
293 if (node.initializers === null) return; 317 FunctionExpression functionNode) {
294 initializers = node.initializers.nodes; 318 if (functionNode.initializers === null) return null;
295 Compiler compiler = visitor.compiler; 319 Link<Node> link = functionNode.initializers.nodes;
320 if (!link.isEmpty() && Initializers.isConstructorRedirect(link.head)) {
321 return resolveSuperOrThis(constructor, functionNode, link.head);
322 }
323 return null;
324 }
325
326 /**
327 * Resolve all initializers of this constructor. In the case of a redirecting
328 * constructor, the resolved constructor's function element is returned.
329 */
330 FunctionElement resolveInitializers(FunctionElement constructor,
331 FunctionExpression functionNode) {
332 if (functionNode.initializers === null) return null;
333 initializers = functionNode.initializers.nodes;
334 FunctionElement result;
296 for (Link<Node> link = initializers; 335 for (Link<Node> link = initializers;
297 !link.isEmpty(); 336 !link.isEmpty();
298 link = link.tail) { 337 link = link.tail) {
299 if (link.head.asSendSet() != null) { 338 if (link.head.asSendSet() != null) {
300 final SendSet init = link.head.asSendSet(); 339 final SendSet init = link.head.asSendSet();
301 resolveFieldInitializer(init); 340 resolveFieldInitializer(constructor, init);
302 } else if (link.head.asSend() !== null) { 341 } else if (link.head.asSend() !== null) {
303 final Send call = link.head.asSend(); 342 final Send call = link.head.asSend();
304 resolveSuperOrThis(call); 343 result = resolveSuperOrThis(constructor, functionNode, call);
305 } else { 344 } else {
306 visitor.compiler.cancel('internal error: invalid initializer', 345 visitor.compiler.cancel('internal error: invalid initializer',
307 node: link.head); 346 node: link.head);
308 } 347 }
309 } 348 }
349 return result;
310 } 350 }
311 } 351 }
312 352
313 class CommonResolverVisitor<R> extends AbstractVisitor<Element> { 353 class CommonResolverVisitor<R> extends AbstractVisitor<R> {
314 final Compiler compiler; 354 final Compiler compiler;
315 355
316 CommonResolverVisitor(Compiler this.compiler); 356 CommonResolverVisitor(Compiler this.compiler);
317 357
318 R visitNode(Node node) { 358 R visitNode(Node node) {
319 cancel(node, 'internal error'); 359 cancel(node, 'internal error');
320 } 360 }
321 361
322 /** Convenience method for visiting nodes that may be null. */ 362 /** Convenience method for visiting nodes that may be null. */
323 R visit(Node node) => (node == null) ? null : node.accept(this); 363 R visit(Node node) => (node == null) ? null : node.accept(this);
324 364
325 void error(Node node, MessageKind kind, [arguments = const []]) { 365 void error(Node node, MessageKind kind, [arguments = const []]) {
326 ResolutionError error = new ResolutionError(kind, arguments); 366 ResolutionError message = new ResolutionError(kind, arguments);
327 compiler.reportError(node, error); 367 compiler.reportError(node, message);
328 } 368 }
329 369
330 void warning(Node node, MessageKind kind, [arguments = const []]) { 370 void warning(Node node, MessageKind kind, [arguments = const []]) {
331 ResolutionWarning warning = new ResolutionWarning(kind, arguments); 371 ResolutionWarning message = new ResolutionWarning(kind, arguments);
332 compiler.reportWarning(node, warning); 372 compiler.reportWarning(node, message);
333 } 373 }
334 374
335 void cancel(Node node, String message) { 375 void cancel(Node node, String message) {
336 compiler.cancel(message, node: node); 376 compiler.cancel(message, node: node);
337 } 377 }
338 378
339 void internalError(Node node, String message) { 379 void internalError(Node node, String message) {
340 compiler.internalError(message, node: node); 380 compiler.internalError(message, node: node);
341 } 381 }
342 382
(...skipping 807 matching lines...) Expand 10 before | Expand all | Expand 10 after
1150 class TopScope extends Scope { 1190 class TopScope extends Scope {
1151 LibraryElement get library() => element; 1191 LibraryElement get library() => element;
1152 1192
1153 TopScope(LibraryElement library) : super(null, library); 1193 TopScope(LibraryElement library) : super(null, library);
1154 Element lookup(SourceString name) => library.find(name); 1194 Element lookup(SourceString name) => library.find(name);
1155 1195
1156 Element add(Element element) { 1196 Element add(Element element) {
1157 throw "Cannot add an element in the top scope"; 1197 throw "Cannot add an element in the top scope";
1158 } 1198 }
1159 } 1199 }
OLDNEW
« no previous file with comments | « no previous file | frog/leg/ssa/builder.dart » ('j') | frog/leg/ssa/builder.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698