Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 library dart2js.resolution.constructors; | 5 library dart2js.resolution.constructors; |
| 6 | 6 |
| 7 import '../common.dart'; | 7 import '../common.dart'; |
| 8 import '../compiler.dart' show | 8 import '../compiler.dart' show |
| 9 Compiler; | 9 Compiler; |
| 10 import '../constants/constructors.dart' show | 10 import '../constants/constructors.dart' show |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 120 selector, MessageKind.INIT_STATIC_FIELD, {'fieldName': name}); | 120 selector, MessageKind.INIT_STATIC_FIELD, {'fieldName': name}); |
| 121 } else { | 121 } else { |
| 122 field = target; | 122 field = target; |
| 123 } | 123 } |
| 124 } else { | 124 } else { |
| 125 reporter.reportErrorMessage( | 125 reporter.reportErrorMessage( |
| 126 init, MessageKind.INVALID_RECEIVER_IN_INITIALIZER); | 126 init, MessageKind.INVALID_RECEIVER_IN_INITIALIZER); |
| 127 } | 127 } |
| 128 if (target != null) { | 128 if (target != null) { |
| 129 registry.useElement(init, target); | 129 registry.useElement(init, target); |
| 130 if (!target.isMalformed) { | |
| 131 registry.registerStaticUse(new StaticUse.fieldInit(target)); | |
| 132 } | |
| 133 checkForDuplicateInitializers(target, init); | 130 checkForDuplicateInitializers(target, init); |
| 134 } | 131 } |
| 132 if (field != null) { | |
| 133 registry.registerStaticUse(new StaticUse.fieldInit(field)); | |
| 134 } | |
| 135 // Resolve initializing value. | 135 // Resolve initializing value. |
| 136 ResolutionResult result = visitor.visitInStaticContext( | 136 ResolutionResult result = visitor.visitInStaticContext( |
| 137 init.arguments.head, | 137 init.arguments.head, |
| 138 inConstantInitializer: isConst); | 138 inConstantInitializer: isConst); |
| 139 if (isConst) { | 139 if (isConst) { |
| 140 if (result.isConstant && field != null) { | 140 if (result.isConstant && field != null) { |
| 141 // TODO(johnniwinther): Report error if `result.constant` is `null`. | 141 // TODO(johnniwinther): Report error if `result.constant` is `null`. |
| 142 fieldInitializers[field] = result.constant; | 142 fieldInitializers[field] = result.constant; |
| 143 } else { | 143 } else { |
| 144 isValidAsConstant = false; | 144 isValidAsConstant = false; |
| 145 } | 145 } |
| 146 } | 146 } |
| 147 } | 147 } |
| 148 | 148 |
| 149 InterfaceType getSuperOrThisLookupTarget(Node diagnosticNode, | 149 InterfaceType getSuperOrThisLookupTarget(Node diagnosticNode, |
| 150 {bool isSuperCall}) { | 150 {bool isSuperCall}) { |
| 151 if (isSuperCall) { | 151 if (isSuperCall) { |
| 152 // Calculate correct lookup target and constructor name. | 152 // Calculate correct lookup target and constructor name. |
| 153 if (constructor.enclosingClass.isObject) { | 153 if (constructor.enclosingClass.isObject) { |
| 154 reporter.reportErrorMessage( | 154 reporter.reportErrorMessage( |
| 155 diagnosticNode, MessageKind.SUPER_INITIALIZER_IN_OBJECT); | 155 diagnosticNode, MessageKind.SUPER_INITIALIZER_IN_OBJECT); |
| 156 isValidAsConstant = false; | 156 isValidAsConstant = false; |
| 157 } else { | 157 } else { |
| 158 return constructor.enclosingClass.supertype; | 158 return constructor.enclosingClass.supertype; |
| 159 } | 159 } |
| 160 } | 160 } |
| 161 return constructor.enclosingClass.thisType; | 161 return constructor.enclosingClass.thisType; |
| 162 } | 162 } |
| 163 | 163 |
| 164 ResolutionResult resolveSuperOrThisForSend(Send call) { | 164 ResolutionResult resolveSuperOrThisForSend(Send node) { |
| 165 // Resolve the selector and the arguments. | 165 // Resolve the selector and the arguments. |
| 166 ArgumentsResult argumentsResult = visitor.inStaticContext(() { | 166 ArgumentsResult argumentsResult = visitor.inStaticContext(() { |
| 167 visitor.resolveSelector(call, null); | 167 // TODO(johnniwinther): Remove this when [SendStructure] is used directly. |
| 168 return visitor.resolveArguments(call.argumentsNode); | 168 visitor.resolveSelector(node, null); |
| 169 return visitor.resolveArguments(node.argumentsNode); | |
| 169 }, inConstantInitializer: isConst); | 170 }, inConstantInitializer: isConst); |
| 170 | 171 |
| 171 bool isSuperCall = Initializers.isSuperConstructorCall(call); | 172 bool isSuperCall = Initializers.isSuperConstructorCall(node); |
| 172 InterfaceType targetType = | 173 InterfaceType targetType = |
| 173 getSuperOrThisLookupTarget(call, isSuperCall: isSuperCall); | 174 getSuperOrThisLookupTarget(node, isSuperCall: isSuperCall); |
| 174 ClassElement lookupTarget = targetType.element; | 175 ClassElement lookupTarget = targetType.element; |
| 175 Selector constructorSelector = | 176 String constructorName = |
| 176 visitor.getRedirectingThisOrSuperConstructorSelector(call); | 177 visitor.getRedirectingThisOrSuperConstructorName(node).text; |
| 177 ConstructorElement calledConstructor = findConstructor( | 178 ConstructorElement foundConstructor = findConstructor( |
| 178 constructor.library, lookupTarget, constructorSelector.name); | 179 constructor.library, lookupTarget, constructorName); |
| 179 | 180 |
| 180 final bool isImplicitSuperCall = false; | 181 final bool isImplicitSuperCall = false; |
| 181 final String className = lookupTarget.name; | 182 final String className = lookupTarget.name; |
| 182 verifyThatConstructorMatchesCall(calledConstructor, | 183 CallStructure callStructure = argumentsResult.callStructure; |
| 183 argumentsResult.callStructure, | 184 ConstructorElement calledConstructor = verifyThatConstructorMatchesCall( |
| 184 isImplicitSuperCall, | 185 node, |
| 185 call, | 186 foundConstructor, |
| 186 className, | 187 callStructure, |
| 187 constructorSelector); | 188 className, |
| 188 if (calledConstructor != null) { | 189 constructorName: constructorName, |
| 189 registry.useElement(call, calledConstructor); | 190 isThisCall: !isSuperCall, |
| 191 isImplicitSuperCall: false); | |
| 192 // TODO(johnniwinther): Remove this when information is pulled from an | |
| 193 // [InitializerStructure]. | |
| 194 registry.useElement(node, calledConstructor); | |
| 195 if (!calledConstructor.isError) { | |
| 190 registry.registerStaticUse( | 196 registry.registerStaticUse( |
| 191 new StaticUse.superConstructorInvoke( | 197 new StaticUse.superConstructorInvoke( |
| 192 calledConstructor, argumentsResult.callStructure)); | 198 calledConstructor, callStructure)); |
| 193 } | 199 } |
| 194 if (isConst) { | 200 if (isConst) { |
| 195 if (isValidAsConstant && | 201 if (isValidAsConstant && |
| 196 calledConstructor.isConst && | 202 calledConstructor.isConst && |
| 197 argumentsResult.isValidAsConstant) { | 203 argumentsResult.isValidAsConstant) { |
| 198 CallStructure callStructure = argumentsResult.callStructure; | |
| 199 List<ConstantExpression> arguments = argumentsResult.constantArguments; | 204 List<ConstantExpression> arguments = argumentsResult.constantArguments; |
| 200 return new ConstantResult( | 205 return new ConstantResult( |
| 201 call, | 206 node, |
| 202 new ConstructedConstantExpression( | 207 new ConstructedConstantExpression( |
| 203 targetType, | 208 targetType, |
| 204 calledConstructor, | 209 calledConstructor, |
| 205 callStructure, | 210 callStructure, |
| 206 arguments), | 211 arguments), |
| 207 element: calledConstructor); | 212 element: calledConstructor); |
| 208 } else { | 213 } else { |
| 209 isValidAsConstant = false; | 214 isValidAsConstant = false; |
| 210 } | 215 } |
| 211 } | 216 } |
| 212 return new ResolutionResult.forElement(calledConstructor); | 217 return new ResolutionResult.forElement(calledConstructor); |
| 213 } | 218 } |
| 214 | 219 |
| 215 ConstructedConstantExpression resolveImplicitSuperConstructorSend() { | 220 ConstructedConstantExpression resolveImplicitSuperConstructorSend() { |
| 216 // If the class has a super resolve the implicit super call. | 221 // If the class has a super resolve the implicit super call. |
| 217 ClassElement classElement = constructor.enclosingClass; | 222 ClassElement classElement = constructor.enclosingClass; |
| 218 ClassElement superClass = classElement.superclass; | 223 ClassElement superClass = classElement.superclass; |
| 219 if (!classElement.isObject) { | 224 if (!classElement.isObject) { |
| 220 assert(superClass != null); | 225 assert(superClass != null); |
| 221 assert(superClass.isResolved); | 226 assert(superClass.isResolved); |
| 222 | 227 |
| 223 InterfaceType targetType = | 228 InterfaceType targetType = |
| 224 getSuperOrThisLookupTarget(functionNode, isSuperCall: true); | 229 getSuperOrThisLookupTarget(functionNode, isSuperCall: true); |
| 225 ClassElement lookupTarget = targetType.element; | 230 ClassElement lookupTarget = targetType.element; |
| 226 Selector constructorSelector = new Selector.callDefaultConstructor(); | 231 ConstructorElement calledConstructor = |
| 227 ConstructorElement calledConstructor = findConstructor( | 232 findConstructor(constructor.library, lookupTarget, ''); |
| 228 constructor.library, | |
| 229 lookupTarget, | |
| 230 constructorSelector.name); | |
| 231 | 233 |
| 232 final String className = lookupTarget.name; | 234 final String className = lookupTarget.name; |
| 233 final bool isImplicitSuperCall = true; | 235 CallStructure callStructure = CallStructure.NO_ARGS; |
| 234 verifyThatConstructorMatchesCall(calledConstructor, | 236 ConstructorElement result = verifyThatConstructorMatchesCall( |
| 235 CallStructure.NO_ARGS, | 237 functionNode, |
| 236 isImplicitSuperCall, | 238 calledConstructor, |
| 237 functionNode, | 239 callStructure, |
| 238 className, | 240 className, |
| 239 constructorSelector); | 241 isImplicitSuperCall: true); |
| 240 if (calledConstructor != null) { | 242 if (!result.isError) { |
| 241 registry.registerStaticUse( | 243 registry.registerStaticUse( |
| 242 new StaticUse.constructorInvoke( | 244 new StaticUse.constructorInvoke(calledConstructor, callStructure)); |
| 243 calledConstructor, constructorSelector.callStructure)); | |
| 244 } | 245 } |
| 245 | 246 |
| 246 if (isConst && isValidAsConstant) { | 247 if (isConst && isValidAsConstant) { |
| 247 return new ConstructedConstantExpression( | 248 return new ConstructedConstantExpression( |
| 248 targetType, | 249 targetType, |
| 249 calledConstructor, | 250 result, |
| 250 CallStructure.NO_ARGS, | 251 CallStructure.NO_ARGS, |
| 251 const <ConstantExpression>[]); | 252 const <ConstantExpression>[]); |
| 252 } | 253 } |
| 253 } | 254 } |
| 254 return null; | 255 return null; |
| 255 } | 256 } |
| 256 | 257 |
| 257 void verifyThatConstructorMatchesCall( | 258 ConstructorElement reportAndCreateErroneousConstructor( |
| 259 Spannable diagnosticNode, | |
| 260 String name, | |
| 261 MessageKind kind, | |
| 262 Map arguments) { | |
| 263 isValidAsConstant = false; | |
| 264 reporter.reportErrorMessage( | |
| 265 diagnosticNode, kind, arguments); | |
| 266 return new ErroneousConstructorElementX( | |
| 267 kind, arguments, name, visitor.currentClass); | |
| 268 } | |
| 269 | |
| 270 ConstructorElement verifyThatConstructorMatchesCall( | |
|
sigurdm
2015/11/09 11:40:44
Dartdoc-comment needed explaining what is returned
Johnni Winther
2015/11/09 11:52:56
Done.
| |
| 271 Node node, | |
| 258 ConstructorElementX lookedupConstructor, | 272 ConstructorElementX lookedupConstructor, |
| 259 CallStructure call, | 273 CallStructure callStructure, |
| 260 bool isImplicitSuperCall, | |
| 261 Node diagnosticNode, | |
| 262 String className, | 274 String className, |
| 263 Selector constructorSelector) { | 275 {String constructorName: '', |
| 264 if (lookedupConstructor == null || | 276 bool isImplicitSuperCall: false, |
| 265 !lookedupConstructor.isGenerativeConstructor) { | 277 bool isThisCall: false}) { |
| 266 String fullConstructorName = Elements.constructorNameForDiagnostics( | 278 Element result = lookedupConstructor; |
| 267 className, | 279 if (lookedupConstructor == null) { |
| 268 constructorSelector.name); | 280 String fullConstructorName = |
| 281 Elements.constructorNameForDiagnostics(className, constructorName); | |
| 269 MessageKind kind = isImplicitSuperCall | 282 MessageKind kind = isImplicitSuperCall |
| 270 ? MessageKind.CANNOT_RESOLVE_CONSTRUCTOR_FOR_IMPLICIT | 283 ? MessageKind.CANNOT_RESOLVE_CONSTRUCTOR_FOR_IMPLICIT |
| 271 : MessageKind.CANNOT_RESOLVE_CONSTRUCTOR; | 284 : MessageKind.CANNOT_RESOLVE_CONSTRUCTOR; |
| 272 reporter.reportErrorMessage( | 285 result = reportAndCreateErroneousConstructor( |
| 273 diagnosticNode, kind, {'constructorName': fullConstructorName}); | 286 node, constructorName, |
| 274 isValidAsConstant = false; | 287 kind, {'constructorName': fullConstructorName}); |
| 288 } else if (!lookedupConstructor.isGenerativeConstructor) { | |
| 289 MessageKind kind = isThisCall | |
| 290 ? MessageKind.THIS_CALL_TO_FACTORY | |
| 291 : MessageKind.SUPER_CALL_TO_FACTORY; | |
| 292 result = reportAndCreateErroneousConstructor( | |
| 293 node, constructorName, kind, {}); | |
| 275 } else { | 294 } else { |
| 276 lookedupConstructor.computeType(visitor.resolution); | 295 lookedupConstructor.computeType(visitor.resolution); |
| 277 if (!call.signatureApplies(lookedupConstructor.functionSignature)) { | 296 if (!callStructure.signatureApplies( |
| 297 lookedupConstructor.functionSignature)) { | |
| 278 MessageKind kind = isImplicitSuperCall | 298 MessageKind kind = isImplicitSuperCall |
| 279 ? MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT | 299 ? MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT |
| 280 : MessageKind.NO_MATCHING_CONSTRUCTOR; | 300 : MessageKind.NO_MATCHING_CONSTRUCTOR; |
| 281 reporter.reportErrorMessage(diagnosticNode, kind); | 301 result = reportAndCreateErroneousConstructor( |
| 282 isValidAsConstant = false; | 302 node, constructorName, kind, {}); |
| 283 } else if (constructor.isConst | 303 } else if (constructor.isConst && !lookedupConstructor.isConst) { |
| 284 && !lookedupConstructor.isConst) { | |
| 285 MessageKind kind = isImplicitSuperCall | 304 MessageKind kind = isImplicitSuperCall |
| 286 ? MessageKind.CONST_CALLS_NON_CONST_FOR_IMPLICIT | 305 ? MessageKind.CONST_CALLS_NON_CONST_FOR_IMPLICIT |
| 287 : MessageKind.CONST_CALLS_NON_CONST; | 306 : MessageKind.CONST_CALLS_NON_CONST; |
| 288 reporter.reportErrorMessage(diagnosticNode, kind); | 307 result = reportAndCreateErroneousConstructor( |
| 289 isValidAsConstant = false; | 308 node, constructorName, kind, {}); |
| 290 } | 309 } |
| 291 } | 310 } |
| 311 return result; | |
| 292 } | 312 } |
| 293 | 313 |
| 294 /** | 314 /** |
| 295 * Resolve all initializers of this constructor. In the case of a redirecting | 315 * Resolve all initializers of this constructor. In the case of a redirecting |
| 296 * constructor, the resolved constructor's function element is returned. | 316 * constructor, the resolved constructor's function element is returned. |
| 297 */ | 317 */ |
| 298 ConstructorElement resolveInitializers() { | 318 ConstructorElement resolveInitializers() { |
| 299 Map<dynamic/*String|int*/, ConstantExpression> defaultValues = | 319 Map<dynamic/*String|int*/, ConstantExpression> defaultValues = |
| 300 <dynamic/*String|int*/, ConstantExpression>{}; | 320 <dynamic/*String|int*/, ConstantExpression>{}; |
| 301 ConstructedConstantExpression constructorInvocation; | 321 ConstructedConstantExpression constructorInvocation; |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 483 | 503 |
| 484 ConstructorResult resolveConstructor( | 504 ConstructorResult resolveConstructor( |
| 485 InterfaceType type, | 505 InterfaceType type, |
| 486 Node diagnosticNode, | 506 Node diagnosticNode, |
| 487 String constructorName) { | 507 String constructorName) { |
| 488 ClassElement cls = type.element; | 508 ClassElement cls = type.element; |
| 489 cls.ensureResolved(resolution); | 509 cls.ensureResolved(resolution); |
| 490 ConstructorElement constructor = findConstructor( | 510 ConstructorElement constructor = findConstructor( |
| 491 resolver.enclosingElement.library, cls, constructorName); | 511 resolver.enclosingElement.library, cls, constructorName); |
| 492 if (constructor == null) { | 512 if (constructor == null) { |
| 493 String fullConstructorName = | 513 MessageKind kind = constructorName.isEmpty |
| 494 Elements.constructorNameForDiagnostics(cls.name, constructorName); | 514 ? MessageKind.CANNOT_FIND_UNNAMED_CONSTRUCTOR |
| 515 : MessageKind.CANNOT_FIND_CONSTRUCTOR; | |
| 495 return reportAndCreateErroneousConstructorElement( | 516 return reportAndCreateErroneousConstructorElement( |
| 496 diagnosticNode, | 517 diagnosticNode, |
| 497 ConstructorResultKind.UNRESOLVED_CONSTRUCTOR, type, | 518 ConstructorResultKind.UNRESOLVED_CONSTRUCTOR, type, |
| 498 cls, constructorName, | 519 cls, constructorName, kind, |
| 499 MessageKind.CANNOT_FIND_CONSTRUCTOR, | 520 {'className': cls.name, 'constructorName': constructorName}, |
| 500 {'constructorName': fullConstructorName}, | |
| 501 missingConstructor: true); | 521 missingConstructor: true); |
| 502 } else if (inConstContext && !constructor.isConst) { | 522 } else if (inConstContext && !constructor.isConst) { |
| 503 reporter.reportErrorMessage( | 523 reporter.reportErrorMessage( |
| 504 diagnosticNode, MessageKind.CONSTRUCTOR_IS_NOT_CONST); | 524 diagnosticNode, MessageKind.CONSTRUCTOR_IS_NOT_CONST); |
| 505 return new ConstructorResult( | 525 return new ConstructorResult( |
| 506 ConstructorResultKind.NON_CONSTANT, constructor, type); | 526 ConstructorResultKind.NON_CONSTANT, constructor, type); |
| 507 } else { | 527 } else { |
| 508 if (constructor.isGenerativeConstructor) { | 528 if (constructor.isGenerativeConstructor) { |
| 509 if (cls.isAbstract) { | 529 if (cls.isAbstract) { |
| 510 reporter.reportWarningMessage( | 530 reporter.reportWarningMessage( |
| (...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 761 // constructors. | 781 // constructors. |
| 762 return null; | 782 return null; |
| 763 } | 783 } |
| 764 // TODO(johnniwinther): Use [Name] for lookup. | 784 // TODO(johnniwinther): Use [Name] for lookup. |
| 765 ConstructorElement constructor = cls.lookupConstructor(constructorName); | 785 ConstructorElement constructor = cls.lookupConstructor(constructorName); |
| 766 if (constructor != null) { | 786 if (constructor != null) { |
| 767 constructor = constructor.declaration; | 787 constructor = constructor.declaration; |
| 768 } | 788 } |
| 769 return constructor; | 789 return constructor; |
| 770 } | 790 } |
| OLD | NEW |