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

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: Address comments. 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') | no next file with comments »
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 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
50 case ElementKind.PARAMETER: 50 case ElementKind.PARAMETER:
51 return resolveVariableElement(element); 51 return resolveVariableElement(element);
52 52
53 default: 53 default:
54 compiler.unimplemented( 54 compiler.unimplemented(
55 "resolver", node: element.parseNode(compiler)); 55 "resolver", node: element.parseNode(compiler));
56 } 56 }
57 }); 57 });
58 } 58 }
59 59
60 SourceString getConstructorName(Send node) {
61 if (node.receiver !== null) {
62 return node.selector.asIdentifier().source;
63 } else {
64 return const SourceString('');
65 }
66 }
67
68 FunctionElement lookupConstructor(ClassElement classElement, Send send,
69 [noConstructor(Element)]) {
70 final SourceString constructorName = getConstructorName(send);
71 final SourceString className = classElement.name;
72 FunctionElement result = classElement.lookupConstructor(className,
73 constructorName,
74 noConstructor);
75 if (result === null && send.arguments.isEmpty()) {
76 result = classElement.getSynthesizedConstructor();
77 }
78 return result;
79 }
80
81 FunctionElement resolveConstructorRedirection(FunctionElement constructor) {
82 FunctionExpression node = constructor.parseNode(compiler);
83 // A synthetic constructor does not have a node.
84 if (node === null) return null;
85 if (node.initializers === null) return null;
86 Link<Node> initializers = node.initializers.nodes;
87 if (!initializers.isEmpty() &&
88 Initializers.isConstructorRedirect(initializers.head)) {
89 return lookupConstructor(constructor.enclosingElement, initializers.head);
90 }
91 return null;
92 }
93
94 void resolveRedirectingConstructor(InitializerResolver resolver,
95 Node node,
96 FunctionElement constructor,
97 FunctionElement redirection) {
98 Set<FunctionElement> seen = new Set<FunctionElement>();
99 seen.add(constructor);
100 while (redirection !== null) {
101 if (seen.contains(redirection)) {
102 resolver.visitor.error(node, MessageKind.REDIRECTING_CONSTRUCTOR_CYCLE);
103 return;
104 }
105 seen.add(redirection);
106 redirection = resolveConstructorRedirection(redirection);
107 }
108 }
109
60 TreeElements resolveMethodElement(FunctionElement element) { 110 TreeElements resolveMethodElement(FunctionElement element) {
61 if (element.kind === ElementKind.GENERATIVE_CONSTRUCTOR && 111 if (element.kind === ElementKind.GENERATIVE_CONSTRUCTOR &&
62 constructorElements[element] !== null) { 112 constructorElements[element] !== null) {
63 return constructorElements[element]; 113 return constructorElements[element];
64 } 114 }
65 FunctionExpression tree = element.parseNode(compiler); 115 FunctionExpression tree = element.parseNode(compiler);
66 ResolverVisitor visitor = new ResolverVisitor(compiler, element); 116 ResolverVisitor visitor = new ResolverVisitor(compiler, element);
67 visitor.useElement(tree, element); 117 visitor.useElement(tree, element);
68 visitor.setupFunction(tree, element); 118 visitor.setupFunction(tree, element);
69 119
70 if (tree.initializers != null) { 120 if (element.kind !== ElementKind.GENERATIVE_CONSTRUCTOR_BODY &&
71 new InitializerResolver(visitor, element).resolveInitializers(tree); 121 tree.initializers != null) {
122 if (element.kind !== ElementKind.GENERATIVE_CONSTRUCTOR) {
123 error(tree, MessageKind.FUNCTION_WITH_INITIALIZER);
124 }
125 InitializerResolver resolver = new InitializerResolver(visitor);
126 FunctionElement redirection = resolver.resolveInitializers(element, tree);
127 if (redirection !== null) {
128 resolveRedirectingConstructor(resolver, tree, element, redirection);
129 }
72 } 130 }
73 visitor.visit(tree.body); 131 visitor.visit(tree.body);
74 132
75 // Resolve the type annotations encountered in the method. 133 // Resolve the type annotations encountered in the method.
76 Link<ClassElement> newResolvedClasses = const EmptyLink<ClassElement>(); 134 Link<ClassElement> newResolvedClasses = const EmptyLink<ClassElement>();
77 while (!toResolve.isEmpty()) { 135 while (!toResolve.isEmpty()) {
78 ClassElement classElement = toResolve.removeFirst(); 136 ClassElement classElement = toResolve.removeFirst();
79 if (!classElement.isResolved) { 137 if (!classElement.isResolved) {
80 classElement.resolve(compiler); 138 classElement.resolve(compiler);
81 } 139 }
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
133 // TODO(karlklose): check if type arguments match, if a classelement occurs 191 // TODO(karlklose): check if type arguments match, if a classelement occurs
134 // more than once in the supertypes. 192 // more than once in the supertypes.
135 if (classElement.allSupertypes !== null) return; 193 if (classElement.allSupertypes !== null) return;
136 final Type supertype = classElement.supertype; 194 final Type supertype = classElement.supertype;
137 if (seen.contains(classElement)) { 195 if (seen.contains(classElement)) {
138 error(classElement.parseNode(compiler), 196 error(classElement.parseNode(compiler),
139 MessageKind.CYCLIC_CLASS_HIERARCHY, 197 MessageKind.CYCLIC_CLASS_HIERARCHY,
140 [classElement.name]); 198 [classElement.name]);
141 classElement.allSupertypes = const EmptyLink<Type>(); 199 classElement.allSupertypes = const EmptyLink<Type>();
142 } else if (supertype != null) { 200 } else if (supertype != null) {
143 Type supertype = classElement.supertype;
144 seen.add(classElement); 201 seen.add(classElement);
145 Link<Type> superSupertypes = 202 Link<Type> superSupertypes =
146 getOrCalculateAllSupertypes(supertype.element, seen); 203 getOrCalculateAllSupertypes(supertype.element, seen);
147 Link<Type> supertypes = new Link<Type>(supertype, superSupertypes); 204 Link<Type> supertypes = new Link<Type>(supertype, superSupertypes);
148 for (Link<Type> interfaces = classElement.interfaces; 205 for (Link<Type> interfaces = classElement.interfaces;
149 !interfaces.isEmpty(); 206 !interfaces.isEmpty();
150 interfaces = interfaces.tail) { 207 interfaces = interfaces.tail) {
151 Element element = interfaces.head.element; 208 Element element = interfaces.head.element;
152 Link<Type> interfaceSupertypes = 209 Link<Type> interfaceSupertypes =
153 getOrCalculateAllSupertypes(element, seen); 210 getOrCalculateAllSupertypes(element, seen);
154 supertypes = supertypes.reversePrependAll(interfaceSupertypes); 211 supertypes = supertypes.reversePrependAll(interfaceSupertypes);
155 } 212 }
156 seen.remove(classElement); 213 seen.remove(classElement);
157 classElement.allSupertypes = supertypes; 214 classElement.allSupertypes = supertypes;
158 } else { 215 } else {
159 classElement.allSupertypes = const EmptyLink<Type>(); 216 classElement.allSupertypes = const EmptyLink<Type>();
160 } 217 }
161 } 218 }
162 219
163 error(Node node, MessageKind kind, [arguments = const []]) { 220 error(Node node, MessageKind kind, [arguments = const []]) {
164 ResolutionError error = new ResolutionError(kind, arguments); 221 ResolutionError message = new ResolutionError(kind, arguments);
165 compiler.reportError(node, error); 222 compiler.reportError(node, message);
166 } 223 }
167 } 224 }
168 225
169 class InitializerResolver { 226 class InitializerResolver {
170 final ResolverVisitor visitor; 227 final ResolverVisitor visitor;
171 final FunctionElement constructor;
172 final Map<SourceString, Node> initialized; 228 final Map<SourceString, Node> initialized;
173 Link<Node> initializers; 229 Link<Node> initializers;
174 bool hasSuper; 230 bool hasSuper;
175 231
176 InitializerResolver(this.visitor, this.constructor) 232 InitializerResolver(this.visitor)
177 : initialized = new Map<SourceString, Node>(), hasSuper = false; 233 : initialized = new Map<SourceString, Node>(), hasSuper = false;
178 234
179 error(Node node, MessageKind kind, [arguments = const []]) { 235 error(Node node, MessageKind kind, [arguments = const []]) {
180 visitor.error(node, kind, arguments); 236 visitor.error(node, kind, arguments);
181 } 237 }
182 238
183 warning(Node node, MessageKind kind, [arguments = const []]) { 239 warning(Node node, MessageKind kind, [arguments = const []]) {
184 visitor.warning(node, kind, arguments); 240 visitor.warning(node, kind, arguments);
185 } 241 }
186 242
187 bool isFieldInitializer(SendSet node) { 243 bool isFieldInitializer(SendSet node) {
188 if (node.selector.asIdentifier() == null) return false; 244 if (node.selector.asIdentifier() == null) return false;
189 if (node.receiver == null) return true; 245 if (node.receiver == null) return true;
190 if (node.receiver.asIdentifier() == null) return false; 246 if (node.receiver.asIdentifier() == null) return false;
191 return node.receiver.asIdentifier().isThis(); 247 return node.receiver.asIdentifier().isThis();
192 } 248 }
193 249
194 void resolveFieldInitializer(SendSet init) { 250 void resolveFieldInitializer(FunctionElement constructor, SendSet init) {
195 // init is of the form [this.]field = value. 251 // init is of the form [this.]field = value.
196 final Node selector = init.selector; 252 final Node selector = init.selector;
197 final SourceString name = selector.asIdentifier().source; 253 final SourceString name = selector.asIdentifier().source;
198 // Lookup target field. 254 // Lookup target field.
199 Element target; 255 Element target;
200 if (isFieldInitializer(init)) { 256 if (isFieldInitializer(init)) {
201 final ClassElement classElement = constructor.enclosingElement; 257 final ClassElement classElement = constructor.enclosingElement;
202 target = classElement.lookupLocalMember(name); 258 target = classElement.lookupLocalMember(name);
203 if (target === null) { 259 if (target === null) {
204 error(selector, MessageKind.CANNOT_RESOLVE, [name]); 260 error(selector, MessageKind.CANNOT_RESOLVE, [name]);
205 } else if (target.kind != ElementKind.FIELD) { 261 } else if (target.kind != ElementKind.FIELD) {
206 error(selector, MessageKind.NOT_A_FIELD, [name]); 262 error(selector, MessageKind.NOT_A_FIELD, [name]);
207 } else if (!target.isInstanceMember()) { 263 } else if (!target.isInstanceMember()) {
208 error(selector, MessageKind.INIT_STATIC_FIELD, [name]); 264 error(selector, MessageKind.INIT_STATIC_FIELD, [name]);
209 } 265 }
210 } else { 266 } else {
211 error(init, MessageKind.INVALID_RECEIVER_IN_INITIALIZER); 267 error(init, MessageKind.INVALID_RECEIVER_IN_INITIALIZER);
212 } 268 }
213 visitor.useElement(init, target); 269 visitor.useElement(init, target);
214 // Check for duplicate initializers. 270 // Check for duplicate initializers.
215 if (initialized.containsKey(name)) { 271 if (initialized.containsKey(name)) {
216 error(init, MessageKind.DUPLICATE_INITIALIZER, [name]); 272 error(init, MessageKind.DUPLICATE_INITIALIZER, [name]);
217 warning(initialized[name], MessageKind.ALREADY_INITIALIZED, [name]); 273 warning(initialized[name], MessageKind.ALREADY_INITIALIZED, [name]);
218 } 274 }
219 initialized[name] = init; 275 initialized[name] = init;
220 // Resolve initializing value. 276 // Resolve initializing value.
221 visitor.visitInStaticContext(init.arguments.head); 277 visitor.visitInStaticContext(init.arguments.head);
222 } 278 }
223 279
224 SourceString getConstructorName(Send node) { 280 Element resolveSuperOrThis(FunctionElement constructor,
225 if (node.receiver !== null) { 281 FunctionExpression functionNode,
226 return node.selector.asIdentifier().source; 282 Send call) {
227 } else {
228 return const SourceString('');
229 }
230 }
231
232 void resolveSuperOrThis(Send call) {
233 noConstructor(e) { 283 noConstructor(e) {
234 if (e !== null) error(call, MessageKind.NO_CONSTRUCTOR, [e.name, e.kind]); 284 if (e !== null) error(call, MessageKind.NO_CONSTRUCTOR, [e.name, e.kind]);
235 } 285 }
236 286
237 ClassElement lookupTarget = constructor.enclosingElement; 287 ClassElement lookupTarget = constructor.enclosingElement;
238 bool validTarget = true; 288 bool validTarget = true;
289 FunctionElement result;
239 if (Initializers.isSuperConstructorCall(call)) { 290 if (Initializers.isSuperConstructorCall(call)) {
240 // Check for invalid initializers. 291 // Check for invalid initializers.
241 if (hasSuper) { 292 if (hasSuper) {
242 error(call, MessageKind.DUPLICATE_SUPER_INITIALIZER); 293 error(call, MessageKind.DUPLICATE_SUPER_INITIALIZER);
243 } 294 }
244 hasSuper = true; 295 hasSuper = true;
245 // Calculate correct lookup target and constructor name. 296 // Calculate correct lookup target and constructor name.
246 if (lookupTarget.name == Types.OBJECT) { 297 if (lookupTarget.name == Types.OBJECT) {
247 error(call, MessageKind.SUPER_INITIALIZER_IN_OBJECT); 298 error(call, MessageKind.SUPER_INITIALIZER_IN_OBJECT);
248 } else { 299 } else {
249 lookupTarget = lookupTarget.supertype.element; 300 lookupTarget = lookupTarget.supertype.element;
250 } 301 }
251 } else if (Initializers.isConstructorRedirect(call)) { 302 } else if (Initializers.isConstructorRedirect(call)) {
303 // Check that there is no body (Language specification 7.5.1).
304 if (functionNode.hasBody()) {
305 error(functionNode, MessageKind.REDIRECTING_CONSTRUCTOR_HAS_BODY);
306 }
252 // Check that there are no other initializers. 307 // Check that there are no other initializers.
253 if (!initializers.tail.isEmpty()) { 308 if (!initializers.tail.isEmpty()) {
254 error(call, MessageKind.REDIRECTING_CTOR_HAS_INITIALIZER); 309 error(call, MessageKind.REDIRECTING_CONSTRUCTOR_HAS_INITIALIZER);
255 } 310 }
256 } else { 311 } else {
257 visitor.error(call, MessageKind.CONSTRUCTOR_CALL_EXPECTED); 312 visitor.error(call, MessageKind.CONSTRUCTOR_CALL_EXPECTED);
258 validTarget = false; 313 validTarget = false;
259 } 314 }
260 315
261 if (validTarget) { 316 if (validTarget) {
262 final SourceString className = lookupTarget.name; 317 ResolverTask resolver = visitor.compiler.resolver;
263 final SourceString constructorName = getConstructorName(call); 318 result = resolver.lookupConstructor(lookupTarget, call);
264 FunctionElement target = 319 if (result === null) {
265 lookupTarget.lookupConstructor(className, constructorName, 320 SourceString constructorName = resolver.getConstructorName(call);
266 noConstructor); 321 SourceString className = lookupTarget.name;
267 if (target === null && call.arguments.isEmpty()) {
268 target = lookupTarget.getSynthesizedConstructor();
269 }
270 if (target === null) {
271 String name = (constructorName === const SourceString('')) 322 String name = (constructorName === const SourceString(''))
272 ? className.stringValue 323 ? className.stringValue
273 : "$className.$constructorName"; 324 : "$className.$constructorName";
274 error(call, MessageKind.CANNOT_RESOLVE_CONSTRUCTOR, [name]); 325 error(call, MessageKind.CANNOT_RESOLVE_CONSTRUCTOR, [name]);
275 } else { 326 } else {
276 final Compiler compiler = visitor.compiler; 327 final Compiler compiler = visitor.compiler;
277 // TODO(karlklose): support optional arguments. 328 // TODO(karlklose): support optional arguments.
278 if (target.parameterCount(compiler) != call.argumentCount()) { 329 if (result.parameterCount(compiler) != call.argumentCount()) {
279 error(call, MessageKind.NO_MATCHING_CONSTRUCTOR); 330 error(call, MessageKind.NO_MATCHING_CONSTRUCTOR);
280 } 331 }
281 } 332 }
282 visitor.useElement(call, target); 333 visitor.useElement(call, result);
283 } 334 }
284 // Resolve the arguments of the call. 335 // Resolve the arguments of the call.
285 for (Link<Node> arguments = call.arguments; 336 for (Link<Node> arguments = call.arguments;
286 !arguments.isEmpty(); 337 !arguments.isEmpty();
287 arguments = arguments.tail) { 338 arguments = arguments.tail) {
288 visitor.visitInStaticContext(arguments.head); 339 visitor.visitInStaticContext(arguments.head);
289 } 340 }
341 return result;
290 } 342 }
291 343
292 void resolveInitializers(FunctionExpression node) { 344 FunctionElement resolveRedirection(FunctionElement constructor,
293 if (node.initializers === null) return; 345 FunctionExpression functionNode) {
294 initializers = node.initializers.nodes; 346 if (functionNode.initializers === null) return null;
295 Compiler compiler = visitor.compiler; 347 Link<Node> link = functionNode.initializers.nodes;
348 if (!link.isEmpty() && Initializers.isConstructorRedirect(link.head)) {
349 return resolveSuperOrThis(constructor, functionNode, link.head);
350 }
351 return null;
352 }
353
354 /**
355 * Resolve all initializers of this constructor. In the case of a redirecting
356 * constructor, the resolved constructor's function element is returned.
357 */
358 FunctionElement resolveInitializers(FunctionElement constructor,
359 FunctionExpression functionNode) {
360 if (functionNode.initializers === null) return null;
361 initializers = functionNode.initializers.nodes;
362 FunctionElement result;
296 for (Link<Node> link = initializers; 363 for (Link<Node> link = initializers;
297 !link.isEmpty(); 364 !link.isEmpty();
298 link = link.tail) { 365 link = link.tail) {
299 if (link.head.asSendSet() != null) { 366 if (link.head.asSendSet() != null) {
300 final SendSet init = link.head.asSendSet(); 367 final SendSet init = link.head.asSendSet();
301 resolveFieldInitializer(init); 368 resolveFieldInitializer(constructor, init);
302 } else if (link.head.asSend() !== null) { 369 } else if (link.head.asSend() !== null) {
303 final Send call = link.head.asSend(); 370 final Send call = link.head.asSend();
304 resolveSuperOrThis(call); 371 result = resolveSuperOrThis(constructor, functionNode, call);
305 } else { 372 } else {
306 visitor.compiler.cancel('internal error: invalid initializer', 373 error(link.head, MessageKind.INVALID_INITIALIZER);
307 node: link.head);
308 } 374 }
309 } 375 }
376 return result;
310 } 377 }
311 } 378 }
312 379
313 class CommonResolverVisitor<R> extends AbstractVisitor<Element> { 380 class CommonResolverVisitor<R> extends AbstractVisitor<R> {
314 final Compiler compiler; 381 final Compiler compiler;
315 382
316 CommonResolverVisitor(Compiler this.compiler); 383 CommonResolverVisitor(Compiler this.compiler);
317 384
318 R visitNode(Node node) { 385 R visitNode(Node node) {
319 cancel(node, 'internal error'); 386 cancel(node, 'internal error');
320 } 387 }
321 388
322 /** Convenience method for visiting nodes that may be null. */ 389 /** Convenience method for visiting nodes that may be null. */
323 R visit(Node node) => (node == null) ? null : node.accept(this); 390 R visit(Node node) => (node == null) ? null : node.accept(this);
324 391
325 void error(Node node, MessageKind kind, [arguments = const []]) { 392 void error(Node node, MessageKind kind, [arguments = const []]) {
326 ResolutionError error = new ResolutionError(kind, arguments); 393 ResolutionError message = new ResolutionError(kind, arguments);
327 compiler.reportError(node, error); 394 compiler.reportError(node, message);
328 } 395 }
329 396
330 void warning(Node node, MessageKind kind, [arguments = const []]) { 397 void warning(Node node, MessageKind kind, [arguments = const []]) {
331 ResolutionWarning warning = new ResolutionWarning(kind, arguments); 398 ResolutionWarning message = new ResolutionWarning(kind, arguments);
332 compiler.reportWarning(node, warning); 399 compiler.reportWarning(node, message);
333 } 400 }
334 401
335 void cancel(Node node, String message) { 402 void cancel(Node node, String message) {
336 compiler.cancel(message, node: node); 403 compiler.cancel(message, node: node);
337 } 404 }
338 405
339 void internalError(Node node, String message) { 406 void internalError(Node node, String message) {
340 compiler.internalError(message, node: node); 407 compiler.internalError(message, node: node);
341 } 408 }
342 409
(...skipping 948 matching lines...) Expand 10 before | Expand all | Expand 10 after
1291 class TopScope extends Scope { 1358 class TopScope extends Scope {
1292 LibraryElement get library() => element; 1359 LibraryElement get library() => element;
1293 1360
1294 TopScope(LibraryElement library) : super(null, library); 1361 TopScope(LibraryElement library) : super(null, library);
1295 Element lookup(SourceString name) => library.find(name); 1362 Element lookup(SourceString name) => library.find(name);
1296 1363
1297 Element add(Element element) { 1364 Element add(Element element) {
1298 throw "Cannot add an element in the top scope"; 1365 throw "Cannot add an element in the top scope";
1299 } 1366 }
1300 } 1367 }
OLDNEW
« no previous file with comments | « no previous file | frog/leg/ssa/builder.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698