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

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 and add a test. 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 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
60 TreeElements resolveMethodElement(FunctionElement element) { 60 TreeElements resolveMethodElement(FunctionElement element) {
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) {
floitsch 2012/02/14 16:38:02 maybe verify in here that we have a constructor.
karlklose 2012/02/15 13:10:35 Done.
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);
78 }
79 if (seen.contains(redirection)) {
80 visitor.error(tree, MessageKind.REDIRECTING_CONSTRUCTOR_CYCLE);
81 break;
82 }
83 seen.add(redirection);
84 FunctionExpression functionNode = redirection.parseNode(compiler);
85 if (functionNode !== null) {
86 redirection = resolver.resolveRedirection(redirection, functionNode);
87 } else {
88 // A synthetic constructor does not have a node.
89 redirection = null;
90 }
91 }
72 } 92 }
73 visitor.visit(tree.body); 93 visitor.visit(tree.body);
74 94
75 // Resolve the type annotations encountered in the method. 95 // Resolve the type annotations encountered in the method.
76 Link<ClassElement> newResolvedClasses = const EmptyLink<ClassElement>(); 96 Link<ClassElement> newResolvedClasses = const EmptyLink<ClassElement>();
77 while (!toResolve.isEmpty()) { 97 while (!toResolve.isEmpty()) {
78 ClassElement classElement = toResolve.removeFirst(); 98 ClassElement classElement = toResolve.removeFirst();
79 if (!classElement.isResolved) { 99 if (!classElement.isResolved) {
80 classElement.resolve(compiler); 100 classElement.resolve(compiler);
81 } 101 }
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
133 // TODO(karlklose): check if type arguments match, if a classelement occurs 153 // TODO(karlklose): check if type arguments match, if a classelement occurs
134 // more than once in the supertypes. 154 // more than once in the supertypes.
135 if (classElement.allSupertypes !== null) return; 155 if (classElement.allSupertypes !== null) return;
136 final Type supertype = classElement.supertype; 156 final Type supertype = classElement.supertype;
137 if (seen.contains(classElement)) { 157 if (seen.contains(classElement)) {
138 error(classElement.parseNode(compiler), 158 error(classElement.parseNode(compiler),
139 MessageKind.CYCLIC_CLASS_HIERARCHY, 159 MessageKind.CYCLIC_CLASS_HIERARCHY,
140 [classElement.name]); 160 [classElement.name]);
141 classElement.allSupertypes = const EmptyLink<Type>(); 161 classElement.allSupertypes = const EmptyLink<Type>();
142 } else if (supertype != null) { 162 } else if (supertype != null) {
143 Type supertype = classElement.supertype;
144 seen.add(classElement); 163 seen.add(classElement);
145 Link<Type> superSupertypes = 164 Link<Type> superSupertypes =
146 getOrCalculateAllSupertypes(supertype.element, seen); 165 getOrCalculateAllSupertypes(supertype.element, seen);
147 Link<Type> supertypes = new Link<Type>(supertype, superSupertypes); 166 Link<Type> supertypes = new Link<Type>(supertype, superSupertypes);
148 for (Link<Type> interfaces = classElement.interfaces; 167 for (Link<Type> interfaces = classElement.interfaces;
149 !interfaces.isEmpty(); 168 !interfaces.isEmpty();
150 interfaces = interfaces.tail) { 169 interfaces = interfaces.tail) {
151 Element element = interfaces.head.element; 170 Element element = interfaces.head.element;
152 Link<Type> interfaceSupertypes = 171 Link<Type> interfaceSupertypes =
153 getOrCalculateAllSupertypes(element, seen); 172 getOrCalculateAllSupertypes(element, seen);
154 supertypes = supertypes.reversePrependAll(interfaceSupertypes); 173 supertypes = supertypes.reversePrependAll(interfaceSupertypes);
155 } 174 }
156 seen.remove(classElement); 175 seen.remove(classElement);
157 classElement.allSupertypes = supertypes; 176 classElement.allSupertypes = supertypes;
158 } else { 177 } else {
159 classElement.allSupertypes = const EmptyLink<Type>(); 178 classElement.allSupertypes = const EmptyLink<Type>();
160 } 179 }
161 } 180 }
162 181
163 error(Node node, MessageKind kind, [arguments = const []]) { 182 error(Node node, MessageKind kind, [arguments = const []]) {
164 ResolutionError error = new ResolutionError(kind, arguments); 183 ResolutionError message = new ResolutionError(kind, arguments);
165 compiler.reportError(node, error); 184 compiler.reportError(node, error);
floitsch 2012/02/14 16:38:02 message?
karlklose 2012/02/15 13:10:35 Done.
166 } 185 }
167 } 186 }
168 187
169 class InitializerResolver { 188 class InitializerResolver {
170 final ResolverVisitor visitor; 189 final ResolverVisitor visitor;
171 final FunctionElement constructor;
172 final Map<SourceString, Node> initialized; 190 final Map<SourceString, Node> initialized;
173 Link<Node> initializers; 191 Link<Node> initializers;
174 bool hasSuper; 192 bool hasSuper;
175 193
176 InitializerResolver(this.visitor, this.constructor) 194 InitializerResolver(this.visitor)
177 : initialized = new Map<SourceString, Node>(), hasSuper = false; 195 : initialized = new Map<SourceString, Node>(), hasSuper = false;
178 196
179 error(Node node, MessageKind kind, [arguments = const []]) { 197 error(Node node, MessageKind kind, [arguments = const []]) {
180 visitor.error(node, kind, arguments); 198 visitor.error(node, kind, arguments);
181 } 199 }
182 200
183 warning(Node node, MessageKind kind, [arguments = const []]) { 201 warning(Node node, MessageKind kind, [arguments = const []]) {
184 visitor.warning(node, kind, arguments); 202 visitor.warning(node, kind, arguments);
185 } 203 }
186 204
187 bool isFieldInitializer(SendSet node) { 205 bool isFieldInitializer(SendSet node) {
188 if (node.selector.asIdentifier() == null) return false; 206 if (node.selector.asIdentifier() == null) return false;
189 if (node.receiver == null) return true; 207 if (node.receiver == null) return true;
190 if (node.receiver.asIdentifier() == null) return false; 208 if (node.receiver.asIdentifier() == null) return false;
191 return node.receiver.asIdentifier().isThis(); 209 return node.receiver.asIdentifier().isThis();
192 } 210 }
193 211
194 void resolveFieldInitializer(SendSet init) { 212 void resolveFieldInitializer(FunctionElement constructor, SendSet init) {
195 // init is of the form [this.]field = value. 213 // init is of the form [this.]field = value.
196 final Node selector = init.selector; 214 final Node selector = init.selector;
197 final SourceString name = selector.asIdentifier().source; 215 final SourceString name = selector.asIdentifier().source;
198 // Lookup target field. 216 // Lookup target field.
199 Element target; 217 Element target;
200 if (isFieldInitializer(init)) { 218 if (isFieldInitializer(init)) {
201 final ClassElement classElement = constructor.enclosingElement; 219 final ClassElement classElement = constructor.enclosingElement;
202 target = classElement.lookupLocalMember(name); 220 target = classElement.lookupLocalMember(name);
203 if (target === null) { 221 if (target === null) {
204 error(selector, MessageKind.CANNOT_RESOLVE, [name]); 222 error(selector, MessageKind.CANNOT_RESOLVE, [name]);
(...skipping 17 matching lines...) Expand all
222 } 240 }
223 241
224 SourceString getConstructorName(Send node) { 242 SourceString getConstructorName(Send node) {
225 if (node.receiver !== null) { 243 if (node.receiver !== null) {
226 return node.selector.asIdentifier().source; 244 return node.selector.asIdentifier().source;
227 } else { 245 } else {
228 return const SourceString(''); 246 return const SourceString('');
229 } 247 }
230 } 248 }
231 249
232 void resolveSuperOrThis(Send call) { 250 Element resolveSuperOrThis(FunctionElement constructor,
251 FunctionExpression functionNode,
252 Send call) {
233 noConstructor(e) { 253 noConstructor(e) {
234 if (e !== null) error(call, MessageKind.NO_CONSTRUCTOR, [e.name, e.kind]); 254 if (e !== null) error(call, MessageKind.NO_CONSTRUCTOR, [e.name, e.kind]);
235 } 255 }
236 256
237 ClassElement lookupTarget = constructor.enclosingElement; 257 ClassElement lookupTarget = constructor.enclosingElement;
238 bool validTarget = true; 258 bool validTarget = true;
259 FunctionElement result;
239 if (Initializers.isSuperConstructorCall(call)) { 260 if (Initializers.isSuperConstructorCall(call)) {
240 // Check for invalid initializers. 261 // Check for invalid initializers.
241 if (hasSuper) { 262 if (hasSuper) {
242 error(call, MessageKind.DUPLICATE_SUPER_INITIALIZER); 263 error(call, MessageKind.DUPLICATE_SUPER_INITIALIZER);
243 } 264 }
244 hasSuper = true; 265 hasSuper = true;
245 // Calculate correct lookup target and constructor name. 266 // Calculate correct lookup target and constructor name.
246 if (lookupTarget.name == Types.OBJECT) { 267 if (lookupTarget.name == Types.OBJECT) {
247 error(call, MessageKind.SUPER_INITIALIZER_IN_OBJECT); 268 error(call, MessageKind.SUPER_INITIALIZER_IN_OBJECT);
248 } else { 269 } else {
249 lookupTarget = lookupTarget.supertype.element; 270 lookupTarget = lookupTarget.supertype.element;
250 } 271 }
251 } else if (Initializers.isConstructorRedirect(call)) { 272 } else if (Initializers.isConstructorRedirect(call)) {
273 // Check that there is no body (Language specification 7.5.1).
274 if (functionNode.hasBody()) {
275 error(functionNode, MessageKind.REDIRECTING_CONSTRUCTOR_HAS_BODY);
276 }
252 // Check that there are no other initializers. 277 // Check that there are no other initializers.
253 if (!initializers.tail.isEmpty()) { 278 if (!initializers.tail.isEmpty()) {
254 error(call, MessageKind.REDIRECTING_CTOR_HAS_INITIALIZER); 279 error(call, MessageKind.REDIRECTING_CONSTRUCTOR_HAS_INITIALIZER);
255 } 280 }
256 } else { 281 } else {
257 visitor.error(call, MessageKind.CONSTRUCTOR_CALL_EXPECTED); 282 visitor.error(call, MessageKind.CONSTRUCTOR_CALL_EXPECTED);
258 validTarget = false; 283 validTarget = false;
259 } 284 }
260 285
261 if (validTarget) { 286 if (validTarget) {
262 final SourceString className = lookupTarget.name; 287 final SourceString className = lookupTarget.name;
263 final SourceString constructorName = getConstructorName(call); 288 final SourceString constructorName = getConstructorName(call);
264 FunctionElement target = 289 result = lookupTarget.lookupConstructor(className, constructorName,
265 lookupTarget.lookupConstructor(className, constructorName,
266 noConstructor); 290 noConstructor);
floitsch 2012/02/14 16:38:02 indendation
karlklose 2012/02/15 13:10:35 Done.
267 if (target === null && call.arguments.isEmpty()) { 291 if (result === null && call.arguments.isEmpty()) {
268 target = lookupTarget.getSynthesizedConstructor(); 292 result = lookupTarget.getSynthesizedConstructor();
269 } 293 }
270 if (target === null) { 294 if (result === null) {
271 String name = (constructorName === const SourceString('')) 295 String name = (constructorName === const SourceString(''))
272 ? className.stringValue 296 ? className.stringValue
273 : "$className.$constructorName"; 297 : "$className.$constructorName";
274 error(call, MessageKind.CANNOT_RESOLVE_CONSTRUCTOR, [name]); 298 error(call, MessageKind.CANNOT_RESOLVE_CONSTRUCTOR, [name]);
275 } else { 299 } else {
276 final Compiler compiler = visitor.compiler; 300 final Compiler compiler = visitor.compiler;
277 // TODO(karlklose): support optional arguments. 301 // TODO(karlklose): support optional arguments.
278 if (target.parameterCount(compiler) != call.argumentCount()) { 302 if (result.parameterCount(compiler) != call.argumentCount()) {
279 error(call, MessageKind.NO_MATCHING_CONSTRUCTOR); 303 error(call, MessageKind.NO_MATCHING_CONSTRUCTOR);
280 } 304 }
281 } 305 }
282 visitor.useElement(call, target); 306 visitor.useElement(call, result);
283 } 307 }
284 // Resolve the arguments of the call. 308 // Resolve the arguments of the call.
285 for (Link<Node> arguments = call.arguments; 309 for (Link<Node> arguments = call.arguments;
286 !arguments.isEmpty(); 310 !arguments.isEmpty();
287 arguments = arguments.tail) { 311 arguments = arguments.tail) {
288 visitor.visitInStaticContext(arguments.head); 312 visitor.visitInStaticContext(arguments.head);
289 } 313 }
314 return result;
290 } 315 }
291 316
292 void resolveInitializers(FunctionExpression node) { 317 FunctionElement resolveRedirection(FunctionElement constructor,
293 if (node.initializers === null) return; 318 FunctionExpression functionNode) {
294 initializers = node.initializers.nodes; 319 if (functionNode.initializers === null) return null;
295 Compiler compiler = visitor.compiler; 320 Link<Node> link = functionNode.initializers.nodes;
321 if (!link.isEmpty() && Initializers.isConstructorRedirect(link.head)) {
322 return resolveSuperOrThis(constructor, functionNode, link.head);
323 }
324 return null;
325 }
326
327 /**
328 * Resolve all initializers of this constructor. In the case of a redirecting
329 * constructor, the resolved constructor's function element is returned.
330 */
331 FunctionElement resolveInitializers(FunctionElement constructor,
332 FunctionExpression functionNode) {
333 if (functionNode.initializers === null) return null;
334 initializers = functionNode.initializers.nodes;
335 FunctionElement result;
296 for (Link<Node> link = initializers; 336 for (Link<Node> link = initializers;
297 !link.isEmpty(); 337 !link.isEmpty();
298 link = link.tail) { 338 link = link.tail) {
299 if (link.head.asSendSet() != null) { 339 if (link.head.asSendSet() != null) {
300 final SendSet init = link.head.asSendSet(); 340 final SendSet init = link.head.asSendSet();
301 resolveFieldInitializer(init); 341 resolveFieldInitializer(constructor, init);
302 } else if (link.head.asSend() !== null) { 342 } else if (link.head.asSend() !== null) {
303 final Send call = link.head.asSend(); 343 final Send call = link.head.asSend();
304 resolveSuperOrThis(call); 344 result = resolveSuperOrThis(constructor, functionNode, call);
305 } else { 345 } else {
306 visitor.compiler.cancel('internal error: invalid initializer', 346 visitor.compiler.cancel('internal error: invalid initializer',
floitsch 2012/02/14 16:38:02 This is not an internal error. The parser accepts
karlklose 2012/02/15 13:10:35 Done.
307 node: link.head); 347 node: link.head);
308 } 348 }
309 } 349 }
350 return result;
310 } 351 }
311 } 352 }
312 353
313 class CommonResolverVisitor<R> extends AbstractVisitor<Element> { 354 class CommonResolverVisitor<R> extends AbstractVisitor<R> {
314 final Compiler compiler; 355 final Compiler compiler;
315 356
316 CommonResolverVisitor(Compiler this.compiler); 357 CommonResolverVisitor(Compiler this.compiler);
317 358
318 R visitNode(Node node) { 359 R visitNode(Node node) {
319 cancel(node, 'internal error'); 360 cancel(node, 'internal error');
320 } 361 }
321 362
322 /** Convenience method for visiting nodes that may be null. */ 363 /** Convenience method for visiting nodes that may be null. */
323 R visit(Node node) => (node == null) ? null : node.accept(this); 364 R visit(Node node) => (node == null) ? null : node.accept(this);
324 365
325 void error(Node node, MessageKind kind, [arguments = const []]) { 366 void error(Node node, MessageKind kind, [arguments = const []]) {
326 ResolutionError error = new ResolutionError(kind, arguments); 367 ResolutionError message = new ResolutionError(kind, arguments);
327 compiler.reportError(node, error); 368 compiler.reportError(node, message);
328 } 369 }
329 370
330 void warning(Node node, MessageKind kind, [arguments = const []]) { 371 void warning(Node node, MessageKind kind, [arguments = const []]) {
331 ResolutionWarning warning = new ResolutionWarning(kind, arguments); 372 ResolutionWarning message = new ResolutionWarning(kind, arguments);
332 compiler.reportWarning(node, warning); 373 compiler.reportWarning(node, message);
333 } 374 }
334 375
335 void cancel(Node node, String message) { 376 void cancel(Node node, String message) {
336 compiler.cancel(message, node: node); 377 compiler.cancel(message, node: node);
337 } 378 }
338 379
339 void internalError(Node node, String message) { 380 void internalError(Node node, String message) {
340 compiler.internalError(message, node: node); 381 compiler.internalError(message, node: node);
341 } 382 }
342 383
(...skipping 807 matching lines...) Expand 10 before | Expand all | Expand 10 after
1150 class TopScope extends Scope { 1191 class TopScope extends Scope {
1151 LibraryElement get library() => element; 1192 LibraryElement get library() => element;
1152 1193
1153 TopScope(LibraryElement library) : super(null, library); 1194 TopScope(LibraryElement library) : super(null, library);
1154 Element lookup(SourceString name) => library.find(name); 1195 Element lookup(SourceString name) => library.find(name);
1155 1196
1156 Element add(Element element) { 1197 Element add(Element element) {
1157 throw "Cannot add an element in the top scope"; 1198 throw "Cannot add an element in the top scope";
1158 } 1199 }
1159 } 1200 }
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