| 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 AnalyzableElement get analyzedElement; | 8 AnalyzableElement get analyzedElement; |
| 9 Iterable<Node> get superUses; | 9 Iterable<Node> get superUses; |
| 10 | 10 |
| 11 /// Iterables of the dependencies that this [TreeElement] records of | 11 /// Iterables of the dependencies that this [TreeElement] records of |
| 12 /// [analyzedElement]. | 12 /// [analyzedElement]. |
| 13 Iterable<Element> get allElements; | 13 Iterable<Element> get allElements; |
| 14 void forEachConstantNode(f(Node n, Constant c)); | 14 void forEachConstantNode(f(Node n, ConstExp c)); |
| 15 | 15 |
| 16 /// A set of additional dependencies. See [registerDependency] below. | 16 /// A set of additional dependencies. See [registerDependency] below. |
| 17 Iterable<Element> get otherDependencies; | 17 Iterable<Element> get otherDependencies; |
| 18 | 18 |
| 19 Element operator[](Node node); | 19 Element operator[](Node node); |
| 20 | 20 |
| 21 // TODO(johnniwinther): Investigate whether [Node] could be a [Send]. | 21 // TODO(johnniwinther): Investigate whether [Node] could be a [Send]. |
| 22 Selector getSelector(Node node); | 22 Selector getSelector(Node node); |
| 23 Selector getGetterSelectorInComplexSendSet(SendSet node); | 23 Selector getGetterSelectorInComplexSendSet(SendSet node); |
| 24 Selector getOperatorSelectorInComplexSendSet(SendSet node); | 24 Selector getOperatorSelectorInComplexSendSet(SendSet node); |
| 25 DartType getType(Node node); | 25 DartType getType(Node node); |
| 26 void setSelector(Node node, Selector selector); | 26 void setSelector(Node node, Selector selector); |
| 27 void setGetterSelectorInComplexSendSet(SendSet node, Selector selector); | 27 void setGetterSelectorInComplexSendSet(SendSet node, Selector selector); |
| 28 void setOperatorSelectorInComplexSendSet(SendSet node, Selector selector); | 28 void setOperatorSelectorInComplexSendSet(SendSet node, Selector selector); |
| 29 | 29 |
| 30 /// Returns the for-in loop variable for [node]. | 30 /// Returns the for-in loop variable for [node]. |
| 31 Element getForInVariable(ForIn node); | 31 Element getForInVariable(ForIn node); |
| 32 Selector getIteratorSelector(ForIn node); | 32 Selector getIteratorSelector(ForIn node); |
| 33 Selector getMoveNextSelector(ForIn node); | 33 Selector getMoveNextSelector(ForIn node); |
| 34 Selector getCurrentSelector(ForIn node); | 34 Selector getCurrentSelector(ForIn node); |
| 35 void setIteratorSelector(ForIn node, Selector selector); | 35 void setIteratorSelector(ForIn node, Selector selector); |
| 36 void setMoveNextSelector(ForIn node, Selector selector); | 36 void setMoveNextSelector(ForIn node, Selector selector); |
| 37 void setCurrentSelector(ForIn node, Selector selector); | 37 void setCurrentSelector(ForIn node, Selector selector); |
| 38 void setConstant(Node node, Constant constant); | 38 void setConstant(Node node, ConstExp constant); |
| 39 Constant getConstant(Node node); | 39 ConstExp getConstant(Node node); |
| 40 bool isAssert(Send send); | 40 bool isAssert(Send send); |
| 41 | 41 |
| 42 /// Returns the [FunctionElement] defined by [node]. | 42 /// Returns the [FunctionElement] defined by [node]. |
| 43 FunctionElement getFunctionDefinition(FunctionExpression node); | 43 FunctionElement getFunctionDefinition(FunctionExpression node); |
| 44 | 44 |
| 45 /// Returns target constructor for the redirecting factory body [node]. | 45 /// Returns target constructor for the redirecting factory body [node]. |
| 46 ConstructorElement getRedirectingTargetConstructor( | 46 ConstructorElement getRedirectingTargetConstructor( |
| 47 RedirectingFactoryBody node); | 47 RedirectingFactoryBody node); |
| 48 | 48 |
| 49 /** | 49 /** |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 86 /// Returns the label that [node] targets. | 86 /// Returns the label that [node] targets. |
| 87 LabelDefinition getTargetLabel(GotoStatement node); | 87 LabelDefinition getTargetLabel(GotoStatement node); |
| 88 } | 88 } |
| 89 | 89 |
| 90 class TreeElementMapping implements TreeElements { | 90 class TreeElementMapping implements TreeElements { |
| 91 final AnalyzableElement analyzedElement; | 91 final AnalyzableElement analyzedElement; |
| 92 Map<Spannable, Selector> _selectors; | 92 Map<Spannable, Selector> _selectors; |
| 93 Map<Node, DartType> _types; | 93 Map<Node, DartType> _types; |
| 94 Setlet<Node> _superUses; | 94 Setlet<Node> _superUses; |
| 95 Setlet<Element> _otherDependencies; | 95 Setlet<Element> _otherDependencies; |
| 96 Map<Node, Constant> _constants; | 96 Map<Node, ConstExp> _constants; |
| 97 Map<VariableElement, List<Node>> _potentiallyMutated; | 97 Map<VariableElement, List<Node>> _potentiallyMutated; |
| 98 Map<Node, Map<VariableElement, List<Node>>> _potentiallyMutatedIn; | 98 Map<Node, Map<VariableElement, List<Node>>> _potentiallyMutatedIn; |
| 99 Map<VariableElement, List<Node>> _potentiallyMutatedInClosure; | 99 Map<VariableElement, List<Node>> _potentiallyMutatedInClosure; |
| 100 Map<Node, Map<VariableElement, List<Node>>> _accessedByClosureIn; | 100 Map<Node, Map<VariableElement, List<Node>>> _accessedByClosureIn; |
| 101 Setlet<Element> _elements; | 101 Setlet<Element> _elements; |
| 102 Setlet<Send> _asserts; | 102 Setlet<Send> _asserts; |
| 103 | 103 |
| 104 /// Map from nodes to the targets they define. | 104 /// Map from nodes to the targets they define. |
| 105 Map<Node, JumpTarget> _definedTargets; | 105 Map<Node, JumpTarget> _definedTargets; |
| 106 | 106 |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 229 } | 229 } |
| 230 | 230 |
| 231 Selector getCurrentSelector(ForIn node) { | 231 Selector getCurrentSelector(ForIn node) { |
| 232 return _getSelector(node.inToken); | 232 return _getSelector(node.inToken); |
| 233 } | 233 } |
| 234 | 234 |
| 235 Element getForInVariable(ForIn node) { | 235 Element getForInVariable(ForIn node) { |
| 236 return this[node]; | 236 return this[node]; |
| 237 } | 237 } |
| 238 | 238 |
| 239 void setConstant(Node node, Constant constant) { | 239 void setConstant(Node node, ConstExp constant) { |
| 240 if (_constants == null) { | 240 if (_constants == null) { |
| 241 _constants = new Maplet<Node, Constant>(); | 241 _constants = new Maplet<Node, ConstExp>(); |
| 242 } | 242 } |
| 243 _constants[node] = constant; | 243 _constants[node] = constant; |
| 244 } | 244 } |
| 245 | 245 |
| 246 Constant getConstant(Node node) { | 246 ConstExp getConstant(Node node) { |
| 247 return _constants != null ? _constants[node] : null; | 247 return _constants != null ? _constants[node] : null; |
| 248 } | 248 } |
| 249 | 249 |
| 250 bool isTypeLiteral(Send node) { | 250 bool isTypeLiteral(Send node) { |
| 251 return getType(node) != null; | 251 return getType(node) != null; |
| 252 } | 252 } |
| 253 | 253 |
| 254 DartType getTypeLiteralType(Send node) { | 254 DartType getTypeLiteralType(Send node) { |
| 255 return getType(node); | 255 return getType(node); |
| 256 } | 256 } |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 337 () => new Maplet<VariableElement, List<Node>>()); | 337 () => new Maplet<VariableElement, List<Node>>()); |
| 338 accessMap.putIfAbsent(element, () => <Node>[]).add(accessNode); | 338 accessMap.putIfAbsent(element, () => <Node>[]).add(accessNode); |
| 339 } | 339 } |
| 340 | 340 |
| 341 String toString() => 'TreeElementMapping($analyzedElement)'; | 341 String toString() => 'TreeElementMapping($analyzedElement)'; |
| 342 | 342 |
| 343 Iterable<Element> get allElements { | 343 Iterable<Element> get allElements { |
| 344 return _elements != null ? _elements : const <Element>[]; | 344 return _elements != null ? _elements : const <Element>[]; |
| 345 } | 345 } |
| 346 | 346 |
| 347 void forEachConstantNode(f(Node n, Constant c)) { | 347 void forEachConstantNode(f(Node n, ConstExp c)) { |
| 348 if (_constants != null) { | 348 if (_constants != null) { |
| 349 _constants.forEach(f); | 349 _constants.forEach(f); |
| 350 } | 350 } |
| 351 } | 351 } |
| 352 | 352 |
| 353 void setAssert(Send node) { | 353 void setAssert(Send node) { |
| 354 if (_asserts == null) { | 354 if (_asserts == null) { |
| 355 _asserts = new Setlet<Send>(); | 355 _asserts = new Setlet<Send>(); |
| 356 } | 356 } |
| 357 _asserts.add(node); | 357 _asserts.add(node); |
| (...skipping 647 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1005 element.supertypeLoadState = STATE_DONE; | 1005 element.supertypeLoadState = STATE_DONE; |
| 1006 element.resolutionState = STATE_DONE; | 1006 element.resolutionState = STATE_DONE; |
| 1007 // TODO(johnniwinther): Check matching type variables and | 1007 // TODO(johnniwinther): Check matching type variables and |
| 1008 // empty extends/implements clauses. | 1008 // empty extends/implements clauses. |
| 1009 } | 1009 } |
| 1010 } | 1010 } |
| 1011 | 1011 |
| 1012 void _postProcessClassElement(BaseClassElementX element) { | 1012 void _postProcessClassElement(BaseClassElementX element) { |
| 1013 for (MetadataAnnotation metadata in element.metadata) { | 1013 for (MetadataAnnotation metadata in element.metadata) { |
| 1014 metadata.ensureResolved(compiler); | 1014 metadata.ensureResolved(compiler); |
| 1015 if (!element.isProxy && metadata.value == compiler.proxyConstant) { | 1015 if (!element.isProxy && |
| 1016 metadata.constant.value == compiler.proxyConstant) { |
| 1016 element.isProxy = true; | 1017 element.isProxy = true; |
| 1017 } | 1018 } |
| 1018 } | 1019 } |
| 1019 | 1020 |
| 1020 // Force resolution of metadata on non-instance members since they may be | 1021 // Force resolution of metadata on non-instance members since they may be |
| 1021 // inspected by the backend while emitting. Metadata on instance members is | 1022 // inspected by the backend while emitting. Metadata on instance members is |
| 1022 // handled as a result of processing instantiated class members in the | 1023 // handled as a result of processing instantiated class members in the |
| 1023 // enqueuer. | 1024 // enqueuer. |
| 1024 // TODO(ahe): Avoid this eager resolution. | 1025 // TODO(ahe): Avoid this eager resolution. |
| 1025 element.forEachMember((_, Element member) { | 1026 element.forEachMember((_, Element member) { |
| (...skipping 368 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1394 classElement.ensureResolved(compiler); | 1395 classElement.ensureResolved(compiler); |
| 1395 } | 1396 } |
| 1396 assert(invariant(node, context != null, | 1397 assert(invariant(node, context != null, |
| 1397 message: "No context found for metadata annotation " | 1398 message: "No context found for metadata annotation " |
| 1398 "on $annotatedElement.")); | 1399 "on $annotatedElement.")); |
| 1399 ResolverVisitor visitor = visitorFor(context, useEnclosingScope: true); | 1400 ResolverVisitor visitor = visitorFor(context, useEnclosingScope: true); |
| 1400 ResolutionRegistry registry = visitor.registry; | 1401 ResolutionRegistry registry = visitor.registry; |
| 1401 node.accept(visitor); | 1402 node.accept(visitor); |
| 1402 // TODO(johnniwinther): Avoid passing the [TreeElements] to | 1403 // TODO(johnniwinther): Avoid passing the [TreeElements] to |
| 1403 // [compileMetadata]. | 1404 // [compileMetadata]. |
| 1404 annotation.value = | 1405 annotation.constant = |
| 1405 constantCompiler.compileMetadata(annotation, node, registry.mapping); | 1406 constantCompiler.compileMetadata(annotation, node, registry.mapping); |
| 1406 // TODO(johnniwinther): Register the relation between the annotation | 1407 // TODO(johnniwinther): Register the relation between the annotation |
| 1407 // and the annotated element instead. This will allow the backend to | 1408 // and the annotated element instead. This will allow the backend to |
| 1408 // retrieve the backend constant and only register metadata on the | 1409 // retrieve the backend constant and only register metadata on the |
| 1409 // elements for which it is needed. (Issue 17732). | 1410 // elements for which it is needed. (Issue 17732). |
| 1410 registry.registerMetadataConstant(annotation, annotatedElement); | 1411 registry.registerMetadataConstant(annotation, annotatedElement); |
| 1411 annotation.resolutionState = STATE_DONE; | 1412 annotation.resolutionState = STATE_DONE; |
| 1412 })); | 1413 })); |
| 1413 } | 1414 } |
| 1414 | 1415 |
| (...skipping 1886 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3301 registry.registerFactoryWithTypeArguments(); | 3302 registry.registerFactoryWithTypeArguments(); |
| 3302 } | 3303 } |
| 3303 if (constructor.isGenerativeConstructor && cls.isAbstract) { | 3304 if (constructor.isGenerativeConstructor && cls.isAbstract) { |
| 3304 warning(node, MessageKind.ABSTRACT_CLASS_INSTANTIATION); | 3305 warning(node, MessageKind.ABSTRACT_CLASS_INSTANTIATION); |
| 3305 registry.registerAbstractClassInstantiation(); | 3306 registry.registerAbstractClassInstantiation(); |
| 3306 } | 3307 } |
| 3307 | 3308 |
| 3308 if (isSymbolConstructor) { | 3309 if (isSymbolConstructor) { |
| 3309 if (node.isConst) { | 3310 if (node.isConst) { |
| 3310 Node argumentNode = node.send.arguments.head; | 3311 Node argumentNode = node.send.arguments.head; |
| 3311 Constant name = compiler.resolver.constantCompiler.compileNode( | 3312 ConstExp constant = compiler.resolver.constantCompiler.compileNode( |
| 3312 argumentNode, registry.mapping); | 3313 argumentNode, registry.mapping); |
| 3314 Constant name = constant.value; |
| 3313 if (!name.isString) { | 3315 if (!name.isString) { |
| 3314 DartType type = name.computeType(compiler); | 3316 DartType type = name.computeType(compiler); |
| 3315 compiler.reportError(argumentNode, MessageKind.STRING_EXPECTED, | 3317 compiler.reportError(argumentNode, MessageKind.STRING_EXPECTED, |
| 3316 {'type': type}); | 3318 {'type': type}); |
| 3317 } else { | 3319 } else { |
| 3318 StringConstant stringConstant = name; | 3320 StringConstant stringConstant = name; |
| 3319 String nameString = stringConstant.toDartString().slowToString(); | 3321 String nameString = stringConstant.toDartString().slowToString(); |
| 3320 if (validateSymbol(argumentNode, nameString)) { | 3322 if (validateSymbol(argumentNode, nameString)) { |
| 3321 registry.registerConstSymbol(nameString); | 3323 registry.registerConstSymbol(nameString); |
| 3322 } | 3324 } |
| (...skipping 29 matching lines...) Expand all Loading... |
| 3352 if (equals.enclosingClass != compiler.objectClass) { | 3354 if (equals.enclosingClass != compiler.objectClass) { |
| 3353 compiler.reportError(spannable, | 3355 compiler.reportError(spannable, |
| 3354 MessageKind.CONST_MAP_KEY_OVERRIDES_EQUALS, | 3356 MessageKind.CONST_MAP_KEY_OVERRIDES_EQUALS, |
| 3355 {'type': keyType}); | 3357 {'type': keyType}); |
| 3356 } | 3358 } |
| 3357 } | 3359 } |
| 3358 } | 3360 } |
| 3359 | 3361 |
| 3360 void analyzeConstant(Node node) { | 3362 void analyzeConstant(Node node) { |
| 3361 addDeferredAction(enclosingElement, () { | 3363 addDeferredAction(enclosingElement, () { |
| 3362 Constant constant = compiler.resolver.constantCompiler.compileNode( | 3364 ConstExp constant = compiler.resolver.constantCompiler.compileNode( |
| 3363 node, registry.mapping); | 3365 node, registry.mapping); |
| 3364 | 3366 |
| 3365 if (constant.isMap) { | 3367 Constant value = constant.value; |
| 3366 checkConstMapKeysDontOverrideEquals(node, constant); | 3368 if (value.isMap) { |
| 3369 checkConstMapKeysDontOverrideEquals(node, value); |
| 3367 } | 3370 } |
| 3368 | 3371 |
| 3369 // The type constant that is an argument to JS_INTERCEPTOR_CONSTANT names | 3372 // The type constant that is an argument to JS_INTERCEPTOR_CONSTANT names |
| 3370 // a class that will be instantiated outside the program by attaching a | 3373 // a class that will be instantiated outside the program by attaching a |
| 3371 // native class dispatch record referencing the interceptor. | 3374 // native class dispatch record referencing the interceptor. |
| 3372 if (argumentsToJsInterceptorConstant != null && | 3375 if (argumentsToJsInterceptorConstant != null && |
| 3373 argumentsToJsInterceptorConstant.contains(node)) { | 3376 argumentsToJsInterceptorConstant.contains(node)) { |
| 3374 if (constant.isType) { | 3377 if (value.isType) { |
| 3375 TypeConstant typeConstant = constant; | 3378 TypeConstant typeConstant = value; |
| 3376 if (typeConstant.representedType is InterfaceType) { | 3379 if (typeConstant.representedType is InterfaceType) { |
| 3377 registry.registerInstantiatedType(typeConstant.representedType); | 3380 registry.registerInstantiatedType(typeConstant.representedType); |
| 3378 } else { | 3381 } else { |
| 3379 compiler.reportError(node, | 3382 compiler.reportError(node, |
| 3380 MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT); | 3383 MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT); |
| 3381 } | 3384 } |
| 3382 } else { | 3385 } else { |
| 3383 compiler.reportError(node, | 3386 compiler.reportError(node, |
| 3384 MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT); | 3387 MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT); |
| 3385 } | 3388 } |
| (...skipping 352 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3738 for (Link<Node> cases = node.cases.nodes; | 3741 for (Link<Node> cases = node.cases.nodes; |
| 3739 !cases.isEmpty; | 3742 !cases.isEmpty; |
| 3740 cases = cases.tail) { | 3743 cases = cases.tail) { |
| 3741 SwitchCase switchCase = cases.head; | 3744 SwitchCase switchCase = cases.head; |
| 3742 | 3745 |
| 3743 for (Node labelOrCase in switchCase.labelsAndCases) { | 3746 for (Node labelOrCase in switchCase.labelsAndCases) { |
| 3744 CaseMatch caseMatch = labelOrCase.asCaseMatch(); | 3747 CaseMatch caseMatch = labelOrCase.asCaseMatch(); |
| 3745 if (caseMatch == null) continue; | 3748 if (caseMatch == null) continue; |
| 3746 | 3749 |
| 3747 // Analyze the constant. | 3750 // Analyze the constant. |
| 3748 Constant constant = registry.getConstant(caseMatch.expression); | 3751 ConstExp constant = registry.getConstant(caseMatch.expression); |
| 3749 assert(invariant(node, constant != null, | 3752 assert(invariant(node, constant != null, |
| 3750 message: 'No constant computed for $node')); | 3753 message: 'No constant computed for $node')); |
| 3751 | 3754 |
| 3752 DartType caseType = typeOfConstant(constant); | 3755 DartType caseType = typeOfConstant(constant.value); |
| 3753 | 3756 |
| 3754 if (firstCaseType == null) { | 3757 if (firstCaseType == null) { |
| 3755 firstCase = caseMatch; | 3758 firstCase = caseMatch; |
| 3756 firstCaseType = caseType; | 3759 firstCaseType = caseType; |
| 3757 | 3760 |
| 3758 // We only report the bad type on the first class element. All others | 3761 // We only report the bad type on the first class element. All others |
| 3759 // get a "type differs" error. | 3762 // get a "type differs" error. |
| 3760 if (caseType.element == compiler.doubleClass) { | 3763 if (caseType.element == compiler.doubleClass) { |
| 3761 compiler.reportError(node, | 3764 compiler.reportError(node, |
| 3762 MessageKind.SWITCH_CASE_VALUE_OVERRIDES_EQUALS, | 3765 MessageKind.SWITCH_CASE_VALUE_OVERRIDES_EQUALS, |
| 3763 {'type': "double"}); | 3766 {'type': "double"}); |
| 3764 } else if (caseType.element == compiler.functionClass) { | 3767 } else if (caseType.element == compiler.functionClass) { |
| 3765 compiler.reportError(node, MessageKind.SWITCH_CASE_FORBIDDEN, | 3768 compiler.reportError(node, MessageKind.SWITCH_CASE_FORBIDDEN, |
| 3766 {'type': "Function"}); | 3769 {'type': "Function"}); |
| 3767 } else if (constant.isObject && overridesEquals(caseType)) { | 3770 } else if (constant.value.isObject && overridesEquals(caseType)) { |
| 3768 compiler.reportError(firstCase.expression, | 3771 compiler.reportError(firstCase.expression, |
| 3769 MessageKind.SWITCH_CASE_VALUE_OVERRIDES_EQUALS, | 3772 MessageKind.SWITCH_CASE_VALUE_OVERRIDES_EQUALS, |
| 3770 {'type': caseType}); | 3773 {'type': caseType}); |
| 3771 } | 3774 } |
| 3772 } else { | 3775 } else { |
| 3773 if (caseType != firstCaseType) { | 3776 if (caseType != firstCaseType) { |
| 3774 if (!hasReportedProblem) { | 3777 if (!hasReportedProblem) { |
| 3775 compiler.reportError( | 3778 compiler.reportError( |
| 3776 node, | 3779 node, |
| 3777 MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL, | 3780 MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL, |
| (...skipping 1181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4959 } | 4962 } |
| 4960 | 4963 |
| 4961 /// The result for the resolution of the `assert` method. | 4964 /// The result for the resolution of the `assert` method. |
| 4962 class AssertResult implements ResolutionResult { | 4965 class AssertResult implements ResolutionResult { |
| 4963 const AssertResult(); | 4966 const AssertResult(); |
| 4964 | 4967 |
| 4965 Element get element => null; | 4968 Element get element => null; |
| 4966 | 4969 |
| 4967 String toString() => 'AssertResult()'; | 4970 String toString() => 'AssertResult()'; |
| 4968 } | 4971 } |
| OLD | NEW |