| 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 /// Checks that [lookedupConstructor] is valid as a target for the super/this |
| 271 /// constructor call using with the given [callStructure]. |
| 272 /// |
| 273 /// If [lookedupConstructor] is valid it is returned, otherwise an error is |
| 274 /// reported and an [ErroneousConstructorElement] is returned. |
| 275 ConstructorElement verifyThatConstructorMatchesCall( |
| 276 Node node, |
| 258 ConstructorElementX lookedupConstructor, | 277 ConstructorElementX lookedupConstructor, |
| 259 CallStructure call, | 278 CallStructure callStructure, |
| 260 bool isImplicitSuperCall, | |
| 261 Node diagnosticNode, | |
| 262 String className, | 279 String className, |
| 263 Selector constructorSelector) { | 280 {String constructorName: '', |
| 264 if (lookedupConstructor == null || | 281 bool isImplicitSuperCall: false, |
| 265 !lookedupConstructor.isGenerativeConstructor) { | 282 bool isThisCall: false}) { |
| 266 String fullConstructorName = Elements.constructorNameForDiagnostics( | 283 Element result = lookedupConstructor; |
| 267 className, | 284 if (lookedupConstructor == null) { |
| 268 constructorSelector.name); | 285 String fullConstructorName = |
| 286 Elements.constructorNameForDiagnostics(className, constructorName); |
| 269 MessageKind kind = isImplicitSuperCall | 287 MessageKind kind = isImplicitSuperCall |
| 270 ? MessageKind.CANNOT_RESOLVE_CONSTRUCTOR_FOR_IMPLICIT | 288 ? MessageKind.CANNOT_RESOLVE_CONSTRUCTOR_FOR_IMPLICIT |
| 271 : MessageKind.CANNOT_RESOLVE_CONSTRUCTOR; | 289 : MessageKind.CANNOT_RESOLVE_CONSTRUCTOR; |
| 272 reporter.reportErrorMessage( | 290 result = reportAndCreateErroneousConstructor( |
| 273 diagnosticNode, kind, {'constructorName': fullConstructorName}); | 291 node, constructorName, |
| 274 isValidAsConstant = false; | 292 kind, {'constructorName': fullConstructorName}); |
| 293 } else if (!lookedupConstructor.isGenerativeConstructor) { |
| 294 MessageKind kind = isThisCall |
| 295 ? MessageKind.THIS_CALL_TO_FACTORY |
| 296 : MessageKind.SUPER_CALL_TO_FACTORY; |
| 297 result = reportAndCreateErroneousConstructor( |
| 298 node, constructorName, kind, {}); |
| 275 } else { | 299 } else { |
| 276 lookedupConstructor.computeType(visitor.resolution); | 300 lookedupConstructor.computeType(visitor.resolution); |
| 277 if (!call.signatureApplies(lookedupConstructor.functionSignature)) { | 301 if (!callStructure.signatureApplies( |
| 302 lookedupConstructor.functionSignature)) { |
| 278 MessageKind kind = isImplicitSuperCall | 303 MessageKind kind = isImplicitSuperCall |
| 279 ? MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT | 304 ? MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT |
| 280 : MessageKind.NO_MATCHING_CONSTRUCTOR; | 305 : MessageKind.NO_MATCHING_CONSTRUCTOR; |
| 281 reporter.reportErrorMessage(diagnosticNode, kind); | 306 result = reportAndCreateErroneousConstructor( |
| 282 isValidAsConstant = false; | 307 node, constructorName, kind, {}); |
| 283 } else if (constructor.isConst | 308 } else if (constructor.isConst && !lookedupConstructor.isConst) { |
| 284 && !lookedupConstructor.isConst) { | |
| 285 MessageKind kind = isImplicitSuperCall | 309 MessageKind kind = isImplicitSuperCall |
| 286 ? MessageKind.CONST_CALLS_NON_CONST_FOR_IMPLICIT | 310 ? MessageKind.CONST_CALLS_NON_CONST_FOR_IMPLICIT |
| 287 : MessageKind.CONST_CALLS_NON_CONST; | 311 : MessageKind.CONST_CALLS_NON_CONST; |
| 288 reporter.reportErrorMessage(diagnosticNode, kind); | 312 result = reportAndCreateErroneousConstructor( |
| 289 isValidAsConstant = false; | 313 node, constructorName, kind, {}); |
| 290 } | 314 } |
| 291 } | 315 } |
| 316 return result; |
| 292 } | 317 } |
| 293 | 318 |
| 294 /** | 319 /** |
| 295 * Resolve all initializers of this constructor. In the case of a redirecting | 320 * Resolve all initializers of this constructor. In the case of a redirecting |
| 296 * constructor, the resolved constructor's function element is returned. | 321 * constructor, the resolved constructor's function element is returned. |
| 297 */ | 322 */ |
| 298 ConstructorElement resolveInitializers() { | 323 ConstructorElement resolveInitializers() { |
| 299 Map<dynamic/*String|int*/, ConstantExpression> defaultValues = | 324 Map<dynamic/*String|int*/, ConstantExpression> defaultValues = |
| 300 <dynamic/*String|int*/, ConstantExpression>{}; | 325 <dynamic/*String|int*/, ConstantExpression>{}; |
| 301 ConstructedConstantExpression constructorInvocation; | 326 ConstructedConstantExpression constructorInvocation; |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 483 | 508 |
| 484 ConstructorResult resolveConstructor( | 509 ConstructorResult resolveConstructor( |
| 485 InterfaceType type, | 510 InterfaceType type, |
| 486 Node diagnosticNode, | 511 Node diagnosticNode, |
| 487 String constructorName) { | 512 String constructorName) { |
| 488 ClassElement cls = type.element; | 513 ClassElement cls = type.element; |
| 489 cls.ensureResolved(resolution); | 514 cls.ensureResolved(resolution); |
| 490 ConstructorElement constructor = findConstructor( | 515 ConstructorElement constructor = findConstructor( |
| 491 resolver.enclosingElement.library, cls, constructorName); | 516 resolver.enclosingElement.library, cls, constructorName); |
| 492 if (constructor == null) { | 517 if (constructor == null) { |
| 493 String fullConstructorName = | 518 MessageKind kind = constructorName.isEmpty |
| 494 Elements.constructorNameForDiagnostics(cls.name, constructorName); | 519 ? MessageKind.CANNOT_FIND_UNNAMED_CONSTRUCTOR |
| 520 : MessageKind.CANNOT_FIND_CONSTRUCTOR; |
| 495 return reportAndCreateErroneousConstructorElement( | 521 return reportAndCreateErroneousConstructorElement( |
| 496 diagnosticNode, | 522 diagnosticNode, |
| 497 ConstructorResultKind.UNRESOLVED_CONSTRUCTOR, type, | 523 ConstructorResultKind.UNRESOLVED_CONSTRUCTOR, type, |
| 498 cls, constructorName, | 524 cls, constructorName, kind, |
| 499 MessageKind.CANNOT_FIND_CONSTRUCTOR, | 525 {'className': cls.name, 'constructorName': constructorName}, |
| 500 {'constructorName': fullConstructorName}, | |
| 501 missingConstructor: true); | 526 missingConstructor: true); |
| 502 } else if (inConstContext && !constructor.isConst) { | 527 } else if (inConstContext && !constructor.isConst) { |
| 503 reporter.reportErrorMessage( | 528 reporter.reportErrorMessage( |
| 504 diagnosticNode, MessageKind.CONSTRUCTOR_IS_NOT_CONST); | 529 diagnosticNode, MessageKind.CONSTRUCTOR_IS_NOT_CONST); |
| 505 return new ConstructorResult( | 530 return new ConstructorResult( |
| 506 ConstructorResultKind.NON_CONSTANT, constructor, type); | 531 ConstructorResultKind.NON_CONSTANT, constructor, type); |
| 507 } else { | 532 } else { |
| 508 if (constructor.isGenerativeConstructor) { | 533 if (constructor.isGenerativeConstructor) { |
| 509 if (cls.isAbstract) { | 534 if (cls.isAbstract) { |
| 510 reporter.reportWarningMessage( | 535 reporter.reportWarningMessage( |
| (...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 761 // constructors. | 786 // constructors. |
| 762 return null; | 787 return null; |
| 763 } | 788 } |
| 764 // TODO(johnniwinther): Use [Name] for lookup. | 789 // TODO(johnniwinther): Use [Name] for lookup. |
| 765 ConstructorElement constructor = cls.lookupConstructor(constructorName); | 790 ConstructorElement constructor = cls.lookupConstructor(constructorName); |
| 766 if (constructor != null) { | 791 if (constructor != null) { |
| 767 constructor = constructor.declaration; | 792 constructor = constructor.declaration; |
| 768 } | 793 } |
| 769 return constructor; | 794 return constructor; |
| 770 } | 795 } |
| OLD | NEW |