OLD | NEW |
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 part of resolution; | 5 part of resolution; |
6 | 6 |
7 abstract class TreeElements { | 7 abstract class TreeElements { |
8 Element get currentElement; | 8 Element get currentElement; |
9 Set<Node> get superUses; | 9 Set<Node> get superUses; |
10 | 10 |
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
295 return compiler.withCurrentElement(element, () { | 295 return compiler.withCurrentElement(element, () { |
296 FunctionExpression tree = element.parseNode(compiler); | 296 FunctionExpression tree = element.parseNode(compiler); |
297 if (tree.modifiers.isExternal()) { | 297 if (tree.modifiers.isExternal()) { |
298 error(tree, MessageKind.PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION); | 298 error(tree, MessageKind.PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION); |
299 return; | 299 return; |
300 } | 300 } |
301 if (isConstructor) { | 301 if (isConstructor) { |
302 if (tree.returnType != null) { | 302 if (tree.returnType != null) { |
303 error(tree, MessageKind.CONSTRUCTOR_WITH_RETURN_TYPE); | 303 error(tree, MessageKind.CONSTRUCTOR_WITH_RETURN_TYPE); |
304 } | 304 } |
305 resolveConstructorImplementation(element, tree); | |
306 } | 305 } |
307 ResolverVisitor visitor = visitorFor(element); | 306 ResolverVisitor visitor = visitorFor(element); |
308 visitor.useElement(tree, element); | 307 visitor.useElement(tree, element); |
309 visitor.setupFunction(tree, element); | 308 visitor.setupFunction(tree, element); |
310 | 309 |
311 if (isConstructor && !element.isForwardingConstructor) { | 310 if (isConstructor && !element.isForwardingConstructor) { |
312 // Even if there is no initializer list we still have to do the | 311 // Even if there is no initializer list we still have to do the |
313 // resolution in case there is an implicit super constructor call. | 312 // resolution in case there is an implicit super constructor call. |
314 InitializerResolver resolver = new InitializerResolver(visitor); | 313 InitializerResolver resolver = new InitializerResolver(visitor); |
315 FunctionElement redirection = | 314 FunctionElement redirection = |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
352 var mapping = new TreeElementMapping(element); | 351 var mapping = new TreeElementMapping(element); |
353 return new ResolverVisitor(compiler, element, mapping); | 352 return new ResolverVisitor(compiler, element, mapping); |
354 } | 353 } |
355 | 354 |
356 void visitBody(ResolverVisitor visitor, Statement body) { | 355 void visitBody(ResolverVisitor visitor, Statement body) { |
357 if (!compiler.analyzeSignaturesOnly) { | 356 if (!compiler.analyzeSignaturesOnly) { |
358 visitor.visit(body); | 357 visitor.visit(body); |
359 } | 358 } |
360 } | 359 } |
361 | 360 |
362 void resolveConstructorImplementation(FunctionElement constructor, | |
363 FunctionExpression node) { | |
364 if (!identical(constructor.defaultImplementation, constructor)) return; | |
365 ClassElement intrface = constructor.getEnclosingClass(); | |
366 if (!intrface.isInterface()) return; | |
367 DartType defaultType = intrface.defaultClass; | |
368 if (defaultType == null) { | |
369 error(node, MessageKind.NO_DEFAULT_CLASS, | |
370 {'interfaceName': intrface.name}); | |
371 } | |
372 ClassElement defaultClass = defaultType.element; | |
373 defaultClass.ensureResolved(compiler); | |
374 assert(defaultClass.resolutionState == STATE_DONE); | |
375 assert(defaultClass.supertypeLoadState == STATE_DONE); | |
376 if (defaultClass.isInterface()) { | |
377 error(node, MessageKind.CANNOT_INSTANTIATE_INTERFACE, | |
378 {'interfaceName': defaultClass.name}); | |
379 } | |
380 // We have now established the following: | |
381 // [intrface] is an interface, let's say "MyInterface". | |
382 // [defaultClass] is a class, let's say "MyClass". | |
383 | |
384 Selector selector; | |
385 // If the default class implements the interface then we must use the | |
386 // default class' name. Otherwise we look for a factory with the name | |
387 // of the interface. | |
388 if (defaultClass.implementsInterface(intrface)) { | |
389 var constructorNameString = constructor.name.slowToString(); | |
390 // Create selector based on constructor.name but where interface | |
391 // is replaced with default class name. | |
392 // TODO(ahe): Don't use string manipulations here. | |
393 int classNameSeparatorIndex = constructorNameString.indexOf('\$'); | |
394 if (classNameSeparatorIndex < 0) { | |
395 selector = new Selector.callDefaultConstructor( | |
396 defaultClass.getLibrary()); | |
397 } else { | |
398 selector = new Selector.callConstructor( | |
399 new SourceString( | |
400 constructorNameString.substring(classNameSeparatorIndex + 1)), | |
401 defaultClass.getLibrary()); | |
402 } | |
403 constructor.defaultImplementation = | |
404 defaultClass.lookupConstructor(selector); | |
405 } else { | |
406 selector = | |
407 new Selector.callConstructor(constructor.name, | |
408 defaultClass.getLibrary()); | |
409 constructor.defaultImplementation = | |
410 defaultClass.lookupFactoryConstructor(selector); | |
411 } | |
412 if (constructor.defaultImplementation == null) { | |
413 // We failed to find a constructor named either | |
414 // "MyInterface.name" or "MyClass.name". | |
415 // TODO(aprelev@gmail.com): Use constructorNameForDiagnostics in | |
416 // the error message below. | |
417 error(node, | |
418 MessageKind.CANNOT_FIND_CONSTRUCTOR2, | |
419 {'constructorName': selector.name, 'className': defaultClass.name}); | |
420 } | |
421 } | |
422 | |
423 TreeElements resolveField(VariableElement element) { | 361 TreeElements resolveField(VariableElement element) { |
424 Node tree = element.parseNode(compiler); | 362 Node tree = element.parseNode(compiler); |
425 if(element.modifiers.isStatic() && element.variables.isTopLevel()) { | 363 if(element.modifiers.isStatic() && element.variables.isTopLevel()) { |
426 error(element.modifiers.getStatic(), | 364 error(element.modifiers.getStatic(), |
427 MessageKind.TOP_LEVEL_VARIABLE_DECLARED_STATIC); | 365 MessageKind.TOP_LEVEL_VARIABLE_DECLARED_STATIC); |
428 } | 366 } |
429 ResolverVisitor visitor = visitorFor(element); | 367 ResolverVisitor visitor = visitorFor(element); |
430 // TODO(johnniwinther): Avoid analyzing initializers if | 368 // TODO(johnniwinther): Avoid analyzing initializers if |
431 // [Compiler.analyzeSignaturesOnly] is set. | 369 // [Compiler.analyzeSignaturesOnly] is set. |
432 initializerDo(tree, visitor.visit); | 370 initializerDo(tree, visitor.visit); |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
561 element.patch.ensureResolved(compiler); | 499 element.patch.ensureResolved(compiler); |
562 } | 500 } |
563 } else { // Handle patch classes: | 501 } else { // Handle patch classes: |
564 element.resolutionState = STATE_STARTED; | 502 element.resolutionState = STATE_STARTED; |
565 // Ensure handling origin before patch. | 503 // Ensure handling origin before patch. |
566 element.origin.ensureResolved(compiler); | 504 element.origin.ensureResolved(compiler); |
567 // Ensure that the type is computed. | 505 // Ensure that the type is computed. |
568 element.computeType(compiler); | 506 element.computeType(compiler); |
569 // Copy class hiearchy from origin. | 507 // Copy class hiearchy from origin. |
570 element.supertype = element.origin.supertype; | 508 element.supertype = element.origin.supertype; |
571 element.defaultClass = element.origin.defaultClass; | |
572 element.interfaces = element.origin.interfaces; | 509 element.interfaces = element.origin.interfaces; |
573 element.allSupertypes = element.origin.allSupertypes; | 510 element.allSupertypes = element.origin.allSupertypes; |
574 // Stepwise assignment to ensure invariant. | 511 // Stepwise assignment to ensure invariant. |
575 element.supertypeLoadState = STATE_STARTED; | 512 element.supertypeLoadState = STATE_STARTED; |
576 element.supertypeLoadState = STATE_DONE; | 513 element.supertypeLoadState = STATE_DONE; |
577 element.resolutionState = STATE_DONE; | 514 element.resolutionState = STATE_DONE; |
578 // TODO(johnniwinther): Check matching type variables and | 515 // TODO(johnniwinther): Check matching type variables and |
579 // empty extends/implements clauses. | 516 // empty extends/implements clauses. |
580 } | 517 } |
581 for (MetadataAnnotation metadata in element.metadata) { | 518 for (MetadataAnnotation metadata in element.metadata) { |
(...skipping 1987 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2569 } | 2506 } |
2570 resolveSelector(node.send, constructor); | 2507 resolveSelector(node.send, constructor); |
2571 resolveArguments(node.send.argumentsNode); | 2508 resolveArguments(node.send.argumentsNode); |
2572 useElement(node.send, constructor); | 2509 useElement(node.send, constructor); |
2573 if (Elements.isUnresolved(constructor)) return constructor; | 2510 if (Elements.isUnresolved(constructor)) return constructor; |
2574 Selector callSelector = mapping.getSelector(node.send); | 2511 Selector callSelector = mapping.getSelector(node.send); |
2575 if (!callSelector.applies(constructor, compiler)) { | 2512 if (!callSelector.applies(constructor, compiler)) { |
2576 warnArgumentMismatch(node.send, constructor); | 2513 warnArgumentMismatch(node.send, constructor); |
2577 compiler.backend.registerThrowNoSuchMethod(mapping); | 2514 compiler.backend.registerThrowNoSuchMethod(mapping); |
2578 } | 2515 } |
2579 compiler.withCurrentElement(constructor, () { | |
2580 FunctionElement target = constructor; | |
2581 if (constructor.isForwardingConstructor) { | |
2582 target = constructor.targetConstructor; | |
2583 } | |
2584 FunctionExpression tree = target.parseNode(compiler); | |
2585 compiler.resolver.resolveConstructorImplementation(constructor, tree); | |
2586 }); | |
2587 | 2516 |
2588 if (constructor.defaultImplementation != constructor) { | 2517 // [constructor] might be the implementation element |
2589 // Support for deprecated interface support. | |
2590 // TODO(ngeoffray): Remove once we remove such support. | |
2591 world.registerStaticUse(constructor.declaration); | |
2592 world.registerInstantiatedClass( | |
2593 constructor.getEnclosingClass().declaration, mapping); | |
2594 constructor = constructor.defaultImplementation; | |
2595 } | |
2596 // [constructor.defaultImplementation] might be the implementation element | |
2597 // and only declaration elements may be registered. | 2518 // and only declaration elements may be registered. |
2598 world.registerStaticUse(constructor.declaration); | 2519 world.registerStaticUse(constructor.declaration); |
2599 ClassElement cls = constructor.getEnclosingClass(); | 2520 ClassElement cls = constructor.getEnclosingClass(); |
2600 InterfaceType type = mapping.getType(node); | 2521 InterfaceType type = mapping.getType(node); |
2601 world.registerInstantiatedType(type, mapping); | 2522 world.registerInstantiatedType(type, mapping); |
2602 if (constructor.isFactoryConstructor() && !type.typeArguments.isEmpty) { | 2523 if (constructor.isFactoryConstructor() && !type.typeArguments.isEmpty) { |
2603 world.registerFactoryWithTypeArguments(mapping); | 2524 world.registerFactoryWithTypeArguments(mapping); |
2604 } | 2525 } |
2605 if (cls.isAbstract(compiler)) { | 2526 if (cls.isAbstract(compiler)) { |
2606 compiler.backend.registerAbstractClassInstantiation(mapping); | 2527 compiler.backend.registerAbstractClassInstantiation(mapping); |
(...skipping 629 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3236 superElement.ensureResolved(compiler); | 3157 superElement.ensureResolved(compiler); |
3237 } | 3158 } |
3238 element.supertype = superElement.computeType(compiler); | 3159 element.supertype = superElement.computeType(compiler); |
3239 } | 3160 } |
3240 } | 3161 } |
3241 | 3162 |
3242 assert(element.interfaces == null); | 3163 assert(element.interfaces == null); |
3243 element.interfaces = resolveInterfaces(node.interfaces, node.superclass); | 3164 element.interfaces = resolveInterfaces(node.interfaces, node.superclass); |
3244 calculateAllSupertypes(element); | 3165 calculateAllSupertypes(element); |
3245 | 3166 |
3246 if (node.defaultClause != null) { | |
3247 element.defaultClass = visit(node.defaultClause); | |
3248 } | |
3249 element.addDefaultConstructorIfNeeded(compiler); | 3167 element.addDefaultConstructorIfNeeded(compiler); |
3250 return element.computeType(compiler); | 3168 return element.computeType(compiler); |
3251 } | 3169 } |
3252 | 3170 |
3253 DartType visitNamedMixinApplication(NamedMixinApplication node) { | 3171 DartType visitNamedMixinApplication(NamedMixinApplication node) { |
3254 compiler.ensure(element != null); | 3172 compiler.ensure(element != null); |
3255 compiler.ensure(element.resolutionState == STATE_STARTED); | 3173 compiler.ensure(element.resolutionState == STATE_STARTED); |
3256 | 3174 |
3257 InterfaceType type = element.computeType(compiler); | 3175 InterfaceType type = element.computeType(compiler); |
3258 scope = new TypeDeclarationScope(scope, element); | 3176 scope = new TypeDeclarationScope(scope, element); |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3372 // infinite recursion when traversing members. | 3290 // infinite recursion when traversing members. |
3373 return null; | 3291 return null; |
3374 } | 3292 } |
3375 previous = current; | 3293 previous = current; |
3376 current = currentMixinApplication.mixin; | 3294 current = currentMixinApplication.mixin; |
3377 } | 3295 } |
3378 compiler.world.registerMixinUse(mixinApplication, mixin); | 3296 compiler.world.registerMixinUse(mixinApplication, mixin); |
3379 return mixin; | 3297 return mixin; |
3380 } | 3298 } |
3381 | 3299 |
3382 // TODO(johnniwinther): Remove when default class is no longer supported. | |
3383 DartType visitTypeAnnotation(TypeAnnotation node) { | |
3384 return visit(node.typeName); | |
3385 } | |
3386 | |
3387 DartType resolveType(TypeAnnotation node) { | 3300 DartType resolveType(TypeAnnotation node) { |
3388 // TODO(johnniwinther): Report errors/warnings on resolution failures. | 3301 // TODO(johnniwinther): Report errors/warnings on resolution failures. |
3389 return typeResolver.resolveTypeAnnotation(this, node); | 3302 return typeResolver.resolveTypeAnnotation(this, node); |
3390 } | 3303 } |
3391 | 3304 |
3392 // TODO(johnniwinther): Remove when default class is no longer supported. | |
3393 DartType visitIdentifier(Identifier node) { | |
3394 Element element = scope.lookup(node.source); | |
3395 if (element == null) { | |
3396 error(node, MessageKind.CANNOT_RESOLVE_TYPE, {'typeName': node}); | |
3397 return null; | |
3398 } else if (!element.impliesType() && !element.isTypeVariable()) { | |
3399 error(node, MessageKind.NOT_A_TYPE, {'node': node}); | |
3400 return null; | |
3401 } else { | |
3402 if (element.isTypeVariable()) { | |
3403 TypeVariableElement variableElement = element; | |
3404 return variableElement.type; | |
3405 } else if (element.isTypedef()) { | |
3406 compiler.unimplemented('visitIdentifier for typedefs', node: node); | |
3407 } else { | |
3408 // TODO(ngeoffray): Use type variables. | |
3409 return element.computeType(compiler); | |
3410 } | |
3411 } | |
3412 return null; | |
3413 } | |
3414 | |
3415 // TODO(johnniwinther): Remove when default class is no longer supported. | |
3416 DartType visitSend(Send node) { | |
3417 Identifier prefix = node.receiver.asIdentifier(); | |
3418 if (prefix == null) { | |
3419 error(node.receiver, MessageKind.NOT_A_PREFIX, {'node': node.receiver}); | |
3420 return null; | |
3421 } | |
3422 Element element = scope.lookup(prefix.source); | |
3423 if (element == null || !identical(element.kind, ElementKind.PREFIX)) { | |
3424 error(node.receiver, MessageKind.NOT_A_PREFIX, {'node': node.receiver}); | |
3425 return null; | |
3426 } | |
3427 PrefixElement prefixElement = element; | |
3428 Identifier selector = node.selector.asIdentifier(); | |
3429 var e = prefixElement.lookupLocalMember(selector.source); | |
3430 if (e == null || !e.impliesType()) { | |
3431 error(node.selector, MessageKind.CANNOT_RESOLVE_TYPE, | |
3432 {'typeName': node.selector}); | |
3433 return null; | |
3434 } | |
3435 return e.computeType(compiler); | |
3436 } | |
3437 | |
3438 DartType resolveSupertype(ClassElement cls, TypeAnnotation superclass) { | 3305 DartType resolveSupertype(ClassElement cls, TypeAnnotation superclass) { |
3439 DartType supertype = typeResolver.resolveTypeAnnotation( | 3306 DartType supertype = typeResolver.resolveTypeAnnotation( |
3440 this, superclass, onFailure: error); | 3307 this, superclass, onFailure: error); |
3441 if (supertype != null) { | 3308 if (supertype != null) { |
3442 if (identical(supertype.kind, TypeKind.MALFORMED_TYPE)) { | 3309 if (identical(supertype.kind, TypeKind.MALFORMED_TYPE)) { |
3443 // Error has already been reported. | 3310 // Error has already been reported. |
3444 return null; | 3311 return null; |
3445 } else if (!identical(supertype.kind, TypeKind.INTERFACE)) { | 3312 } else if (!identical(supertype.kind, TypeKind.INTERFACE)) { |
3446 // TODO(johnniwinther): Handle dynamic. | 3313 // TODO(johnniwinther): Handle dynamic. |
3447 error(superclass.typeName, MessageKind.CLASS_NAME_EXPECTED); | 3314 error(superclass.typeName, MessageKind.CLASS_NAME_EXPECTED); |
(...skipping 511 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3959 /// Finishes resolution of a constructor reference and records the | 3826 /// Finishes resolution of a constructor reference and records the |
3960 /// type of the constructed instance on [expression]. | 3827 /// type of the constructed instance on [expression]. |
3961 FunctionElement finishConstructorReference(Element e, | 3828 FunctionElement finishConstructorReference(Element e, |
3962 Node diagnosticNode, | 3829 Node diagnosticNode, |
3963 Node expression) { | 3830 Node expression) { |
3964 // Find the unnamed constructor if the reference resolved to a | 3831 // Find the unnamed constructor if the reference resolved to a |
3965 // class. | 3832 // class. |
3966 if (!Elements.isUnresolved(e) && e.isClass()) { | 3833 if (!Elements.isUnresolved(e) && e.isClass()) { |
3967 ClassElement cls = e; | 3834 ClassElement cls = e; |
3968 cls.ensureResolved(compiler); | 3835 cls.ensureResolved(compiler); |
3969 if (cls.isInterface() && (cls.defaultClass == null)) { | |
3970 // TODO(ahe): Remove this check and error message when we | |
3971 // don't have interfaces anymore. | |
3972 error(diagnosticNode, | |
3973 MessageKind.CANNOT_INSTANTIATE_INTERFACE, | |
3974 {'interfaceName': cls.name}); | |
3975 } | |
3976 // The unnamed constructor may not exist, so [e] may become unresolved. | 3836 // The unnamed constructor may not exist, so [e] may become unresolved. |
3977 e = lookupConstructor(cls, diagnosticNode, const SourceString('')); | 3837 e = lookupConstructor(cls, diagnosticNode, const SourceString('')); |
3978 } | 3838 } |
3979 if (type == null) { | 3839 if (type == null) { |
3980 if (Elements.isUnresolved(e)) { | 3840 if (Elements.isUnresolved(e)) { |
3981 type = compiler.dynamicClass.computeType(compiler); | 3841 type = compiler.dynamicClass.computeType(compiler); |
3982 } else { | 3842 } else { |
3983 type = e.getEnclosingClass().computeType(compiler).asRaw(); | 3843 type = e.getEnclosingClass().computeType(compiler).asRaw(); |
3984 } | 3844 } |
3985 } | 3845 } |
3986 resolver.mapping.setType(expression, type); | 3846 resolver.mapping.setType(expression, type); |
3987 return e; | 3847 return e; |
3988 } | 3848 } |
3989 | 3849 |
3990 visitTypeAnnotation(TypeAnnotation node) { | 3850 visitTypeAnnotation(TypeAnnotation node) { |
3991 assert(invariant(node, type == null)); | 3851 assert(invariant(node, type == null)); |
3992 type = resolver.resolveTypeRequired(node); | 3852 type = resolver.resolveTypeRequired(node); |
3993 return resolver.mapping[node]; | 3853 return resolver.mapping[node]; |
3994 } | 3854 } |
3995 | 3855 |
3996 visitSend(Send node) { | 3856 visitSend(Send node) { |
3997 Element e = visit(node.receiver); | 3857 Element e = visit(node.receiver); |
3998 if (Elements.isUnresolved(e)) return e; | 3858 if (Elements.isUnresolved(e)) return e; |
3999 Identifier name = node.selector.asIdentifier(); | 3859 Identifier name = node.selector.asIdentifier(); |
4000 if (name == null) internalError(node.selector, 'unexpected node'); | 3860 if (name == null) internalError(node.selector, 'unexpected node'); |
4001 | 3861 |
4002 if (identical(e.kind, ElementKind.CLASS)) { | 3862 if (identical(e.kind, ElementKind.CLASS)) { |
4003 ClassElement cls = e; | 3863 ClassElement cls = e; |
4004 cls.ensureResolved(compiler); | 3864 cls.ensureResolved(compiler); |
4005 if (cls.isInterface() && (cls.defaultClass == null)) { | |
4006 error(node.receiver, | |
4007 MessageKind.CANNOT_INSTANTIATE_INTERFACE, | |
4008 {'interfaceName': cls.name}); | |
4009 } | |
4010 return lookupConstructor(cls, name, name.source); | 3865 return lookupConstructor(cls, name, name.source); |
4011 } else if (identical(e.kind, ElementKind.PREFIX)) { | 3866 } else if (identical(e.kind, ElementKind.PREFIX)) { |
4012 PrefixElement prefix = e; | 3867 PrefixElement prefix = e; |
4013 e = prefix.lookupLocalMember(name.source); | 3868 e = prefix.lookupLocalMember(name.source); |
4014 if (e == null) { | 3869 if (e == null) { |
4015 return failOrReturnErroneousElement(resolver.enclosingElement, name, | 3870 return failOrReturnErroneousElement(resolver.enclosingElement, name, |
4016 name.source, | 3871 name.source, |
4017 MessageKind.CANNOT_RESOLVE, | 3872 MessageKind.CANNOT_RESOLVE, |
4018 {'name': name}); | 3873 {'name': name}); |
4019 } else if (!identical(e.kind, ElementKind.CLASS)) { | 3874 } else if (!identical(e.kind, ElementKind.CLASS)) { |
(...skipping 28 matching lines...) Expand all Loading... |
4048 return e; | 3903 return e; |
4049 } | 3904 } |
4050 | 3905 |
4051 /// Assumed to be called by [resolveRedirectingFactory]. | 3906 /// Assumed to be called by [resolveRedirectingFactory]. |
4052 Element visitReturn(Return node) { | 3907 Element visitReturn(Return node) { |
4053 Node expression = node.expression; | 3908 Node expression = node.expression; |
4054 return finishConstructorReference(visit(expression), | 3909 return finishConstructorReference(visit(expression), |
4055 expression, expression); | 3910 expression, expression); |
4056 } | 3911 } |
4057 } | 3912 } |
OLD | NEW |