| 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 '../common/resolution.dart' show | 8 import '../common/resolution.dart' show Feature; |
| 9 Feature; | 9 import '../compiler.dart' show Compiler; |
| 10 import '../compiler.dart' show | 10 import '../constants/constructors.dart' |
| 11 Compiler; | 11 show |
| 12 import '../constants/constructors.dart' show | 12 GenerativeConstantConstructor, |
| 13 GenerativeConstantConstructor, | 13 RedirectingGenerativeConstantConstructor; |
| 14 RedirectingGenerativeConstantConstructor; | |
| 15 import '../constants/expressions.dart'; | 14 import '../constants/expressions.dart'; |
| 16 import '../dart_types.dart'; | 15 import '../dart_types.dart'; |
| 17 import '../elements/elements.dart'; | 16 import '../elements/elements.dart'; |
| 18 import '../elements/modelx.dart' show | 17 import '../elements/modelx.dart' |
| 19 ConstructorElementX, | 18 show |
| 20 ErroneousConstructorElementX, | 19 ConstructorElementX, |
| 21 ErroneousElementX, | 20 ErroneousConstructorElementX, |
| 22 ErroneousFieldElementX, | 21 ErroneousElementX, |
| 23 FieldElementX, | 22 ErroneousFieldElementX, |
| 24 InitializingFormalElementX, | 23 FieldElementX, |
| 25 ParameterElementX; | 24 InitializingFormalElementX, |
| 25 ParameterElementX; |
| 26 import '../tree/tree.dart'; | 26 import '../tree/tree.dart'; |
| 27 import '../util/util.dart' show | 27 import '../util/util.dart' show Link; |
| 28 Link; | 28 import '../universe/call_structure.dart' show CallStructure; |
| 29 import '../universe/call_structure.dart' show | 29 import '../universe/use.dart' show StaticUse; |
| 30 CallStructure; | |
| 31 import '../universe/use.dart' show | |
| 32 StaticUse; | |
| 33 | 30 |
| 34 import 'members.dart' show | 31 import 'members.dart' show lookupInScope, ResolverVisitor; |
| 35 lookupInScope, | 32 import 'registry.dart' show ResolutionRegistry; |
| 36 ResolverVisitor; | 33 import 'resolution_common.dart' show CommonResolverVisitor; |
| 37 import 'registry.dart' show | |
| 38 ResolutionRegistry; | |
| 39 import 'resolution_common.dart' show | |
| 40 CommonResolverVisitor; | |
| 41 import 'resolution_result.dart'; | 34 import 'resolution_result.dart'; |
| 42 | 35 |
| 43 class InitializerResolver { | 36 class InitializerResolver { |
| 44 final ResolverVisitor visitor; | 37 final ResolverVisitor visitor; |
| 45 final ConstructorElementX constructor; | 38 final ConstructorElementX constructor; |
| 46 final FunctionExpression functionNode; | 39 final FunctionExpression functionNode; |
| 47 final Map<FieldElement, Node> initialized = <FieldElement, Node>{}; | 40 final Map<FieldElement, Node> initialized = <FieldElement, Node>{}; |
| 48 final Map<FieldElement, ConstantExpression> fieldInitializers = | 41 final Map<FieldElement, ConstantExpression> fieldInitializers = |
| 49 <FieldElement, ConstantExpression>{}; | 42 <FieldElement, ConstantExpression>{}; |
| 50 Link<Node> initializers; | 43 Link<Node> initializers; |
| 51 bool hasSuper = false; | 44 bool hasSuper = false; |
| 52 bool isValidAsConstant = true; | 45 bool isValidAsConstant = true; |
| 53 | 46 |
| 54 bool get isConst => constructor.isConst; | 47 bool get isConst => constructor.isConst; |
| 55 | 48 |
| 56 InitializerResolver(this.visitor, this.constructor, this.functionNode); | 49 InitializerResolver(this.visitor, this.constructor, this.functionNode); |
| 57 | 50 |
| 58 ResolutionRegistry get registry => visitor.registry; | 51 ResolutionRegistry get registry => visitor.registry; |
| 59 | 52 |
| 60 DiagnosticReporter get reporter => visitor.reporter; | 53 DiagnosticReporter get reporter => visitor.reporter; |
| 61 | 54 |
| 62 bool isFieldInitializer(SendSet node) { | 55 bool isFieldInitializer(SendSet node) { |
| 63 if (node.selector.asIdentifier() == null) return false; | 56 if (node.selector.asIdentifier() == null) return false; |
| 64 if (node.receiver == null) return true; | 57 if (node.receiver == null) return true; |
| 65 if (node.receiver.asIdentifier() == null) return false; | 58 if (node.receiver.asIdentifier() == null) return false; |
| 66 return node.receiver.asIdentifier().isThis(); | 59 return node.receiver.asIdentifier().isThis(); |
| 67 } | 60 } |
| 68 | 61 |
| 69 reportDuplicateInitializerError(Element field, | 62 reportDuplicateInitializerError( |
| 70 Node init, | 63 Element field, Node init, Spannable existing) { |
| 71 Spannable existing) { | |
| 72 reporter.reportError( | 64 reporter.reportError( |
| 73 reporter.createMessage( | 65 reporter.createMessage( |
| 74 init, | 66 init, MessageKind.DUPLICATE_INITIALIZER, {'fieldName': field.name}), |
| 75 MessageKind.DUPLICATE_INITIALIZER, | |
| 76 {'fieldName': field.name}), | |
| 77 <DiagnosticMessage>[ | 67 <DiagnosticMessage>[ |
| 78 reporter.createMessage( | 68 reporter.createMessage(existing, MessageKind.ALREADY_INITIALIZED, |
| 79 existing, | 69 {'fieldName': field.name}), |
| 80 MessageKind.ALREADY_INITIALIZED, | |
| 81 {'fieldName': field.name}), | |
| 82 ]); | 70 ]); |
| 83 isValidAsConstant = false; | 71 isValidAsConstant = false; |
| 84 } | 72 } |
| 85 | 73 |
| 86 void checkForDuplicateInitializers(FieldElementX field, Node init) { | 74 void checkForDuplicateInitializers(FieldElementX field, Node init) { |
| 87 // [field] can be null if it could not be resolved. | 75 // [field] can be null if it could not be resolved. |
| 88 if (field == null) return; | 76 if (field == null) return; |
| 89 if (initialized.containsKey(field)) { | 77 if (initialized.containsKey(field)) { |
| 90 reportDuplicateInitializerError(field, init, initialized[field]); | 78 reportDuplicateInitializerError(field, init, initialized[field]); |
| 91 } else if (field.isFinal) { | 79 } else if (field.isFinal) { |
| 92 field.parseNode(visitor.resolution.parsing); | 80 field.parseNode(visitor.resolution.parsing); |
| 93 Expression initializer = field.initializer; | 81 Expression initializer = field.initializer; |
| 94 if (initializer != null) { | 82 if (initializer != null) { |
| 95 reportDuplicateInitializerError(field, init, | 83 reportDuplicateInitializerError( |
| 96 reporter.withCurrentElement(field, | 84 field, |
| 97 () => reporter.spanFromSpannable(initializer))); | 85 init, |
| 86 reporter.withCurrentElement( |
| 87 field, () => reporter.spanFromSpannable(initializer))); |
| 98 } | 88 } |
| 99 } | 89 } |
| 100 initialized[field] = init; | 90 initialized[field] = init; |
| 101 } | 91 } |
| 102 | 92 |
| 103 void resolveFieldInitializer(SendSet init) { | 93 void resolveFieldInitializer(SendSet init) { |
| 104 // init is of the form [this.]field = value. | 94 // init is of the form [this.]field = value. |
| 105 final Node selector = init.selector; | 95 final Node selector = init.selector; |
| 106 final String name = selector.asIdentifier().source; | 96 final String name = selector.asIdentifier().source; |
| 107 // Lookup target field. | 97 // Lookup target field. |
| (...skipping 22 matching lines...) Expand all Loading... |
| 130 init, MessageKind.INVALID_RECEIVER_IN_INITIALIZER); | 120 init, MessageKind.INVALID_RECEIVER_IN_INITIALIZER); |
| 131 } | 121 } |
| 132 if (target != null) { | 122 if (target != null) { |
| 133 registry.useElement(init, target); | 123 registry.useElement(init, target); |
| 134 checkForDuplicateInitializers(target, init); | 124 checkForDuplicateInitializers(target, init); |
| 135 } | 125 } |
| 136 if (field != null) { | 126 if (field != null) { |
| 137 registry.registerStaticUse(new StaticUse.fieldInit(field)); | 127 registry.registerStaticUse(new StaticUse.fieldInit(field)); |
| 138 } | 128 } |
| 139 // Resolve initializing value. | 129 // Resolve initializing value. |
| 140 ResolutionResult result = visitor.visitInStaticContext( | 130 ResolutionResult result = visitor.visitInStaticContext(init.arguments.head, |
| 141 init.arguments.head, | |
| 142 inConstantInitializer: isConst); | 131 inConstantInitializer: isConst); |
| 143 if (isConst) { | 132 if (isConst) { |
| 144 if (result.isConstant && field != null) { | 133 if (result.isConstant && field != null) { |
| 145 // TODO(johnniwinther): Report error if `result.constant` is `null`. | 134 // TODO(johnniwinther): Report error if `result.constant` is `null`. |
| 146 fieldInitializers[field] = result.constant; | 135 fieldInitializers[field] = result.constant; |
| 147 } else { | 136 } else { |
| 148 isValidAsConstant = false; | 137 isValidAsConstant = false; |
| 149 } | 138 } |
| 150 } | 139 } |
| 151 } | 140 } |
| 152 | 141 |
| 153 InterfaceType getSuperOrThisLookupTarget(Node diagnosticNode, | 142 InterfaceType getSuperOrThisLookupTarget(Node diagnosticNode, |
| 154 {bool isSuperCall}) { | 143 {bool isSuperCall}) { |
| 155 if (isSuperCall) { | 144 if (isSuperCall) { |
| 156 // Calculate correct lookup target and constructor name. | 145 // Calculate correct lookup target and constructor name. |
| 157 if (constructor.enclosingClass.isObject) { | 146 if (constructor.enclosingClass.isObject) { |
| 158 reporter.reportErrorMessage( | 147 reporter.reportErrorMessage( |
| 159 diagnosticNode, MessageKind.SUPER_INITIALIZER_IN_OBJECT); | 148 diagnosticNode, MessageKind.SUPER_INITIALIZER_IN_OBJECT); |
| 160 isValidAsConstant = false; | 149 isValidAsConstant = false; |
| 161 } else { | 150 } else { |
| 162 return constructor.enclosingClass.supertype; | 151 return constructor.enclosingClass.supertype; |
| 163 } | 152 } |
| 164 } | 153 } |
| 165 return constructor.enclosingClass.thisType; | 154 return constructor.enclosingClass.thisType; |
| 166 } | 155 } |
| 167 | 156 |
| 168 ResolutionResult resolveSuperOrThisForSend(Send node) { | 157 ResolutionResult resolveSuperOrThisForSend(Send node) { |
| 169 // Resolve the selector and the arguments. | 158 // Resolve the selector and the arguments. |
| 170 ArgumentsResult argumentsResult = visitor.inStaticContext(() { | 159 ArgumentsResult argumentsResult = visitor.inStaticContext(() { |
| 171 // TODO(johnniwinther): Remove this when [SendStructure] is used directly. | 160 // TODO(johnniwinther): Remove this when [SendStructure] is used directly. |
| 172 visitor.resolveSelector(node, null); | 161 visitor.resolveSelector(node, null); |
| 173 return visitor.resolveArguments(node.argumentsNode); | 162 return visitor.resolveArguments(node.argumentsNode); |
| 174 }, inConstantInitializer: isConst); | 163 }, inConstantInitializer: isConst); |
| 175 | 164 |
| 176 bool isSuperCall = Initializers.isSuperConstructorCall(node); | 165 bool isSuperCall = Initializers.isSuperConstructorCall(node); |
| 177 InterfaceType targetType = | 166 InterfaceType targetType = |
| 178 getSuperOrThisLookupTarget(node, isSuperCall: isSuperCall); | 167 getSuperOrThisLookupTarget(node, isSuperCall: isSuperCall); |
| 179 ClassElement lookupTarget = targetType.element; | 168 ClassElement lookupTarget = targetType.element; |
| 180 String constructorName = | 169 String constructorName = |
| 181 visitor.getRedirectingThisOrSuperConstructorName(node).text; | 170 visitor.getRedirectingThisOrSuperConstructorName(node).text; |
| 182 ConstructorElement foundConstructor = findConstructor( | 171 ConstructorElement foundConstructor = |
| 183 constructor.library, lookupTarget, constructorName); | 172 findConstructor(constructor.library, lookupTarget, constructorName); |
| 184 | 173 |
| 185 final bool isImplicitSuperCall = false; | 174 final bool isImplicitSuperCall = false; |
| 186 final String className = lookupTarget.name; | 175 final String className = lookupTarget.name; |
| 187 CallStructure callStructure = argumentsResult.callStructure; | 176 CallStructure callStructure = argumentsResult.callStructure; |
| 188 ConstructorElement calledConstructor = verifyThatConstructorMatchesCall( | 177 ConstructorElement calledConstructor = verifyThatConstructorMatchesCall( |
| 189 node, | 178 node, foundConstructor, callStructure, className, |
| 190 foundConstructor, | |
| 191 callStructure, | |
| 192 className, | |
| 193 constructorName: constructorName, | 179 constructorName: constructorName, |
| 194 isThisCall: !isSuperCall, | 180 isThisCall: !isSuperCall, |
| 195 isImplicitSuperCall: false); | 181 isImplicitSuperCall: false); |
| 196 // TODO(johnniwinther): Remove this when information is pulled from an | 182 // TODO(johnniwinther): Remove this when information is pulled from an |
| 197 // [InitializerStructure]. | 183 // [InitializerStructure]. |
| 198 registry.useElement(node, calledConstructor); | 184 registry.useElement(node, calledConstructor); |
| 199 if (!calledConstructor.isError) { | 185 if (!calledConstructor.isError) { |
| 200 registry.registerStaticUse( | 186 registry.registerStaticUse(new StaticUse.superConstructorInvoke( |
| 201 new StaticUse.superConstructorInvoke( | 187 calledConstructor, callStructure)); |
| 202 calledConstructor, callStructure)); | |
| 203 } | 188 } |
| 204 if (isConst) { | 189 if (isConst) { |
| 205 if (isValidAsConstant && | 190 if (isValidAsConstant && |
| 206 calledConstructor.isConst && | 191 calledConstructor.isConst && |
| 207 argumentsResult.isValidAsConstant) { | 192 argumentsResult.isValidAsConstant) { |
| 208 List<ConstantExpression> arguments = argumentsResult.constantArguments; | 193 List<ConstantExpression> arguments = argumentsResult.constantArguments; |
| 209 return new ConstantResult( | 194 return new ConstantResult( |
| 210 node, | 195 node, |
| 211 new ConstructedConstantExpression( | 196 new ConstructedConstantExpression( |
| 212 targetType, | 197 targetType, calledConstructor, callStructure, arguments), |
| 213 calledConstructor, | |
| 214 callStructure, | |
| 215 arguments), | |
| 216 element: calledConstructor); | 198 element: calledConstructor); |
| 217 } else { | 199 } else { |
| 218 isValidAsConstant = false; | 200 isValidAsConstant = false; |
| 219 } | 201 } |
| 220 } | 202 } |
| 221 return new ResolutionResult.forElement(calledConstructor); | 203 return new ResolutionResult.forElement(calledConstructor); |
| 222 } | 204 } |
| 223 | 205 |
| 224 ConstructedConstantExpression resolveImplicitSuperConstructorSend() { | 206 ConstructedConstantExpression resolveImplicitSuperConstructorSend() { |
| 225 // If the class has a super resolve the implicit super call. | 207 // If the class has a super resolve the implicit super call. |
| 226 ClassElement classElement = constructor.enclosingClass; | 208 ClassElement classElement = constructor.enclosingClass; |
| 227 ClassElement superClass = classElement.superclass; | 209 ClassElement superClass = classElement.superclass; |
| 228 if (!classElement.isObject) { | 210 if (!classElement.isObject) { |
| 229 assert(superClass != null); | 211 assert(superClass != null); |
| 230 assert(superClass.isResolved); | 212 assert(superClass.isResolved); |
| 231 | 213 |
| 232 InterfaceType targetType = | 214 InterfaceType targetType = |
| 233 getSuperOrThisLookupTarget(functionNode, isSuperCall: true); | 215 getSuperOrThisLookupTarget(functionNode, isSuperCall: true); |
| 234 ClassElement lookupTarget = targetType.element; | 216 ClassElement lookupTarget = targetType.element; |
| 235 ConstructorElement calledConstructor = | 217 ConstructorElement calledConstructor = |
| 236 findConstructor(constructor.library, lookupTarget, ''); | 218 findConstructor(constructor.library, lookupTarget, ''); |
| 237 | 219 |
| 238 final String className = lookupTarget.name; | 220 final String className = lookupTarget.name; |
| 239 CallStructure callStructure = CallStructure.NO_ARGS; | 221 CallStructure callStructure = CallStructure.NO_ARGS; |
| 240 ConstructorElement result = verifyThatConstructorMatchesCall( | 222 ConstructorElement result = verifyThatConstructorMatchesCall( |
| 241 functionNode, | 223 functionNode, calledConstructor, callStructure, className, |
| 242 calledConstructor, | |
| 243 callStructure, | |
| 244 className, | |
| 245 isImplicitSuperCall: true); | 224 isImplicitSuperCall: true); |
| 246 if (!result.isError) { | 225 if (!result.isError) { |
| 247 registry.registerStaticUse( | 226 registry.registerStaticUse( |
| 248 new StaticUse.constructorInvoke(calledConstructor, callStructure)); | 227 new StaticUse.constructorInvoke(calledConstructor, callStructure)); |
| 249 } | 228 } |
| 250 | 229 |
| 251 if (isConst && isValidAsConstant) { | 230 if (isConst && isValidAsConstant) { |
| 252 return new ConstructedConstantExpression( | 231 return new ConstructedConstantExpression(targetType, result, |
| 253 targetType, | 232 CallStructure.NO_ARGS, const <ConstantExpression>[]); |
| 254 result, | |
| 255 CallStructure.NO_ARGS, | |
| 256 const <ConstantExpression>[]); | |
| 257 } | 233 } |
| 258 } | 234 } |
| 259 return null; | 235 return null; |
| 260 } | 236 } |
| 261 | 237 |
| 262 ConstructorElement reportAndCreateErroneousConstructor( | 238 ConstructorElement reportAndCreateErroneousConstructor( |
| 263 Spannable diagnosticNode, | 239 Spannable diagnosticNode, String name, MessageKind kind, Map arguments) { |
| 264 String name, | |
| 265 MessageKind kind, | |
| 266 Map arguments) { | |
| 267 isValidAsConstant = false; | 240 isValidAsConstant = false; |
| 268 reporter.reportErrorMessage( | 241 reporter.reportErrorMessage(diagnosticNode, kind, arguments); |
| 269 diagnosticNode, kind, arguments); | |
| 270 return new ErroneousConstructorElementX( | 242 return new ErroneousConstructorElementX( |
| 271 kind, arguments, name, visitor.currentClass); | 243 kind, arguments, name, visitor.currentClass); |
| 272 } | 244 } |
| 273 | 245 |
| 274 /// Checks that [lookedupConstructor] is valid as a target for the super/this | 246 /// Checks that [lookedupConstructor] is valid as a target for the super/this |
| 275 /// constructor call using with the given [callStructure]. | 247 /// constructor call using with the given [callStructure]. |
| 276 /// | 248 /// |
| 277 /// If [lookedupConstructor] is valid it is returned, otherwise an error is | 249 /// If [lookedupConstructor] is valid it is returned, otherwise an error is |
| 278 /// reported and an [ErroneousConstructorElement] is returned. | 250 /// reported and an [ErroneousConstructorElement] is returned. |
| 279 ConstructorElement verifyThatConstructorMatchesCall( | 251 ConstructorElement verifyThatConstructorMatchesCall( |
| 280 Node node, | 252 Node node, |
| 281 ConstructorElementX lookedupConstructor, | 253 ConstructorElementX lookedupConstructor, |
| 282 CallStructure callStructure, | 254 CallStructure callStructure, |
| 283 String className, | 255 String className, |
| 284 {String constructorName: '', | 256 {String constructorName: '', |
| 285 bool isImplicitSuperCall: false, | 257 bool isImplicitSuperCall: false, |
| 286 bool isThisCall: false}) { | 258 bool isThisCall: false}) { |
| 287 Element result = lookedupConstructor; | 259 Element result = lookedupConstructor; |
| 288 if (lookedupConstructor == null) { | 260 if (lookedupConstructor == null) { |
| 289 String fullConstructorName = | 261 String fullConstructorName = |
| 290 Elements.constructorNameForDiagnostics(className, constructorName); | 262 Elements.constructorNameForDiagnostics(className, constructorName); |
| 291 MessageKind kind = isImplicitSuperCall | 263 MessageKind kind = isImplicitSuperCall |
| 292 ? MessageKind.CANNOT_RESOLVE_CONSTRUCTOR_FOR_IMPLICIT | 264 ? MessageKind.CANNOT_RESOLVE_CONSTRUCTOR_FOR_IMPLICIT |
| 293 : MessageKind.CANNOT_RESOLVE_CONSTRUCTOR; | 265 : MessageKind.CANNOT_RESOLVE_CONSTRUCTOR; |
| 294 result = reportAndCreateErroneousConstructor( | 266 result = reportAndCreateErroneousConstructor(node, constructorName, kind, |
| 295 node, constructorName, | 267 {'constructorName': fullConstructorName}); |
| 296 kind, {'constructorName': fullConstructorName}); | |
| 297 } else if (!lookedupConstructor.isGenerativeConstructor) { | 268 } else if (!lookedupConstructor.isGenerativeConstructor) { |
| 298 MessageKind kind = isThisCall | 269 MessageKind kind = isThisCall |
| 299 ? MessageKind.THIS_CALL_TO_FACTORY | 270 ? MessageKind.THIS_CALL_TO_FACTORY |
| 300 : MessageKind.SUPER_CALL_TO_FACTORY; | 271 : MessageKind.SUPER_CALL_TO_FACTORY; |
| 301 result = reportAndCreateErroneousConstructor( | 272 result = |
| 302 node, constructorName, kind, {}); | 273 reportAndCreateErroneousConstructor(node, constructorName, kind, {}); |
| 303 } else { | 274 } else { |
| 304 lookedupConstructor.computeType(visitor.resolution); | 275 lookedupConstructor.computeType(visitor.resolution); |
| 305 if (!callStructure.signatureApplies( | 276 if (!callStructure |
| 306 lookedupConstructor.functionSignature)) { | 277 .signatureApplies(lookedupConstructor.functionSignature)) { |
| 307 MessageKind kind = isImplicitSuperCall | 278 MessageKind kind = isImplicitSuperCall |
| 308 ? MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT | 279 ? MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT |
| 309 : MessageKind.NO_MATCHING_CONSTRUCTOR; | 280 : MessageKind.NO_MATCHING_CONSTRUCTOR; |
| 310 result = reportAndCreateErroneousConstructor( | 281 result = reportAndCreateErroneousConstructor( |
| 311 node, constructorName, kind, {}); | 282 node, constructorName, kind, {}); |
| 312 } else if (constructor.isConst && !lookedupConstructor.isConst) { | 283 } else if (constructor.isConst && !lookedupConstructor.isConst) { |
| 313 MessageKind kind = isImplicitSuperCall | 284 MessageKind kind = isImplicitSuperCall |
| 314 ? MessageKind.CONST_CALLS_NON_CONST_FOR_IMPLICIT | 285 ? MessageKind.CONST_CALLS_NON_CONST_FOR_IMPLICIT |
| 315 : MessageKind.CONST_CALLS_NON_CONST; | 286 : MessageKind.CONST_CALLS_NON_CONST; |
| 316 result = reportAndCreateErroneousConstructor( | 287 result = reportAndCreateErroneousConstructor( |
| 317 node, constructorName, kind, {}); | 288 node, constructorName, kind, {}); |
| 318 } | 289 } |
| 319 } | 290 } |
| 320 return result; | 291 return result; |
| 321 } | 292 } |
| 322 | 293 |
| 323 /** | 294 /** |
| 324 * Resolve all initializers of this constructor. In the case of a redirecting | 295 * Resolve all initializers of this constructor. In the case of a redirecting |
| 325 * constructor, the resolved constructor's function element is returned. | 296 * constructor, the resolved constructor's function element is returned. |
| 326 */ | 297 */ |
| 327 ConstructorElement resolveInitializers() { | 298 ConstructorElement resolveInitializers() { |
| 328 Map<dynamic/*String|int*/, ConstantExpression> defaultValues = | 299 Map<dynamic /*String|int*/, ConstantExpression> defaultValues = |
| 329 <dynamic/*String|int*/, ConstantExpression>{}; | 300 <dynamic /*String|int*/, ConstantExpression>{}; |
| 330 ConstructedConstantExpression constructorInvocation; | 301 ConstructedConstantExpression constructorInvocation; |
| 331 // Keep track of all "this.param" parameters specified for constructor so | 302 // Keep track of all "this.param" parameters specified for constructor so |
| 332 // that we can ensure that fields are initialized only once. | 303 // that we can ensure that fields are initialized only once. |
| 333 FunctionSignature functionParameters = constructor.functionSignature; | 304 FunctionSignature functionParameters = constructor.functionSignature; |
| 334 functionParameters.forEachParameter((ParameterElementX element) { | 305 functionParameters.forEachParameter((ParameterElementX element) { |
| 335 if (isConst) { | 306 if (isConst) { |
| 336 if (element.isOptional) { | 307 if (element.isOptional) { |
| 337 if (element.constantCache == null) { | 308 if (element.constantCache == null) { |
| 338 // TODO(johnniwinther): Remove this when all constant expressions | 309 // TODO(johnniwinther): Remove this when all constant expressions |
| 339 // can be computed during resolution. | 310 // can be computed during resolution. |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 430 ResolutionResult result = resolveSuperOrThisForSend(call); | 401 ResolutionResult result = resolveSuperOrThisForSend(call); |
| 431 if (isConst) { | 402 if (isConst) { |
| 432 if (result.isConstant) { | 403 if (result.isConstant) { |
| 433 constructorInvocation = result.constant; | 404 constructorInvocation = result.constant; |
| 434 } else { | 405 } else { |
| 435 isValidAsConstant = false; | 406 isValidAsConstant = false; |
| 436 } | 407 } |
| 437 if (isConst && isValidAsConstant) { | 408 if (isConst && isValidAsConstant) { |
| 438 constructor.constantConstructor = | 409 constructor.constantConstructor = |
| 439 new RedirectingGenerativeConstantConstructor( | 410 new RedirectingGenerativeConstantConstructor( |
| 440 defaultValues, | 411 defaultValues, constructorInvocation); |
| 441 constructorInvocation); | |
| 442 } | 412 } |
| 443 } | 413 } |
| 444 return result.element; | 414 return result.element; |
| 445 } else { | 415 } else { |
| 446 reporter.reportErrorMessage( | 416 reporter.reportErrorMessage( |
| 447 call, MessageKind.CONSTRUCTOR_CALL_EXPECTED); | 417 call, MessageKind.CONSTRUCTOR_CALL_EXPECTED); |
| 448 return null; | 418 return null; |
| 449 } | 419 } |
| 450 } else { | 420 } else { |
| 451 reporter.reportErrorMessage( | 421 reporter.reportErrorMessage(link.head, MessageKind.INVALID_INITIALIZER); |
| 452 link.head, MessageKind.INVALID_INITIALIZER); | |
| 453 } | 422 } |
| 454 } | 423 } |
| 455 if (!resolvedSuper) { | 424 if (!resolvedSuper) { |
| 456 constructorInvocation = resolveImplicitSuperConstructorSend(); | 425 constructorInvocation = resolveImplicitSuperConstructorSend(); |
| 457 } | 426 } |
| 458 if (isConst && isValidAsConstant) { | 427 if (isConst && isValidAsConstant) { |
| 459 constructor.constantConstructor = new GenerativeConstantConstructor( | 428 constructor.constantConstructor = new GenerativeConstantConstructor( |
| 460 constructor.enclosingClass.thisType, | 429 constructor.enclosingClass.thisType, |
| 461 defaultValues, | 430 defaultValues, |
| 462 fieldInitializers, | 431 fieldInitializers, |
| 463 constructorInvocation); | 432 constructorInvocation); |
| 464 } | 433 } |
| 465 return null; // If there was no redirection always return null. | 434 return null; // If there was no redirection always return null. |
| 466 } | 435 } |
| 467 } | 436 } |
| 468 | 437 |
| 469 class ConstructorResolver extends CommonResolverVisitor<ConstructorResult> { | 438 class ConstructorResolver extends CommonResolverVisitor<ConstructorResult> { |
| 470 final ResolverVisitor resolver; | 439 final ResolverVisitor resolver; |
| 471 final bool inConstContext; | 440 final bool inConstContext; |
| 472 | 441 |
| 473 ConstructorResolver(Compiler compiler, this.resolver, | 442 ConstructorResolver(Compiler compiler, this.resolver, |
| 474 {bool this.inConstContext: false}) | 443 {bool this.inConstContext: false}) |
| 475 : super(compiler); | 444 : super(compiler); |
| 476 | 445 |
| 477 ResolutionRegistry get registry => resolver.registry; | 446 ResolutionRegistry get registry => resolver.registry; |
| 478 | 447 |
| 479 visitNode(Node node) { | 448 visitNode(Node node) { |
| 480 throw 'not supported'; | 449 throw 'not supported'; |
| 481 } | 450 } |
| 482 | 451 |
| 483 ConstructorResult reportAndCreateErroneousConstructorElement( | 452 ConstructorResult reportAndCreateErroneousConstructorElement( |
| 484 Spannable diagnosticNode, | 453 Spannable diagnosticNode, |
| 485 ConstructorResultKind resultKind, | 454 ConstructorResultKind resultKind, |
| 486 DartType type, | 455 DartType type, |
| 487 Element enclosing, | 456 Element enclosing, |
| 488 String name, | 457 String name, |
| 489 MessageKind kind, | 458 MessageKind kind, |
| 490 Map arguments, | 459 Map arguments, |
| 491 {bool isError: false, | 460 {bool isError: false, |
| 492 bool missingConstructor: false, | 461 bool missingConstructor: false, |
| 493 List<DiagnosticMessage> infos: const <DiagnosticMessage>[]}) { | 462 List<DiagnosticMessage> infos: const <DiagnosticMessage>[]}) { |
| 494 if (missingConstructor) { | 463 if (missingConstructor) { |
| 495 registry.registerFeature(Feature.THROW_NO_SUCH_METHOD); | 464 registry.registerFeature(Feature.THROW_NO_SUCH_METHOD); |
| 496 } else { | 465 } else { |
| 497 registry.registerFeature(Feature.THROW_RUNTIME_ERROR); | 466 registry.registerFeature(Feature.THROW_RUNTIME_ERROR); |
| 498 } | 467 } |
| 499 DiagnosticMessage message = | 468 DiagnosticMessage message = |
| 500 reporter.createMessage(diagnosticNode, kind, arguments); | 469 reporter.createMessage(diagnosticNode, kind, arguments); |
| 501 if (isError || inConstContext) { | 470 if (isError || inConstContext) { |
| 502 reporter.reportError(message, infos); | 471 reporter.reportError(message, infos); |
| 503 } else { | 472 } else { |
| 504 reporter.reportWarning(message, infos); | 473 reporter.reportWarning(message, infos); |
| 505 } | 474 } |
| 506 ErroneousElement error = new ErroneousConstructorElementX( | 475 ErroneousElement error = |
| 507 kind, arguments, name, enclosing); | 476 new ErroneousConstructorElementX(kind, arguments, name, enclosing); |
| 508 if (type == null) { | 477 if (type == null) { |
| 509 type = new MalformedType(error, null); | 478 type = new MalformedType(error, null); |
| 510 } | 479 } |
| 511 return new ConstructorResult.forError(resultKind, error, type); | 480 return new ConstructorResult.forError(resultKind, error, type); |
| 512 } | 481 } |
| 513 | 482 |
| 514 ConstructorResult resolveConstructor( | 483 ConstructorResult resolveConstructor(PrefixElement prefix, InterfaceType type, |
| 515 PrefixElement prefix, | 484 Node diagnosticNode, String constructorName) { |
| 516 InterfaceType type, | |
| 517 Node diagnosticNode, | |
| 518 String constructorName) { | |
| 519 ClassElement cls = type.element; | 485 ClassElement cls = type.element; |
| 520 cls.ensureResolved(resolution); | 486 cls.ensureResolved(resolution); |
| 521 ConstructorElement constructor = findConstructor( | 487 ConstructorElement constructor = findConstructor( |
| 522 resolver.enclosingElement.library, cls, constructorName); | 488 resolver.enclosingElement.library, cls, constructorName); |
| 523 if (constructor == null) { | 489 if (constructor == null) { |
| 524 MessageKind kind = constructorName.isEmpty | 490 MessageKind kind = constructorName.isEmpty |
| 525 ? MessageKind.CANNOT_FIND_UNNAMED_CONSTRUCTOR | 491 ? MessageKind.CANNOT_FIND_UNNAMED_CONSTRUCTOR |
| 526 : MessageKind.CANNOT_FIND_CONSTRUCTOR; | 492 : MessageKind.CANNOT_FIND_CONSTRUCTOR; |
| 527 return reportAndCreateErroneousConstructorElement( | 493 return reportAndCreateErroneousConstructorElement( |
| 528 diagnosticNode, | 494 diagnosticNode, |
| 529 ConstructorResultKind.UNRESOLVED_CONSTRUCTOR, type, | 495 ConstructorResultKind.UNRESOLVED_CONSTRUCTOR, |
| 530 cls, constructorName, kind, | 496 type, |
| 497 cls, |
| 498 constructorName, |
| 499 kind, |
| 531 {'className': cls.name, 'constructorName': constructorName}, | 500 {'className': cls.name, 'constructorName': constructorName}, |
| 532 missingConstructor: true); | 501 missingConstructor: true); |
| 533 } else if (inConstContext && !constructor.isConst) { | 502 } else if (inConstContext && !constructor.isConst) { |
| 534 reporter.reportErrorMessage( | 503 reporter.reportErrorMessage( |
| 535 diagnosticNode, MessageKind.CONSTRUCTOR_IS_NOT_CONST); | 504 diagnosticNode, MessageKind.CONSTRUCTOR_IS_NOT_CONST); |
| 536 return new ConstructorResult( | 505 return new ConstructorResult( |
| 537 ConstructorResultKind.NON_CONSTANT, prefix, constructor, type); | 506 ConstructorResultKind.NON_CONSTANT, prefix, constructor, type); |
| 538 } else { | 507 } else { |
| 539 if (cls.isEnumClass && resolver.currentClass != cls) { | 508 if (cls.isEnumClass && resolver.currentClass != cls) { |
| 540 return reportAndCreateErroneousConstructorElement( | 509 return reportAndCreateErroneousConstructorElement( |
| 541 diagnosticNode, | 510 diagnosticNode, |
| 542 ConstructorResultKind.INVALID_TYPE, type, | 511 ConstructorResultKind.INVALID_TYPE, |
| 543 cls, constructorName, | 512 type, |
| 513 cls, |
| 514 constructorName, |
| 544 MessageKind.CANNOT_INSTANTIATE_ENUM, | 515 MessageKind.CANNOT_INSTANTIATE_ENUM, |
| 545 {'enumName': cls.name}, | 516 {'enumName': cls.name}, |
| 546 isError: true); | 517 isError: true); |
| 547 } | 518 } |
| 548 if (constructor.isGenerativeConstructor) { | 519 if (constructor.isGenerativeConstructor) { |
| 549 if (cls.isAbstract) { | 520 if (cls.isAbstract) { |
| 550 reporter.reportWarningMessage( | 521 reporter.reportWarningMessage( |
| 551 diagnosticNode, MessageKind.ABSTRACT_CLASS_INSTANTIATION); | 522 diagnosticNode, MessageKind.ABSTRACT_CLASS_INSTANTIATION); |
| 552 registry.registerFeature(Feature.ABSTRACT_CLASS_INSTANTIATION); | 523 registry.registerFeature(Feature.ABSTRACT_CLASS_INSTANTIATION); |
| 553 return new ConstructorResult( | 524 return new ConstructorResult( |
| (...skipping 15 matching lines...) Expand all Loading... |
| 569 Node selector = node.send.selector; | 540 Node selector = node.send.selector; |
| 570 ConstructorResult result = visit(selector); | 541 ConstructorResult result = visit(selector); |
| 571 assert(invariant(selector, result != null, | 542 assert(invariant(selector, result != null, |
| 572 message: 'No result returned for $selector.')); | 543 message: 'No result returned for $selector.')); |
| 573 return finishConstructorReference(result, node.send.selector, node); | 544 return finishConstructorReference(result, node.send.selector, node); |
| 574 } | 545 } |
| 575 | 546 |
| 576 /// Finishes resolution of a constructor reference and records the | 547 /// Finishes resolution of a constructor reference and records the |
| 577 /// type of the constructed instance on [expression]. | 548 /// type of the constructed instance on [expression]. |
| 578 ConstructorResult finishConstructorReference( | 549 ConstructorResult finishConstructorReference( |
| 579 ConstructorResult result, | 550 ConstructorResult result, Node diagnosticNode, Node expression) { |
| 580 Node diagnosticNode, | |
| 581 Node expression) { | |
| 582 assert(invariant(diagnosticNode, result != null, | 551 assert(invariant(diagnosticNode, result != null, |
| 583 message: 'No result returned for $diagnosticNode.')); | 552 message: 'No result returned for $diagnosticNode.')); |
| 584 | 553 |
| 585 if (result.kind != null) { | 554 if (result.kind != null) { |
| 586 resolver.registry.setType(expression, result.type); | 555 resolver.registry.setType(expression, result.type); |
| 587 return result; | 556 return result; |
| 588 } | 557 } |
| 589 | 558 |
| 590 // Find the unnamed constructor if the reference resolved to a | 559 // Find the unnamed constructor if the reference resolved to a |
| 591 // class. | 560 // class. |
| 592 if (result.type != null) { | 561 if (result.type != null) { |
| 593 // The unnamed constructor may not exist, so [e] may become unresolved. | 562 // The unnamed constructor may not exist, so [e] may become unresolved. |
| 594 result = resolveConstructor( | 563 result = |
| 595 result.prefix, result.type, diagnosticNode, ''); | 564 resolveConstructor(result.prefix, result.type, diagnosticNode, ''); |
| 596 } else { | 565 } else { |
| 597 Element element = result.element; | 566 Element element = result.element; |
| 598 if (element.isMalformed) { | 567 if (element.isMalformed) { |
| 599 result = constructorResultForErroneous(diagnosticNode, element); | 568 result = constructorResultForErroneous(diagnosticNode, element); |
| 600 } else { | 569 } else { |
| 601 result = reportAndCreateErroneousConstructorElement( | 570 result = reportAndCreateErroneousConstructorElement( |
| 602 diagnosticNode, | 571 diagnosticNode, |
| 603 ConstructorResultKind.INVALID_TYPE, null, | 572 ConstructorResultKind.INVALID_TYPE, |
| 604 element, element.name, | 573 null, |
| 605 MessageKind.NOT_A_TYPE, {'node': diagnosticNode}); | 574 element, |
| 575 element.name, |
| 576 MessageKind.NOT_A_TYPE, |
| 577 {'node': diagnosticNode}); |
| 606 } | 578 } |
| 607 } | 579 } |
| 608 resolver.registry.setType(expression, result.type); | 580 resolver.registry.setType(expression, result.type); |
| 609 return result; | 581 return result; |
| 610 } | 582 } |
| 611 | 583 |
| 612 ConstructorResult visitTypeAnnotation(TypeAnnotation node) { | 584 ConstructorResult visitTypeAnnotation(TypeAnnotation node) { |
| 613 // This is not really resolving a type-annotation, but the name of the | 585 // This is not really resolving a type-annotation, but the name of the |
| 614 // constructor. Therefore we allow deferred types. | 586 // constructor. Therefore we allow deferred types. |
| 615 DartType type = resolver.resolveTypeAnnotation( | 587 DartType type = resolver.resolveTypeAnnotation(node, |
| 616 node, | 588 malformedIsError: inConstContext, deferredIsMalformed: false); |
| 617 malformedIsError: inConstContext, | |
| 618 deferredIsMalformed: false); | |
| 619 Send send = node.typeName.asSend(); | 589 Send send = node.typeName.asSend(); |
| 620 PrefixElement prefix; | 590 PrefixElement prefix; |
| 621 if (send != null) { | 591 if (send != null) { |
| 622 // The type name is of the form [: prefix . identifier :]. | 592 // The type name is of the form [: prefix . identifier :]. |
| 623 String name = send.receiver.asIdentifier().source; | 593 String name = send.receiver.asIdentifier().source; |
| 624 Element element = lookupInScope(reporter, send, resolver.scope, name); | 594 Element element = lookupInScope(reporter, send, resolver.scope, name); |
| 625 if (element != null && element.isPrefix) { | 595 if (element != null && element.isPrefix) { |
| 626 prefix = element; | 596 prefix = element; |
| 627 } | 597 } |
| 628 } | 598 } |
| (...skipping 17 matching lines...) Expand all Loading... |
| 646 } | 616 } |
| 647 | 617 |
| 648 if (receiver.type != null) { | 618 if (receiver.type != null) { |
| 649 if (receiver.type.isInterfaceType) { | 619 if (receiver.type.isInterfaceType) { |
| 650 return resolveConstructor( | 620 return resolveConstructor( |
| 651 receiver.prefix, receiver.type, name, name.source); | 621 receiver.prefix, receiver.type, name, name.source); |
| 652 } else { | 622 } else { |
| 653 // TODO(johnniwinther): Update the message for the different types. | 623 // TODO(johnniwinther): Update the message for the different types. |
| 654 return reportAndCreateErroneousConstructorElement( | 624 return reportAndCreateErroneousConstructorElement( |
| 655 name, | 625 name, |
| 656 ConstructorResultKind.INVALID_TYPE, null, | 626 ConstructorResultKind.INVALID_TYPE, |
| 657 resolver.enclosingElement, name.source, | 627 null, |
| 658 MessageKind.NOT_A_TYPE, {'node': name}); | 628 resolver.enclosingElement, |
| 629 name.source, |
| 630 MessageKind.NOT_A_TYPE, |
| 631 {'node': name}); |
| 659 } | 632 } |
| 660 } else if (receiver.element.isPrefix) { | 633 } else if (receiver.element.isPrefix) { |
| 661 PrefixElement prefix = receiver.element; | 634 PrefixElement prefix = receiver.element; |
| 662 Element member = prefix.lookupLocalMember(name.source); | 635 Element member = prefix.lookupLocalMember(name.source); |
| 663 return constructorResultForElement( | 636 return constructorResultForElement(node, name.source, member, |
| 664 node, name.source, member, prefix: prefix); | 637 prefix: prefix); |
| 665 } else { | 638 } else { |
| 666 return reporter.internalError( | 639 return reporter.internalError( |
| 667 node.receiver, 'unexpected receiver $receiver'); | 640 node.receiver, 'unexpected receiver $receiver'); |
| 668 } | 641 } |
| 669 } | 642 } |
| 670 | 643 |
| 671 ConstructorResult visitIdentifier(Identifier node) { | 644 ConstructorResult visitIdentifier(Identifier node) { |
| 672 String name = node.source; | 645 String name = node.source; |
| 673 Element element = lookupInScope(reporter, node, resolver.scope, name); | 646 Element element = lookupInScope(reporter, node, resolver.scope, name); |
| 674 registry.useElement(node, element); | 647 registry.useElement(node, element); |
| 675 return constructorResultForElement(node, name, element); | 648 return constructorResultForElement(node, name, element); |
| 676 } | 649 } |
| 677 | 650 |
| 678 /// Assumed to be called by [resolveRedirectingFactory]. | 651 /// Assumed to be called by [resolveRedirectingFactory]. |
| 679 ConstructorResult visitRedirectingFactoryBody(RedirectingFactoryBody node) { | 652 ConstructorResult visitRedirectingFactoryBody(RedirectingFactoryBody node) { |
| 680 Node constructorReference = node.constructorReference; | 653 Node constructorReference = node.constructorReference; |
| 681 return finishConstructorReference(visit(constructorReference), | 654 return finishConstructorReference( |
| 682 constructorReference, node); | 655 visit(constructorReference), constructorReference, node); |
| 683 } | 656 } |
| 684 | 657 |
| 685 ConstructorResult constructorResultForElement( | 658 ConstructorResult constructorResultForElement( |
| 686 Node node, String name, Element element, | 659 Node node, String name, Element element, |
| 687 {PrefixElement prefix}) { | 660 {PrefixElement prefix}) { |
| 688 element = Elements.unwrap(element, reporter, node); | 661 element = Elements.unwrap(element, reporter, node); |
| 689 if (element == null) { | 662 if (element == null) { |
| 690 return reportAndCreateErroneousConstructorElement( | 663 return reportAndCreateErroneousConstructorElement( |
| 691 node, | 664 node, |
| 692 ConstructorResultKind.INVALID_TYPE, null, | 665 ConstructorResultKind.INVALID_TYPE, |
| 693 resolver.enclosingElement, name, | 666 null, |
| 667 resolver.enclosingElement, |
| 668 name, |
| 694 MessageKind.CANNOT_RESOLVE, | 669 MessageKind.CANNOT_RESOLVE, |
| 695 {'name': name}); | 670 {'name': name}); |
| 696 } else if (element.isAmbiguous) { | 671 } else if (element.isAmbiguous) { |
| 697 AmbiguousElement ambiguous = element; | 672 AmbiguousElement ambiguous = element; |
| 698 return reportAndCreateErroneousConstructorElement( | 673 return reportAndCreateErroneousConstructorElement( |
| 699 node, | 674 node, |
| 700 ConstructorResultKind.INVALID_TYPE, null, | 675 ConstructorResultKind.INVALID_TYPE, |
| 701 resolver.enclosingElement, name, | 676 null, |
| 677 resolver.enclosingElement, |
| 678 name, |
| 702 ambiguous.messageKind, | 679 ambiguous.messageKind, |
| 703 ambiguous.messageArguments, | 680 ambiguous.messageArguments, |
| 704 infos: ambiguous.computeInfos(resolver.enclosingElement, reporter)); | 681 infos: ambiguous.computeInfos(resolver.enclosingElement, reporter)); |
| 705 } else if (element.isMalformed) { | 682 } else if (element.isMalformed) { |
| 706 return constructorResultForErroneous(node, element); | 683 return constructorResultForErroneous(node, element); |
| 707 } else if (element.isClass) { | 684 } else if (element.isClass) { |
| 708 ClassElement cls = element; | 685 ClassElement cls = element; |
| 709 cls.computeType(resolution); | 686 cls.computeType(resolution); |
| 710 return constructorResultForType(node, cls.rawType, prefix: prefix); | 687 return constructorResultForType(node, cls.rawType, prefix: prefix); |
| 711 } else if (element.isPrefix) { | 688 } else if (element.isPrefix) { |
| 712 return new ConstructorResult.forPrefix(element); | 689 return new ConstructorResult.forPrefix(element); |
| 713 } else if (element.isTypedef) { | 690 } else if (element.isTypedef) { |
| 714 TypedefElement typdef = element; | 691 TypedefElement typdef = element; |
| 715 typdef.ensureResolved(resolution); | 692 typdef.ensureResolved(resolution); |
| 716 return constructorResultForType(node, typdef.rawType); | 693 return constructorResultForType(node, typdef.rawType); |
| 717 } else if (element.isTypeVariable) { | 694 } else if (element.isTypeVariable) { |
| 718 TypeVariableElement typeVariableElement = element; | 695 TypeVariableElement typeVariableElement = element; |
| 719 return constructorResultForType(node, typeVariableElement.type); | 696 return constructorResultForType(node, typeVariableElement.type); |
| 720 } else { | 697 } else { |
| 721 return reportAndCreateErroneousConstructorElement( | 698 return reportAndCreateErroneousConstructorElement( |
| 722 node, | 699 node, |
| 723 ConstructorResultKind.INVALID_TYPE, null, | 700 ConstructorResultKind.INVALID_TYPE, |
| 724 resolver.enclosingElement, name, | 701 null, |
| 725 MessageKind.NOT_A_TYPE, {'node': name}); | 702 resolver.enclosingElement, |
| 703 name, |
| 704 MessageKind.NOT_A_TYPE, |
| 705 {'node': name}); |
| 726 } | 706 } |
| 727 } | 707 } |
| 728 | 708 |
| 729 ConstructorResult constructorResultForErroneous( | 709 ConstructorResult constructorResultForErroneous(Node node, Element error) { |
| 730 Node node, Element error) { | |
| 731 if (error is! ErroneousElementX) { | 710 if (error is! ErroneousElementX) { |
| 732 // Parser error. The error has already been reported. | 711 // Parser error. The error has already been reported. |
| 733 error = new ErroneousConstructorElementX( | 712 error = new ErroneousConstructorElementX( |
| 734 MessageKind.NOT_A_TYPE, {'node': node}, | 713 MessageKind.NOT_A_TYPE, {'node': node}, error.name, error); |
| 735 error.name, error); | |
| 736 registry.registerFeature(Feature.THROW_RUNTIME_ERROR); | 714 registry.registerFeature(Feature.THROW_RUNTIME_ERROR); |
| 737 } | 715 } |
| 738 return new ConstructorResult.forError( | 716 return new ConstructorResult.forError(ConstructorResultKind.INVALID_TYPE, |
| 739 ConstructorResultKind.INVALID_TYPE, | 717 error, new MalformedType(error, null)); |
| 740 error, | |
| 741 new MalformedType(error, null)); | |
| 742 } | 718 } |
| 743 | 719 |
| 744 ConstructorResult constructorResultForType( | 720 ConstructorResult constructorResultForType(Node node, DartType type, |
| 745 Node node, | |
| 746 DartType type, | |
| 747 {PrefixElement prefix}) { | 721 {PrefixElement prefix}) { |
| 748 String name = type.name; | 722 String name = type.name; |
| 749 if (type.isMalformed) { | 723 if (type.isMalformed) { |
| 750 return new ConstructorResult.forError( | 724 return new ConstructorResult.forError( |
| 751 ConstructorResultKind.INVALID_TYPE, type.element, type); | 725 ConstructorResultKind.INVALID_TYPE, type.element, type); |
| 752 } else if (type.isInterfaceType) { | 726 } else if (type.isInterfaceType) { |
| 753 return new ConstructorResult.forType(prefix, type); | 727 return new ConstructorResult.forType(prefix, type); |
| 754 } else if (type.isTypedef) { | 728 } else if (type.isTypedef) { |
| 755 return reportAndCreateErroneousConstructorElement( | 729 return reportAndCreateErroneousConstructorElement( |
| 756 node, | 730 node, |
| 757 ConstructorResultKind.INVALID_TYPE, type, | 731 ConstructorResultKind.INVALID_TYPE, |
| 758 resolver.enclosingElement, name, | 732 type, |
| 759 MessageKind.CANNOT_INSTANTIATE_TYPEDEF, {'typedefName': name}); | 733 resolver.enclosingElement, |
| 734 name, |
| 735 MessageKind.CANNOT_INSTANTIATE_TYPEDEF, |
| 736 {'typedefName': name}); |
| 760 } else if (type.isTypeVariable) { | 737 } else if (type.isTypeVariable) { |
| 761 return reportAndCreateErroneousConstructorElement( | 738 return reportAndCreateErroneousConstructorElement( |
| 762 node, | 739 node, |
| 763 ConstructorResultKind.INVALID_TYPE, type, | 740 ConstructorResultKind.INVALID_TYPE, |
| 764 resolver.enclosingElement, name, | 741 type, |
| 742 resolver.enclosingElement, |
| 743 name, |
| 765 MessageKind.CANNOT_INSTANTIATE_TYPE_VARIABLE, | 744 MessageKind.CANNOT_INSTANTIATE_TYPE_VARIABLE, |
| 766 {'typeVariableName': name}); | 745 {'typeVariableName': name}); |
| 767 } | 746 } |
| 768 return reporter.internalError(node, "Unexpected constructor type $type"); | 747 return reporter.internalError(node, "Unexpected constructor type $type"); |
| 769 } | 748 } |
| 770 | |
| 771 } | 749 } |
| 772 | 750 |
| 773 /// The kind of constructor found by the [ConstructorResolver]. | 751 /// The kind of constructor found by the [ConstructorResolver]. |
| 774 enum ConstructorResultKind { | 752 enum ConstructorResultKind { |
| 775 /// A generative or redirecting generative constructor. | 753 /// A generative or redirecting generative constructor. |
| 776 GENERATIVE, | 754 GENERATIVE, |
| 755 |
| 777 /// A factory or redirecting factory constructor. | 756 /// A factory or redirecting factory constructor. |
| 778 FACTORY, | 757 FACTORY, |
| 758 |
| 779 /// A generative or redirecting generative constructor on an abstract class. | 759 /// A generative or redirecting generative constructor on an abstract class. |
| 780 ABSTRACT, | 760 ABSTRACT, |
| 761 |
| 781 /// No constructor was found because the type was invalid, for instance | 762 /// No constructor was found because the type was invalid, for instance |
| 782 /// unresolved, an enum class, a type variable, a typedef or a non-type. | 763 /// unresolved, an enum class, a type variable, a typedef or a non-type. |
| 783 INVALID_TYPE, | 764 INVALID_TYPE, |
| 765 |
| 784 /// No constructor of the sought name was found on the class. | 766 /// No constructor of the sought name was found on the class. |
| 785 UNRESOLVED_CONSTRUCTOR, | 767 UNRESOLVED_CONSTRUCTOR, |
| 768 |
| 786 /// A non-constant constructor was found for a const constructor invocation. | 769 /// A non-constant constructor was found for a const constructor invocation. |
| 787 NON_CONSTANT, | 770 NON_CONSTANT, |
| 788 } | 771 } |
| 789 | 772 |
| 790 /// The (partial) result of the resolution of a new expression used in | 773 /// The (partial) result of the resolution of a new expression used in |
| 791 /// [ConstructorResolver]. | 774 /// [ConstructorResolver]. |
| 792 class ConstructorResult { | 775 class ConstructorResult { |
| 793 /// The prefix used to access the constructor. For instance `prefix` in `new | 776 /// The prefix used to access the constructor. For instance `prefix` in `new |
| 794 /// prefix.Class.constructorName()`. | 777 /// prefix.Class.constructorName()`. |
| 795 final PrefixElement prefix; | 778 final PrefixElement prefix; |
| 796 | 779 |
| 797 /// The kind of the found constructor. | 780 /// The kind of the found constructor. |
| 798 final ConstructorResultKind kind; | 781 final ConstructorResultKind kind; |
| 799 | 782 |
| 800 /// The currently found element. Since [ConstructorResult] is used for partial | 783 /// The currently found element. Since [ConstructorResult] is used for partial |
| 801 /// results, this might be a [PrefixElement], a [ClassElement], a | 784 /// results, this might be a [PrefixElement], a [ClassElement], a |
| 802 /// [ConstructorElement] or in the negative cases an [ErroneousElement]. | 785 /// [ConstructorElement] or in the negative cases an [ErroneousElement]. |
| 803 final Element element; | 786 final Element element; |
| 804 | 787 |
| 805 /// The type of the new expression. For instance `Foo<String>` in | 788 /// The type of the new expression. For instance `Foo<String>` in |
| 806 /// `new prefix.Foo<String>.constructorName()`. | 789 /// `new prefix.Foo<String>.constructorName()`. |
| 807 final DartType type; | 790 final DartType type; |
| 808 | 791 |
| 809 /// Creates a fully resolved constructor access where [element] is resolved | 792 /// Creates a fully resolved constructor access where [element] is resolved |
| 810 /// to a constructor and [type] to an interface type. | 793 /// to a constructor and [type] to an interface type. |
| 811 ConstructorResult(this.kind, | 794 ConstructorResult(this.kind, this.prefix, ConstructorElement this.element, |
| 812 this.prefix, | 795 InterfaceType this.type); |
| 813 ConstructorElement this.element, | |
| 814 InterfaceType this.type); | |
| 815 | 796 |
| 816 /// Creates a fully resolved constructor access where [element] is an | 797 /// Creates a fully resolved constructor access where [element] is an |
| 817 /// [ErroneousElement]. | 798 /// [ErroneousElement]. |
| 818 // TODO(johnniwinther): Do we still need the prefix for cases like | 799 // TODO(johnniwinther): Do we still need the prefix for cases like |
| 819 // `new deferred.Class.unresolvedConstructor()` ? | 800 // `new deferred.Class.unresolvedConstructor()` ? |
| 820 ConstructorResult.forError( | 801 ConstructorResult.forError( |
| 821 this.kind, ErroneousElement this.element, this.type) | 802 this.kind, ErroneousElement this.element, this.type) |
| 822 : prefix = null; | 803 : prefix = null; |
| 823 | 804 |
| 824 /// Creates a constructor access that is partially resolved to a prefix. For | 805 /// Creates a constructor access that is partially resolved to a prefix. For |
| (...skipping 30 matching lines...) Expand all Loading... |
| 855 sb.write('type=$type'); | 836 sb.write('type=$type'); |
| 856 } | 837 } |
| 857 sb.write(')'); | 838 sb.write(')'); |
| 858 return sb.toString(); | 839 return sb.toString(); |
| 859 } | 840 } |
| 860 } | 841 } |
| 861 | 842 |
| 862 /// Lookup the [constructorName] constructor in [cls] and normalize the result | 843 /// Lookup the [constructorName] constructor in [cls] and normalize the result |
| 863 /// with respect to privacy and patching. | 844 /// with respect to privacy and patching. |
| 864 ConstructorElement findConstructor( | 845 ConstructorElement findConstructor( |
| 865 LibraryElement currentLibrary, | 846 LibraryElement currentLibrary, ClassElement cls, String constructorName) { |
| 866 ClassElement cls, | |
| 867 String constructorName) { | |
| 868 if (Name.isPrivateName(constructorName) && | 847 if (Name.isPrivateName(constructorName) && |
| 869 currentLibrary.library != cls.library) { | 848 currentLibrary.library != cls.library) { |
| 870 // TODO(johnniwinther): Report a special error on unaccessible private | 849 // TODO(johnniwinther): Report a special error on unaccessible private |
| 871 // constructors. | 850 // constructors. |
| 872 return null; | 851 return null; |
| 873 } | 852 } |
| 874 // TODO(johnniwinther): Use [Name] for lookup. | 853 // TODO(johnniwinther): Use [Name] for lookup. |
| 875 ConstructorElement constructor = cls.lookupConstructor(constructorName); | 854 ConstructorElement constructor = cls.lookupConstructor(constructorName); |
| 876 if (constructor != null) { | 855 if (constructor != null) { |
| 877 constructor = constructor.declaration; | 856 constructor = constructor.declaration; |
| 878 } | 857 } |
| 879 return constructor; | 858 return constructor; |
| 880 } | 859 } |
| OLD | NEW |