| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library dart2js.typechecker; | 5 library dart2js.typechecker; |
| 6 | 6 |
| 7 import 'common/names.dart' show Identifiers; | 7 import 'common/names.dart' show Identifiers; |
| 8 import 'common/resolution.dart' show Resolution; | 8 import 'common/resolution.dart' show Resolution; |
| 9 import 'common/tasks.dart' show CompilerTask; | 9 import 'common/tasks.dart' show CompilerTask; |
| 10 import 'common.dart'; | 10 import 'common.dart'; |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 57 void check(AstElement element) { | 57 void check(AstElement element) { |
| 58 if (element.isClass) return; | 58 if (element.isClass) return; |
| 59 if (element.isTypedef) return; | 59 if (element.isTypedef) return; |
| 60 ResolvedAst resolvedAst = element.resolvedAst; | 60 ResolvedAst resolvedAst = element.resolvedAst; |
| 61 reporter.withCurrentElement(element.implementation, () { | 61 reporter.withCurrentElement(element.implementation, () { |
| 62 measure(() { | 62 measure(() { |
| 63 TypeCheckerVisitor visitor = new TypeCheckerVisitor( | 63 TypeCheckerVisitor visitor = new TypeCheckerVisitor( |
| 64 compiler, resolvedAst.elements, compiler.types); | 64 compiler, resolvedAst.elements, compiler.types); |
| 65 if (element.isField) { | 65 if (element.isField) { |
| 66 visitor.analyzingInitializer = true; | 66 visitor.analyzingInitializer = true; |
| 67 DartType type = | 67 ResolutionDartType type = |
| 68 visitor.analyzeVariableTypeAnnotation(resolvedAst.node); | 68 visitor.analyzeVariableTypeAnnotation(resolvedAst.node); |
| 69 visitor.analyzeVariableInitializer(element, type, resolvedAst.body); | 69 visitor.analyzeVariableInitializer(element, type, resolvedAst.body); |
| 70 } else { | 70 } else { |
| 71 resolvedAst.node.accept(visitor); | 71 resolvedAst.node.accept(visitor); |
| 72 } | 72 } |
| 73 }); | 73 }); |
| 74 }); | 74 }); |
| 75 } | 75 } |
| 76 } | 76 } |
| 77 | 77 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 93 | 93 |
| 94 /** | 94 /** |
| 95 * [ElementAccess] represents the access of [element], either as a property | 95 * [ElementAccess] represents the access of [element], either as a property |
| 96 * access or invocation. | 96 * access or invocation. |
| 97 */ | 97 */ |
| 98 abstract class ElementAccess { | 98 abstract class ElementAccess { |
| 99 Element get element; | 99 Element get element; |
| 100 | 100 |
| 101 String get name => element.name; | 101 String get name => element.name; |
| 102 | 102 |
| 103 DartType computeType(Resolution resolution); | 103 ResolutionDartType computeType(Resolution resolution); |
| 104 | 104 |
| 105 /// Returns [: true :] if the element can be access as an invocation. | 105 /// Returns [: true :] if the element can be access as an invocation. |
| 106 bool isCallable(Compiler compiler) { | 106 bool isCallable(Compiler compiler) { |
| 107 if (element != null && element.isAbstractField) { | 107 if (element != null && element.isAbstractField) { |
| 108 AbstractFieldElement abstractFieldElement = element; | 108 AbstractFieldElement abstractFieldElement = element; |
| 109 if (abstractFieldElement.getter == null) { | 109 if (abstractFieldElement.getter == null) { |
| 110 // Setters cannot be invoked as function invocations. | 110 // Setters cannot be invoked as function invocations. |
| 111 return false; | 111 return false; |
| 112 } | 112 } |
| 113 } | 113 } |
| 114 return compiler.types.isAssignable( | 114 return compiler.types.isAssignable( |
| 115 computeType(compiler.resolution), compiler.commonElements.functionType); | 115 computeType(compiler.resolution), compiler.commonElements.functionType); |
| 116 } | 116 } |
| 117 } | 117 } |
| 118 | 118 |
| 119 /// An access of a instance member. | 119 /// An access of a instance member. |
| 120 class MemberAccess extends ElementAccess { | 120 class MemberAccess extends ElementAccess { |
| 121 final MemberSignature member; | 121 final MemberSignature member; |
| 122 | 122 |
| 123 MemberAccess(MemberSignature this.member); | 123 MemberAccess(MemberSignature this.member); |
| 124 | 124 |
| 125 Element get element => member.declarations.first.element; | 125 Element get element => member.declarations.first.element; |
| 126 | 126 |
| 127 DartType computeType(Resolution resolution) => member.type; | 127 ResolutionDartType computeType(Resolution resolution) => member.type; |
| 128 | 128 |
| 129 String toString() => 'MemberAccess($member)'; | 129 String toString() => 'MemberAccess($member)'; |
| 130 } | 130 } |
| 131 | 131 |
| 132 /// An access of an unresolved element. | 132 /// An access of an unresolved element. |
| 133 class DynamicAccess implements ElementAccess { | 133 class DynamicAccess implements ElementAccess { |
| 134 const DynamicAccess(); | 134 const DynamicAccess(); |
| 135 | 135 |
| 136 Element get element => null; | 136 Element get element => null; |
| 137 | 137 |
| 138 String get name => 'dynamic'; | 138 String get name => 'dynamic'; |
| 139 | 139 |
| 140 DartType computeType(Resolution resolution) => const DynamicType(); | 140 ResolutionDartType computeType(Resolution resolution) => |
| 141 const ResolutionDynamicType(); |
| 141 | 142 |
| 142 bool isCallable(Compiler compiler) => true; | 143 bool isCallable(Compiler compiler) => true; |
| 143 | 144 |
| 144 String toString() => 'DynamicAccess'; | 145 String toString() => 'DynamicAccess'; |
| 145 } | 146 } |
| 146 | 147 |
| 147 /** | 148 /** |
| 148 * An access of a resolved top-level or static property or function, or an | 149 * An access of a resolved top-level or static property or function, or an |
| 149 * access of a resolved element through [:this:]. | 150 * access of a resolved element through [:this:]. |
| 150 */ | 151 */ |
| 151 class ResolvedAccess extends ElementAccess { | 152 class ResolvedAccess extends ElementAccess { |
| 152 final Element element; | 153 final Element element; |
| 153 | 154 |
| 154 ResolvedAccess(Element this.element) { | 155 ResolvedAccess(Element this.element) { |
| 155 assert(element != null); | 156 assert(element != null); |
| 156 } | 157 } |
| 157 | 158 |
| 158 DartType computeType(Resolution resolution) { | 159 ResolutionDartType computeType(Resolution resolution) { |
| 159 if (element.isGetter) { | 160 if (element.isGetter) { |
| 160 GetterElement getter = element; | 161 GetterElement getter = element; |
| 161 FunctionType functionType = getter.computeType(resolution); | 162 ResolutionFunctionType functionType = getter.computeType(resolution); |
| 162 return functionType.returnType; | 163 return functionType.returnType; |
| 163 } else if (element.isSetter) { | 164 } else if (element.isSetter) { |
| 164 SetterElement setter = element; | 165 SetterElement setter = element; |
| 165 FunctionType functionType = setter.computeType(resolution); | 166 ResolutionFunctionType functionType = setter.computeType(resolution); |
| 166 if (functionType.parameterTypes.length != 1) { | 167 if (functionType.parameterTypes.length != 1) { |
| 167 // TODO(johnniwinther,karlklose): this happens for malformed static | 168 // TODO(johnniwinther,karlklose): this happens for malformed static |
| 168 // setters. Treat them the same as instance members. | 169 // setters. Treat them the same as instance members. |
| 169 return const DynamicType(); | 170 return const ResolutionDynamicType(); |
| 170 } | 171 } |
| 171 return functionType.parameterTypes.first; | 172 return functionType.parameterTypes.first; |
| 172 } else if (element.isTypedef || element.isClass) { | 173 } else if (element.isTypedef || element.isClass) { |
| 173 TypeDeclarationElement typeDeclaration = element; | 174 TypeDeclarationElement typeDeclaration = element; |
| 174 typeDeclaration.computeType(resolution); | 175 typeDeclaration.computeType(resolution); |
| 175 return typeDeclaration.thisType; | 176 return typeDeclaration.thisType; |
| 176 } else { | 177 } else { |
| 177 TypedElement typedElement = element; | 178 TypedElement typedElement = element; |
| 178 typedElement.computeType(resolution); | 179 typedElement.computeType(resolution); |
| 179 return typedElement.type; | 180 return typedElement.type; |
| 180 } | 181 } |
| 181 } | 182 } |
| 182 | 183 |
| 183 String toString() => 'ResolvedAccess($element)'; | 184 String toString() => 'ResolvedAccess($element)'; |
| 184 } | 185 } |
| 185 | 186 |
| 186 /// An access to a promoted variable. | 187 /// An access to a promoted variable. |
| 187 class PromotedAccess extends ElementAccess { | 188 class PromotedAccess extends ElementAccess { |
| 188 final VariableElement element; | 189 final VariableElement element; |
| 189 final DartType type; | 190 final ResolutionDartType type; |
| 190 | 191 |
| 191 PromotedAccess(VariableElement this.element, DartType this.type) { | 192 PromotedAccess(VariableElement this.element, ResolutionDartType this.type) { |
| 192 assert(element != null); | 193 assert(element != null); |
| 193 assert(type != null); | 194 assert(type != null); |
| 194 } | 195 } |
| 195 | 196 |
| 196 DartType computeType(Resolution resolution) => type; | 197 ResolutionDartType computeType(Resolution resolution) => type; |
| 197 | 198 |
| 198 String toString() => 'PromotedAccess($element,$type)'; | 199 String toString() => 'PromotedAccess($element,$type)'; |
| 199 } | 200 } |
| 200 | 201 |
| 201 /** | 202 /** |
| 202 * An access of a resolved top-level or static property or function, or an | 203 * An access of a resolved top-level or static property or function, or an |
| 203 * access of a resolved element through [:this:]. | 204 * access of a resolved element through [:this:]. |
| 204 */ | 205 */ |
| 205 class TypeAccess extends ElementAccess { | 206 class TypeAccess extends ElementAccess { |
| 206 final DartType type; | 207 final ResolutionDartType type; |
| 207 TypeAccess(DartType this.type) { | 208 TypeAccess(ResolutionDartType this.type) { |
| 208 assert(type != null); | 209 assert(type != null); |
| 209 } | 210 } |
| 210 | 211 |
| 211 Element get element => type.element; | 212 Element get element => type.element; |
| 212 | 213 |
| 213 DartType computeType(Resolution resolution) => type; | 214 ResolutionDartType computeType(Resolution resolution) => type; |
| 214 | 215 |
| 215 String toString() => 'TypeAccess($type)'; | 216 String toString() => 'TypeAccess($type)'; |
| 216 } | 217 } |
| 217 | 218 |
| 218 /** | 219 /** |
| 219 * An access of a type literal. | 220 * An access of a type literal. |
| 220 */ | 221 */ |
| 221 class TypeLiteralAccess extends ElementAccess { | 222 class TypeLiteralAccess extends ElementAccess { |
| 222 final DartType type; | 223 final ResolutionDartType type; |
| 223 | 224 |
| 224 TypeLiteralAccess(this.type) { | 225 TypeLiteralAccess(this.type) { |
| 225 assert(type != null); | 226 assert(type != null); |
| 226 } | 227 } |
| 227 | 228 |
| 228 Element get element => type.element; | 229 Element get element => type.element; |
| 229 | 230 |
| 230 String get name => type.name; | 231 String get name => type.name; |
| 231 | 232 |
| 232 DartType computeType(Resolution resolution) => | 233 ResolutionDartType computeType(Resolution resolution) => |
| 233 resolution.commonElements.typeType; | 234 resolution.commonElements.typeType; |
| 234 | 235 |
| 235 String toString() => 'TypeLiteralAccess($type)'; | 236 String toString() => 'TypeLiteralAccess($type)'; |
| 236 } | 237 } |
| 237 | 238 |
| 238 /// An access to the 'call' method of a function type. | 239 /// An access to the 'call' method of a function type. |
| 239 class FunctionCallAccess implements ElementAccess { | 240 class FunctionCallAccess implements ElementAccess { |
| 240 final Element element; | 241 final Element element; |
| 241 final DartType type; | 242 final ResolutionDartType type; |
| 242 | 243 |
| 243 const FunctionCallAccess(this.element, this.type); | 244 const FunctionCallAccess(this.element, this.type); |
| 244 | 245 |
| 245 String get name => 'call'; | 246 String get name => 'call'; |
| 246 | 247 |
| 247 DartType computeType(Resolution resolution) => type; | 248 ResolutionDartType computeType(Resolution resolution) => type; |
| 248 | 249 |
| 249 bool isCallable(Compiler compiler) => true; | 250 bool isCallable(Compiler compiler) => true; |
| 250 | 251 |
| 251 String toString() => 'FunctionAccess($element, $type)'; | 252 String toString() => 'FunctionAccess($element, $type)'; |
| 252 } | 253 } |
| 253 | 254 |
| 254 /// An is-expression that potentially promotes a variable. | 255 /// An is-expression that potentially promotes a variable. |
| 255 class TypePromotion { | 256 class TypePromotion { |
| 256 final Send node; | 257 final Send node; |
| 257 final VariableElement variable; | 258 final VariableElement variable; |
| 258 final DartType type; | 259 final ResolutionDartType type; |
| 259 final List<TypePromotionMessage> messages = <TypePromotionMessage>[]; | 260 final List<TypePromotionMessage> messages = <TypePromotionMessage>[]; |
| 260 | 261 |
| 261 TypePromotion(this.node, this.variable, this.type); | 262 TypePromotion(this.node, this.variable, this.type); |
| 262 | 263 |
| 263 bool get isValid => messages.isEmpty; | 264 bool get isValid => messages.isEmpty; |
| 264 | 265 |
| 265 TypePromotion copy() { | 266 TypePromotion copy() { |
| 266 return new TypePromotion(node, variable, type)..messages.addAll(messages); | 267 return new TypePromotion(node, variable, type)..messages.addAll(messages); |
| 267 } | 268 } |
| 268 | 269 |
| 269 void addHint(DiagnosticMessage hint, | 270 void addHint(DiagnosticMessage hint, |
| 270 [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) { | 271 [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) { |
| 271 messages.add(new TypePromotionMessage(hint, infos)); | 272 messages.add(new TypePromotionMessage(hint, infos)); |
| 272 } | 273 } |
| 273 | 274 |
| 274 String toString() { | 275 String toString() { |
| 275 return 'Promote ${variable} to ${type}${isValid ? '' : ' (invalid)'}'; | 276 return 'Promote ${variable} to ${type}${isValid ? '' : ' (invalid)'}'; |
| 276 } | 277 } |
| 277 } | 278 } |
| 278 | 279 |
| 279 /// A hint or info message attached to a type promotion. | 280 /// A hint or info message attached to a type promotion. |
| 280 class TypePromotionMessage { | 281 class TypePromotionMessage { |
| 281 DiagnosticMessage hint; | 282 DiagnosticMessage hint; |
| 282 List<DiagnosticMessage> infos; | 283 List<DiagnosticMessage> infos; |
| 283 | 284 |
| 284 TypePromotionMessage(this.hint, this.infos); | 285 TypePromotionMessage(this.hint, this.infos); |
| 285 } | 286 } |
| 286 | 287 |
| 287 class TypeCheckerVisitor extends Visitor<DartType> { | 288 class TypeCheckerVisitor extends Visitor<ResolutionDartType> { |
| 288 final Compiler compiler; | 289 final Compiler compiler; |
| 289 final TreeElements elements; | 290 final TreeElements elements; |
| 290 final Types types; | 291 final Types types; |
| 291 | 292 |
| 292 Node lastSeenNode; | 293 Node lastSeenNode; |
| 293 DartType expectedReturnType; | 294 ResolutionDartType expectedReturnType; |
| 294 AsyncMarker currentAsyncMarker = AsyncMarker.SYNC; | 295 AsyncMarker currentAsyncMarker = AsyncMarker.SYNC; |
| 295 | 296 |
| 296 final ClassElement currentClass; | 297 final ClassElement currentClass; |
| 297 | 298 |
| 298 /// The immediately enclosing field, method or constructor being analyzed. | 299 /// The immediately enclosing field, method or constructor being analyzed. |
| 299 ExecutableElement executableContext; | 300 ExecutableElement executableContext; |
| 300 | 301 |
| 301 CommonElements get commonElements => compiler.commonElements; | 302 CommonElements get commonElements => compiler.commonElements; |
| 302 | 303 |
| 303 DiagnosticReporter get reporter => compiler.reporter; | 304 DiagnosticReporter get reporter => compiler.reporter; |
| 304 | 305 |
| 305 Resolution get resolution => compiler.resolution; | 306 Resolution get resolution => compiler.resolution; |
| 306 | 307 |
| 307 InterfaceType get intType => commonElements.intType; | 308 ResolutionInterfaceType get intType => commonElements.intType; |
| 308 InterfaceType get doubleType => commonElements.doubleType; | 309 ResolutionInterfaceType get doubleType => commonElements.doubleType; |
| 309 InterfaceType get boolType => commonElements.boolType; | 310 ResolutionInterfaceType get boolType => commonElements.boolType; |
| 310 InterfaceType get stringType => commonElements.stringType; | 311 ResolutionInterfaceType get stringType => commonElements.stringType; |
| 311 | 312 |
| 312 DartType thisType; | 313 ResolutionDartType thisType; |
| 313 DartType superType; | 314 ResolutionDartType superType; |
| 314 | 315 |
| 315 Link<DartType> cascadeTypes = const Link<DartType>(); | 316 Link<ResolutionDartType> cascadeTypes = const Link<ResolutionDartType>(); |
| 316 | 317 |
| 317 bool analyzingInitializer = false; | 318 bool analyzingInitializer = false; |
| 318 | 319 |
| 319 Map<Node, List<TypePromotion>> shownTypePromotionsMap = | 320 Map<Node, List<TypePromotion>> shownTypePromotionsMap = |
| 320 new Map<Node, List<TypePromotion>>(); | 321 new Map<Node, List<TypePromotion>>(); |
| 321 | 322 |
| 322 Map<VariableElement, Link<TypePromotion>> typePromotionsMap = | 323 Map<VariableElement, Link<TypePromotion>> typePromotionsMap = |
| 323 new Map<VariableElement, Link<TypePromotion>>(); | 324 new Map<VariableElement, Link<TypePromotion>>(); |
| 324 | 325 |
| 325 Set<TypePromotion> reportedTypePromotions = new Set<TypePromotion>(); | 326 Set<TypePromotion> reportedTypePromotions = new Set<TypePromotion>(); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 359 TypePromotion typePromotion = promotions.head; | 360 TypePromotion typePromotion = promotions.head; |
| 360 if (typePromotion.isValid) { | 361 if (typePromotion.isValid) { |
| 361 return typePromotion; | 362 return typePromotion; |
| 362 } | 363 } |
| 363 promotions = promotions.tail; | 364 promotions = promotions.tail; |
| 364 } | 365 } |
| 365 } | 366 } |
| 366 return null; | 367 return null; |
| 367 } | 368 } |
| 368 | 369 |
| 369 DartType getKnownType(VariableElement element) { | 370 ResolutionDartType getKnownType(VariableElement element) { |
| 370 TypePromotion typePromotion = getKnownTypePromotion(element); | 371 TypePromotion typePromotion = getKnownTypePromotion(element); |
| 371 if (typePromotion != null) return typePromotion.type; | 372 if (typePromotion != null) return typePromotion.type; |
| 372 return element.type; | 373 return element.type; |
| 373 } | 374 } |
| 374 | 375 |
| 375 TypeCheckerVisitor(this.compiler, TreeElements elements, this.types) | 376 TypeCheckerVisitor(this.compiler, TreeElements elements, this.types) |
| 376 : this.elements = elements, | 377 : this.elements = elements, |
| 377 this.executableContext = elements.analyzedElement, | 378 this.executableContext = elements.analyzedElement, |
| 378 this.currentClass = elements.analyzedElement != null | 379 this.currentClass = elements.analyzedElement != null |
| 379 ? elements.analyzedElement.enclosingClass | 380 ? elements.analyzedElement.enclosingClass |
| 380 : null { | 381 : null { |
| 381 if (currentClass != null) { | 382 if (currentClass != null) { |
| 382 thisType = currentClass.thisType; | 383 thisType = currentClass.thisType; |
| 383 superType = currentClass.supertype; | 384 superType = currentClass.supertype; |
| 384 } else { | 385 } else { |
| 385 // If these are used, an error should have been reported by the resolver. | 386 // If these are used, an error should have been reported by the resolver. |
| 386 thisType = const DynamicType(); | 387 thisType = const ResolutionDynamicType(); |
| 387 superType = const DynamicType(); | 388 superType = const ResolutionDynamicType(); |
| 388 } | 389 } |
| 389 } | 390 } |
| 390 | 391 |
| 391 LibraryElement get currentLibrary => elements.analyzedElement.library; | 392 LibraryElement get currentLibrary => elements.analyzedElement.library; |
| 392 | 393 |
| 393 reportTypeWarning(Spannable spannable, MessageKind kind, | 394 reportTypeWarning(Spannable spannable, MessageKind kind, |
| 394 [Map arguments = const {}]) { | 395 [Map arguments = const {}]) { |
| 395 reporter.reportWarningMessage(spannable, kind, arguments); | 396 reporter.reportWarningMessage(spannable, kind, arguments); |
| 396 } | 397 } |
| 397 | 398 |
| 398 reportMessage(Spannable spannable, MessageKind kind, Map arguments, | 399 reportMessage(Spannable spannable, MessageKind kind, Map arguments, |
| 399 {bool isHint: false}) { | 400 {bool isHint: false}) { |
| 400 if (isHint) { | 401 if (isHint) { |
| 401 reporter.reportHintMessage(spannable, kind, arguments); | 402 reporter.reportHintMessage(spannable, kind, arguments); |
| 402 } else { | 403 } else { |
| 403 reporter.reportWarningMessage(spannable, kind, arguments); | 404 reporter.reportWarningMessage(spannable, kind, arguments); |
| 404 } | 405 } |
| 405 } | 406 } |
| 406 | 407 |
| 407 reportTypePromotionHint(TypePromotion typePromotion) { | 408 reportTypePromotionHint(TypePromotion typePromotion) { |
| 408 if (!reportedTypePromotions.contains(typePromotion)) { | 409 if (!reportedTypePromotions.contains(typePromotion)) { |
| 409 reportedTypePromotions.add(typePromotion); | 410 reportedTypePromotions.add(typePromotion); |
| 410 for (TypePromotionMessage message in typePromotion.messages) { | 411 for (TypePromotionMessage message in typePromotion.messages) { |
| 411 reporter.reportHint(message.hint, message.infos); | 412 reporter.reportHint(message.hint, message.infos); |
| 412 } | 413 } |
| 413 } | 414 } |
| 414 } | 415 } |
| 415 | 416 |
| 416 // TODO(karlklose): remove these functions. | 417 // TODO(karlklose): remove these functions. |
| 417 DartType unhandledExpression() => const DynamicType(); | 418 ResolutionDartType unhandledExpression() => const ResolutionDynamicType(); |
| 418 | 419 |
| 419 DartType analyzeNonVoid(Node node) { | 420 ResolutionDartType analyzeNonVoid(Node node) { |
| 420 DartType type = analyze(node); | 421 ResolutionDartType type = analyze(node); |
| 421 if (type.isVoid) { | 422 if (type.isVoid) { |
| 422 reportTypeWarning(node, MessageKind.VOID_EXPRESSION); | 423 reportTypeWarning(node, MessageKind.VOID_EXPRESSION); |
| 423 } | 424 } |
| 424 return type; | 425 return type; |
| 425 } | 426 } |
| 426 | 427 |
| 427 DartType analyzeWithDefault(Node node, DartType defaultValue) { | 428 ResolutionDartType analyzeWithDefault( |
| 429 Node node, ResolutionDartType defaultValue) { |
| 428 return node != null ? analyze(node) : defaultValue; | 430 return node != null ? analyze(node) : defaultValue; |
| 429 } | 431 } |
| 430 | 432 |
| 431 /// If [inInitializer] is true, assignment should be interpreted as write to | 433 /// If [inInitializer] is true, assignment should be interpreted as write to |
| 432 /// a field and not to a setter. | 434 /// a field and not to a setter. |
| 433 DartType analyze(Node node, | 435 ResolutionDartType analyze(Node node, |
| 434 {bool inInitializer: false, bool mustHaveType: true}) { | 436 {bool inInitializer: false, bool mustHaveType: true}) { |
| 435 if (node == null) { | 437 if (node == null) { |
| 436 final String error = 'Unexpected node: null'; | 438 final String error = 'Unexpected node: null'; |
| 437 if (lastSeenNode != null) { | 439 if (lastSeenNode != null) { |
| 438 reporter.internalError(lastSeenNode, error); | 440 reporter.internalError(lastSeenNode, error); |
| 439 } else { | 441 } else { |
| 440 reporter.internalError(executableContext, error); | 442 reporter.internalError(executableContext, error); |
| 441 } | 443 } |
| 442 } else { | 444 } else { |
| 443 lastSeenNode = node; | 445 lastSeenNode = node; |
| 444 } | 446 } |
| 445 bool previouslyInitializer = analyzingInitializer; | 447 bool previouslyInitializer = analyzingInitializer; |
| 446 analyzingInitializer = inInitializer; | 448 analyzingInitializer = inInitializer; |
| 447 DartType result = node.accept(this); | 449 ResolutionDartType result = node.accept(this); |
| 448 analyzingInitializer = previouslyInitializer; | 450 analyzingInitializer = previouslyInitializer; |
| 449 if (result == null && mustHaveType) { | 451 if (result == null && mustHaveType) { |
| 450 reporter.internalError(node, 'Type is null.'); | 452 reporter.internalError(node, 'Type is null.'); |
| 451 } | 453 } |
| 452 return result; | 454 return result; |
| 453 } | 455 } |
| 454 | 456 |
| 455 void analyzeUntyped(Node node, {bool inInitializer: false}) { | 457 void analyzeUntyped(Node node, {bool inInitializer: false}) { |
| 456 if (node != null) { | 458 if (node != null) { |
| 457 analyze(node, inInitializer: inInitializer, mustHaveType: false); | 459 analyze(node, inInitializer: inInitializer, mustHaveType: false); |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 530 } | 532 } |
| 531 | 533 |
| 532 for (TypePromotion typePromotion in getShownTypePromotionsFor(right)) { | 534 for (TypePromotion typePromotion in getShownTypePromotionsFor(right)) { |
| 533 typePromotion = typePromotion.copy(); | 535 typePromotion = typePromotion.copy(); |
| 534 checkTypePromotion(right, typePromotion); | 536 checkTypePromotion(right, typePromotion); |
| 535 showTypePromotion(node, typePromotion); | 537 showTypePromotion(node, typePromotion); |
| 536 } | 538 } |
| 537 } | 539 } |
| 538 | 540 |
| 539 /// Analyze [node] in the context of the known types shown in [context]. | 541 /// Analyze [node] in the context of the known types shown in [context]. |
| 540 DartType analyzeInPromotedContext(Node context, Node node, | 542 ResolutionDartType analyzeInPromotedContext(Node context, Node node, |
| 541 {bool mustHaveType: true}) { | 543 {bool mustHaveType: true}) { |
| 542 Link<TypePromotion> knownForNode = const Link<TypePromotion>(); | 544 Link<TypePromotion> knownForNode = const Link<TypePromotion>(); |
| 543 for (TypePromotion typePromotion in getShownTypePromotionsFor(context)) { | 545 for (TypePromotion typePromotion in getShownTypePromotionsFor(context)) { |
| 544 typePromotion = typePromotion.copy(); | 546 typePromotion = typePromotion.copy(); |
| 545 checkTypePromotion(node, typePromotion, checkAccesses: true); | 547 checkTypePromotion(node, typePromotion, checkAccesses: true); |
| 546 knownForNode = knownForNode.prepend(typePromotion); | 548 knownForNode = knownForNode.prepend(typePromotion); |
| 547 registerKnownTypePromotion(typePromotion); | 549 registerKnownTypePromotion(typePromotion); |
| 548 } | 550 } |
| 549 | 551 |
| 550 final DartType type = analyze(node, mustHaveType: mustHaveType); | 552 final ResolutionDartType type = analyze(node, mustHaveType: mustHaveType); |
| 551 | 553 |
| 552 while (!knownForNode.isEmpty) { | 554 while (!knownForNode.isEmpty) { |
| 553 unregisterKnownTypePromotion(knownForNode.head); | 555 unregisterKnownTypePromotion(knownForNode.head); |
| 554 knownForNode = knownForNode.tail; | 556 knownForNode = knownForNode.tail; |
| 555 } | 557 } |
| 556 | 558 |
| 557 return type; | 559 return type; |
| 558 } | 560 } |
| 559 | 561 |
| 560 /** | 562 /** |
| 561 * Check if a value of type [from] can be assigned to a variable, parameter or | 563 * Check if a value of type [from] can be assigned to a variable, parameter or |
| 562 * return value of type [to]. If `isConst == true`, an error is emitted in | 564 * return value of type [to]. If `isConst == true`, an error is emitted in |
| 563 * checked mode, otherwise a warning is issued. | 565 * checked mode, otherwise a warning is issued. |
| 564 */ | 566 */ |
| 565 bool checkAssignable(Spannable spannable, DartType from, DartType to, | 567 bool checkAssignable( |
| 568 Spannable spannable, ResolutionDartType from, ResolutionDartType to, |
| 566 {bool isConst: false}) { | 569 {bool isConst: false}) { |
| 567 if (!types.isAssignable(from, to)) { | 570 if (!types.isAssignable(from, to)) { |
| 568 if (compiler.options.enableTypeAssertions && isConst) { | 571 if (compiler.options.enableTypeAssertions && isConst) { |
| 569 reporter.reportErrorMessage(spannable, MessageKind.NOT_ASSIGNABLE, | 572 reporter.reportErrorMessage(spannable, MessageKind.NOT_ASSIGNABLE, |
| 570 {'fromType': from, 'toType': to}); | 573 {'fromType': from, 'toType': to}); |
| 571 } else { | 574 } else { |
| 572 reporter.reportWarningMessage(spannable, MessageKind.NOT_ASSIGNABLE, | 575 reporter.reportWarningMessage(spannable, MessageKind.NOT_ASSIGNABLE, |
| 573 {'fromType': from, 'toType': to}); | 576 {'fromType': from, 'toType': to}); |
| 574 } | 577 } |
| 575 return false; | 578 return false; |
| 576 } | 579 } |
| 577 return true; | 580 return true; |
| 578 } | 581 } |
| 579 | 582 |
| 580 checkCondition(Expression condition) { | 583 checkCondition(Expression condition) { |
| 581 checkAssignable(condition, analyze(condition), boolType); | 584 checkAssignable(condition, analyze(condition), boolType); |
| 582 } | 585 } |
| 583 | 586 |
| 584 void pushCascadeType(DartType type) { | 587 void pushCascadeType(ResolutionDartType type) { |
| 585 cascadeTypes = cascadeTypes.prepend(type); | 588 cascadeTypes = cascadeTypes.prepend(type); |
| 586 } | 589 } |
| 587 | 590 |
| 588 DartType popCascadeType() { | 591 ResolutionDartType popCascadeType() { |
| 589 DartType type = cascadeTypes.head; | 592 ResolutionDartType type = cascadeTypes.head; |
| 590 cascadeTypes = cascadeTypes.tail; | 593 cascadeTypes = cascadeTypes.tail; |
| 591 return type; | 594 return type; |
| 592 } | 595 } |
| 593 | 596 |
| 594 visitAssert(Assert node) { | 597 visitAssert(Assert node) { |
| 595 analyze(node.condition); | 598 analyze(node.condition); |
| 596 if (node.hasMessage) analyze(node.message); | 599 if (node.hasMessage) analyze(node.message); |
| 597 } | 600 } |
| 598 | 601 |
| 599 visitBlock(Block node) { | 602 visitBlock(Block node) { |
| 600 analyzeUntyped(node.statements); | 603 analyzeUntyped(node.statements); |
| 601 } | 604 } |
| 602 | 605 |
| 603 DartType visitCascade(Cascade node) { | 606 ResolutionDartType visitCascade(Cascade node) { |
| 604 analyze(node.expression); | 607 analyze(node.expression); |
| 605 return popCascadeType(); | 608 return popCascadeType(); |
| 606 } | 609 } |
| 607 | 610 |
| 608 DartType visitCascadeReceiver(CascadeReceiver node) { | 611 ResolutionDartType visitCascadeReceiver(CascadeReceiver node) { |
| 609 DartType type = analyze(node.expression); | 612 ResolutionDartType type = analyze(node.expression); |
| 610 pushCascadeType(type); | 613 pushCascadeType(type); |
| 611 return type; | 614 return type; |
| 612 } | 615 } |
| 613 | 616 |
| 614 visitDoWhile(DoWhile node) { | 617 visitDoWhile(DoWhile node) { |
| 615 analyzeUntyped(node.body); | 618 analyzeUntyped(node.body); |
| 616 checkCondition(node.condition); | 619 checkCondition(node.condition); |
| 617 } | 620 } |
| 618 | 621 |
| 619 visitExpressionStatement(ExpressionStatement node) { | 622 visitExpressionStatement(ExpressionStatement node) { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 632 if (node.update != null) { | 635 if (node.update != null) { |
| 633 analyzeUntyped(node.update); | 636 analyzeUntyped(node.update); |
| 634 } | 637 } |
| 635 analyzeUntyped(node.body); | 638 analyzeUntyped(node.body); |
| 636 } | 639 } |
| 637 | 640 |
| 638 visitFunctionDeclaration(FunctionDeclaration node) { | 641 visitFunctionDeclaration(FunctionDeclaration node) { |
| 639 analyze(node.function); | 642 analyze(node.function); |
| 640 } | 643 } |
| 641 | 644 |
| 642 DartType visitFunctionExpression(FunctionExpression node) { | 645 ResolutionDartType visitFunctionExpression(FunctionExpression node) { |
| 643 DartType type; | 646 ResolutionDartType type; |
| 644 DartType returnType; | 647 ResolutionDartType returnType; |
| 645 final FunctionElement element = elements.getFunctionDefinition(node); | 648 final FunctionElement element = elements.getFunctionDefinition(node); |
| 646 assert(invariant(node, element != null, | 649 assert(invariant(node, element != null, |
| 647 message: 'FunctionExpression with no element')); | 650 message: 'FunctionExpression with no element')); |
| 648 if (Elements.isUnresolved(element)) return const DynamicType(); | 651 if (Elements.isUnresolved(element)) return const ResolutionDynamicType(); |
| 649 if (element.isGenerativeConstructor) { | 652 if (element.isGenerativeConstructor) { |
| 650 type = const DynamicType(); | 653 type = const ResolutionDynamicType(); |
| 651 returnType = const VoidType(); | 654 returnType = const ResolutionVoidType(); |
| 652 | 655 |
| 653 element.functionSignature.forEachParameter((ParameterElement parameter) { | 656 element.functionSignature.forEachParameter((ParameterElement parameter) { |
| 654 if (parameter.isInitializingFormal) { | 657 if (parameter.isInitializingFormal) { |
| 655 InitializingFormalElement fieldParameter = parameter; | 658 InitializingFormalElement fieldParameter = parameter; |
| 656 checkAssignable(parameter, parameter.type, | 659 checkAssignable(parameter, parameter.type, |
| 657 fieldParameter.fieldElement.computeType(resolution)); | 660 fieldParameter.fieldElement.computeType(resolution)); |
| 658 } | 661 } |
| 659 }); | 662 }); |
| 660 if (node.initializers != null) { | 663 if (node.initializers != null) { |
| 661 analyzeUntyped(node.initializers, inInitializer: true); | 664 analyzeUntyped(node.initializers, inInitializer: true); |
| 662 } | 665 } |
| 663 } else { | 666 } else { |
| 664 FunctionType functionType = element.computeType(resolution); | 667 ResolutionFunctionType functionType = element.computeType(resolution); |
| 665 returnType = functionType.returnType; | 668 returnType = functionType.returnType; |
| 666 type = functionType; | 669 type = functionType; |
| 667 } | 670 } |
| 668 ExecutableElement previousExecutableContext = executableContext; | 671 ExecutableElement previousExecutableContext = executableContext; |
| 669 DartType previousReturnType = expectedReturnType; | 672 ResolutionDartType previousReturnType = expectedReturnType; |
| 670 expectedReturnType = returnType; | 673 expectedReturnType = returnType; |
| 671 AsyncMarker previousAsyncMarker = currentAsyncMarker; | 674 AsyncMarker previousAsyncMarker = currentAsyncMarker; |
| 672 | 675 |
| 673 executableContext = element; | 676 executableContext = element; |
| 674 currentAsyncMarker = element.asyncMarker; | 677 currentAsyncMarker = element.asyncMarker; |
| 675 analyzeUntyped(node.body); | 678 analyzeUntyped(node.body); |
| 676 | 679 |
| 677 executableContext = previousExecutableContext; | 680 executableContext = previousExecutableContext; |
| 678 expectedReturnType = previousReturnType; | 681 expectedReturnType = previousReturnType; |
| 679 currentAsyncMarker = previousAsyncMarker; | 682 currentAsyncMarker = previousAsyncMarker; |
| 680 return type; | 683 return type; |
| 681 } | 684 } |
| 682 | 685 |
| 683 DartType visitIdentifier(Identifier node) { | 686 ResolutionDartType visitIdentifier(Identifier node) { |
| 684 if (node.isThis()) { | 687 if (node.isThis()) { |
| 685 return thisType; | 688 return thisType; |
| 686 } else if (node.isSuper()) { | 689 } else if (node.isSuper()) { |
| 687 return superType; | 690 return superType; |
| 688 } else { | 691 } else { |
| 689 TypedElement element = elements[node]; | 692 TypedElement element = elements[node]; |
| 690 assert(invariant(node, element != null, | 693 assert(invariant(node, element != null, |
| 691 message: 'Missing element for identifier')); | 694 message: 'Missing element for identifier')); |
| 692 assert(invariant( | 695 assert(invariant( |
| 693 node, element.isVariable || element.isParameter || element.isField, | 696 node, element.isVariable || element.isParameter || element.isField, |
| (...skipping 15 matching lines...) Expand all Loading... |
| 709 | 712 |
| 710 void checkPrivateAccess(Node node, Element element, String name) { | 713 void checkPrivateAccess(Node node, Element element, String name) { |
| 711 if (name != null && | 714 if (name != null && |
| 712 Name.isPrivateName(name) && | 715 Name.isPrivateName(name) && |
| 713 element.library != currentLibrary) { | 716 element.library != currentLibrary) { |
| 714 reportTypeWarning(node, MessageKind.PRIVATE_ACCESS, | 717 reportTypeWarning(node, MessageKind.PRIVATE_ACCESS, |
| 715 {'name': name, 'libraryName': element.library.libraryOrScriptName}); | 718 {'name': name, 'libraryName': element.library.libraryOrScriptName}); |
| 716 } | 719 } |
| 717 } | 720 } |
| 718 | 721 |
| 719 ElementAccess lookupMember(Node node, DartType receiverType, String name, | 722 ElementAccess lookupMember(Node node, ResolutionDartType receiverType, |
| 720 MemberKind memberKind, Element receiverElement, | 723 String name, MemberKind memberKind, Element receiverElement, |
| 721 {bool lookupClassMember: false, bool isHint: false}) { | 724 {bool lookupClassMember: false, bool isHint: false}) { |
| 722 if (receiverType.treatAsDynamic) { | 725 if (receiverType.treatAsDynamic) { |
| 723 return const DynamicAccess(); | 726 return const DynamicAccess(); |
| 724 } | 727 } |
| 725 | 728 |
| 726 Name memberName = new Name(name, currentLibrary, | 729 Name memberName = new Name(name, currentLibrary, |
| 727 isSetter: memberKind == MemberKind.SETTER); | 730 isSetter: memberKind == MemberKind.SETTER); |
| 728 | 731 |
| 729 // Lookup the class or interface member [name] in [interface]. | 732 // Lookup the class or interface member [name] in [interface]. |
| 730 MemberSignature lookupMemberSignature(Name name, InterfaceType interface) { | 733 MemberSignature lookupMemberSignature( |
| 734 Name name, ResolutionInterfaceType interface) { |
| 731 MembersCreator.computeClassMembersByName( | 735 MembersCreator.computeClassMembersByName( |
| 732 resolution, interface.element, name.text); | 736 resolution, interface.element, name.text); |
| 733 return lookupClassMember || analyzingInitializer | 737 return lookupClassMember || analyzingInitializer |
| 734 ? interface.lookupClassMember(name) | 738 ? interface.lookupClassMember(name) |
| 735 : interface.lookupInterfaceMember(name); | 739 : interface.lookupInterfaceMember(name); |
| 736 } | 740 } |
| 737 | 741 |
| 738 // Compute the access of [name] on [type]. This function takes the special | 742 // Compute the access of [name] on [type]. This function takes the special |
| 739 // 'call' method into account. | 743 // 'call' method into account. |
| 740 ElementAccess getAccess( | 744 ElementAccess getAccess(Name name, ResolutionDartType unaliasedBound, |
| 741 Name name, DartType unaliasedBound, InterfaceType interface) { | 745 ResolutionInterfaceType interface) { |
| 742 MemberSignature member = lookupMemberSignature(memberName, interface); | 746 MemberSignature member = lookupMemberSignature(memberName, interface); |
| 743 if (member != null) { | 747 if (member != null) { |
| 744 if (member is ErroneousMember) { | 748 if (member is ErroneousMember) { |
| 745 return const DynamicAccess(); | 749 return const DynamicAccess(); |
| 746 } else { | 750 } else { |
| 747 return new MemberAccess(member); | 751 return new MemberAccess(member); |
| 748 } | 752 } |
| 749 } | 753 } |
| 750 if (name == const PublicName('call')) { | 754 if (name == const PublicName('call')) { |
| 751 if (unaliasedBound.isFunctionType) { | 755 if (unaliasedBound.isFunctionType) { |
| 752 // This is an access the implicit 'call' method of a function type. | 756 // This is an access the implicit 'call' method of a function type. |
| 753 return new FunctionCallAccess(receiverElement, unaliasedBound); | 757 return new FunctionCallAccess(receiverElement, unaliasedBound); |
| 754 } | 758 } |
| 755 if (types.isSubtype(interface, commonElements.functionType)) { | 759 if (types.isSubtype(interface, commonElements.functionType)) { |
| 756 // This is an access of the special 'call' method implicitly defined | 760 // This is an access of the special 'call' method implicitly defined |
| 757 // on 'Function'. This method can be called with any arguments, which | 761 // on 'Function'. This method can be called with any arguments, which |
| 758 // we ensure by giving it the type 'dynamic'. | 762 // we ensure by giving it the type 'dynamic'. |
| 759 return new FunctionCallAccess(null, const DynamicType()); | 763 return new FunctionCallAccess(null, const ResolutionDynamicType()); |
| 760 } | 764 } |
| 761 } | 765 } |
| 762 return null; | 766 return null; |
| 763 } | 767 } |
| 764 | 768 |
| 765 DartType unaliasedBound = | 769 ResolutionDartType unaliasedBound = |
| 766 Types.computeUnaliasedBound(resolution, receiverType); | 770 Types.computeUnaliasedBound(resolution, receiverType); |
| 767 if (unaliasedBound.treatAsDynamic) { | 771 if (unaliasedBound.treatAsDynamic) { |
| 768 return new DynamicAccess(); | 772 return new DynamicAccess(); |
| 769 } | 773 } |
| 770 InterfaceType interface = | 774 ResolutionInterfaceType interface = |
| 771 Types.computeInterfaceType(resolution, unaliasedBound); | 775 Types.computeInterfaceType(resolution, unaliasedBound); |
| 772 ElementAccess access = getAccess(memberName, unaliasedBound, interface); | 776 ElementAccess access = getAccess(memberName, unaliasedBound, interface); |
| 773 if (access != null) { | 777 if (access != null) { |
| 774 return access; | 778 return access; |
| 775 } | 779 } |
| 776 if (receiverElement != null && | 780 if (receiverElement != null && |
| 777 (receiverElement.isVariable || receiverElement.isParameter)) { | 781 (receiverElement.isVariable || receiverElement.isParameter)) { |
| 778 Link<TypePromotion> typePromotions = typePromotionsMap[receiverElement]; | 782 Link<TypePromotion> typePromotions = typePromotionsMap[receiverElement]; |
| 779 if (typePromotions != null) { | 783 if (typePromotions != null) { |
| 780 while (!typePromotions.isEmpty) { | 784 while (!typePromotions.isEmpty) { |
| 781 TypePromotion typePromotion = typePromotions.head; | 785 TypePromotion typePromotion = typePromotions.head; |
| 782 if (!typePromotion.isValid) { | 786 if (!typePromotion.isValid) { |
| 783 DartType unaliasedBound = | 787 ResolutionDartType unaliasedBound = |
| 784 Types.computeUnaliasedBound(resolution, typePromotion.type); | 788 Types.computeUnaliasedBound(resolution, typePromotion.type); |
| 785 if (!unaliasedBound.treatAsDynamic) { | 789 if (!unaliasedBound.treatAsDynamic) { |
| 786 InterfaceType interface = | 790 ResolutionInterfaceType interface = |
| 787 Types.computeInterfaceType(resolution, unaliasedBound); | 791 Types.computeInterfaceType(resolution, unaliasedBound); |
| 788 if (getAccess(memberName, unaliasedBound, interface) != null) { | 792 if (getAccess(memberName, unaliasedBound, interface) != null) { |
| 789 reportTypePromotionHint(typePromotion); | 793 reportTypePromotionHint(typePromotion); |
| 790 } | 794 } |
| 791 } | 795 } |
| 792 } | 796 } |
| 793 typePromotions = typePromotions.tail; | 797 typePromotions = typePromotions.tail; |
| 794 } | 798 } |
| 795 } | 799 } |
| 796 } | 800 } |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 866 reportMessage(node, MessageKind.UNDEFINED_SETTER, | 870 reportMessage(node, MessageKind.UNDEFINED_SETTER, |
| 867 {'className': receiverType.name, 'memberName': name}, | 871 {'className': receiverType.name, 'memberName': name}, |
| 868 isHint: isHint); | 872 isHint: isHint); |
| 869 break; | 873 break; |
| 870 } | 874 } |
| 871 } | 875 } |
| 872 } | 876 } |
| 873 return const DynamicAccess(); | 877 return const DynamicAccess(); |
| 874 } | 878 } |
| 875 | 879 |
| 876 DartType lookupMemberType( | 880 ResolutionDartType lookupMemberType( |
| 877 Node node, DartType type, String name, MemberKind memberKind, | 881 Node node, ResolutionDartType type, String name, MemberKind memberKind, |
| 878 {bool isHint: false}) { | 882 {bool isHint: false}) { |
| 879 return lookupMember(node, type, name, memberKind, null, isHint: isHint) | 883 return lookupMember(node, type, name, memberKind, null, isHint: isHint) |
| 880 .computeType(resolution); | 884 .computeType(resolution); |
| 881 } | 885 } |
| 882 | 886 |
| 883 void analyzeArguments(Send send, Element element, DartType type, | 887 void analyzeArguments(Send send, Element element, ResolutionDartType type, |
| 884 [LinkBuilder<DartType> argumentTypes]) { | 888 [LinkBuilder<ResolutionDartType> argumentTypes]) { |
| 885 Link<Node> arguments = send.arguments; | 889 Link<Node> arguments = send.arguments; |
| 886 type.computeUnaliased(resolution); | 890 type.computeUnaliased(resolution); |
| 887 DartType unaliasedType = type.unaliased; | 891 ResolutionDartType unaliasedType = type.unaliased; |
| 888 if (identical(unaliasedType.kind, TypeKind.FUNCTION)) { | 892 if (identical(unaliasedType.kind, ResolutionTypeKind.FUNCTION)) { |
| 889 /// Report [warning] including info(s) about the declaration of [element] | 893 /// Report [warning] including info(s) about the declaration of [element] |
| 890 /// or [type]. | 894 /// or [type]. |
| 891 void reportWarning(DiagnosticMessage warning) { | 895 void reportWarning(DiagnosticMessage warning) { |
| 892 // TODO(johnniwinther): Support pointing to individual parameters on | 896 // TODO(johnniwinther): Support pointing to individual parameters on |
| 893 // assignability warnings. | 897 // assignability warnings. |
| 894 List<DiagnosticMessage> infos = <DiagnosticMessage>[]; | 898 List<DiagnosticMessage> infos = <DiagnosticMessage>[]; |
| 895 Element declaration = element; | 899 Element declaration = element; |
| 896 if (declaration == null) { | 900 if (declaration == null) { |
| 897 declaration = type.element; | 901 declaration = type.element; |
| 898 } else if (type.isTypedef) { | 902 } else if (type.isTypedef) { |
| 899 infos.add(reporter.createMessage(declaration, | 903 infos.add(reporter.createMessage(declaration, |
| 900 MessageKind.THIS_IS_THE_DECLARATION, {'name': element.name})); | 904 MessageKind.THIS_IS_THE_DECLARATION, {'name': element.name})); |
| 901 declaration = type.element; | 905 declaration = type.element; |
| 902 } | 906 } |
| 903 if (declaration != null) { | 907 if (declaration != null) { |
| 904 infos.add(reporter.createMessage( | 908 infos.add(reporter.createMessage( |
| 905 declaration, MessageKind.THIS_IS_THE_METHOD)); | 909 declaration, MessageKind.THIS_IS_THE_METHOD)); |
| 906 } | 910 } |
| 907 reporter.reportWarning(warning, infos); | 911 reporter.reportWarning(warning, infos); |
| 908 } | 912 } |
| 909 | 913 |
| 910 /// Report a warning on [node] if [argumentType] is not assignable to | 914 /// Report a warning on [node] if [argumentType] is not assignable to |
| 911 /// [parameterType]. | 915 /// [parameterType]. |
| 912 void checkAssignable( | 916 void checkAssignable(Spannable node, ResolutionDartType argumentType, |
| 913 Spannable node, DartType argumentType, DartType parameterType) { | 917 ResolutionDartType parameterType) { |
| 914 if (!types.isAssignable(argumentType, parameterType)) { | 918 if (!types.isAssignable(argumentType, parameterType)) { |
| 915 reportWarning(reporter.createMessage(node, MessageKind.NOT_ASSIGNABLE, | 919 reportWarning(reporter.createMessage(node, MessageKind.NOT_ASSIGNABLE, |
| 916 {'fromType': argumentType, 'toType': parameterType})); | 920 {'fromType': argumentType, 'toType': parameterType})); |
| 917 } | 921 } |
| 918 } | 922 } |
| 919 | 923 |
| 920 FunctionType funType = unaliasedType; | 924 ResolutionFunctionType funType = unaliasedType; |
| 921 Iterator<DartType> parameterTypes = funType.parameterTypes.iterator; | 925 Iterator<ResolutionDartType> parameterTypes = |
| 922 Iterator<DartType> optionalParameterTypes = | 926 funType.parameterTypes.iterator; |
| 927 Iterator<ResolutionDartType> optionalParameterTypes = |
| 923 funType.optionalParameterTypes.iterator; | 928 funType.optionalParameterTypes.iterator; |
| 924 while (!arguments.isEmpty) { | 929 while (!arguments.isEmpty) { |
| 925 Node argument = arguments.head; | 930 Node argument = arguments.head; |
| 926 NamedArgument namedArgument = argument.asNamedArgument(); | 931 NamedArgument namedArgument = argument.asNamedArgument(); |
| 927 if (namedArgument != null) { | 932 if (namedArgument != null) { |
| 928 argument = namedArgument.expression; | 933 argument = namedArgument.expression; |
| 929 String argumentName = namedArgument.name.source; | 934 String argumentName = namedArgument.name.source; |
| 930 DartType namedParameterType = | 935 ResolutionDartType namedParameterType = |
| 931 funType.getNamedParameterType(argumentName); | 936 funType.getNamedParameterType(argumentName); |
| 932 if (namedParameterType == null) { | 937 if (namedParameterType == null) { |
| 933 // TODO(johnniwinther): Provide better information on the called | 938 // TODO(johnniwinther): Provide better information on the called |
| 934 // function. | 939 // function. |
| 935 reportWarning(reporter.createMessage( | 940 reportWarning(reporter.createMessage( |
| 936 argument, | 941 argument, |
| 937 MessageKind.NAMED_ARGUMENT_NOT_FOUND, | 942 MessageKind.NAMED_ARGUMENT_NOT_FOUND, |
| 938 {'argumentName': argumentName})); | 943 {'argumentName': argumentName})); |
| 939 | 944 |
| 940 DartType argumentType = analyze(argument); | 945 ResolutionDartType argumentType = analyze(argument); |
| 941 if (argumentTypes != null) argumentTypes.addLast(argumentType); | 946 if (argumentTypes != null) argumentTypes.addLast(argumentType); |
| 942 } else { | 947 } else { |
| 943 DartType argumentType = analyze(argument); | 948 ResolutionDartType argumentType = analyze(argument); |
| 944 if (argumentTypes != null) argumentTypes.addLast(argumentType); | 949 if (argumentTypes != null) argumentTypes.addLast(argumentType); |
| 945 checkAssignable(argument, argumentType, namedParameterType); | 950 checkAssignable(argument, argumentType, namedParameterType); |
| 946 } | 951 } |
| 947 } else { | 952 } else { |
| 948 if (!parameterTypes.moveNext()) { | 953 if (!parameterTypes.moveNext()) { |
| 949 if (!optionalParameterTypes.moveNext()) { | 954 if (!optionalParameterTypes.moveNext()) { |
| 950 // TODO(johnniwinther): Provide better information on the | 955 // TODO(johnniwinther): Provide better information on the |
| 951 // called function. | 956 // called function. |
| 952 reportWarning(reporter.createMessage( | 957 reportWarning(reporter.createMessage( |
| 953 argument, MessageKind.ADDITIONAL_ARGUMENT)); | 958 argument, MessageKind.ADDITIONAL_ARGUMENT)); |
| 954 | 959 |
| 955 DartType argumentType = analyze(argument); | 960 ResolutionDartType argumentType = analyze(argument); |
| 956 if (argumentTypes != null) argumentTypes.addLast(argumentType); | 961 if (argumentTypes != null) argumentTypes.addLast(argumentType); |
| 957 } else { | 962 } else { |
| 958 DartType argumentType = analyze(argument); | 963 ResolutionDartType argumentType = analyze(argument); |
| 959 if (argumentTypes != null) argumentTypes.addLast(argumentType); | 964 if (argumentTypes != null) argumentTypes.addLast(argumentType); |
| 960 checkAssignable( | 965 checkAssignable( |
| 961 argument, argumentType, optionalParameterTypes.current); | 966 argument, argumentType, optionalParameterTypes.current); |
| 962 } | 967 } |
| 963 } else { | 968 } else { |
| 964 DartType argumentType = analyze(argument); | 969 ResolutionDartType argumentType = analyze(argument); |
| 965 if (argumentTypes != null) argumentTypes.addLast(argumentType); | 970 if (argumentTypes != null) argumentTypes.addLast(argumentType); |
| 966 checkAssignable(argument, argumentType, parameterTypes.current); | 971 checkAssignable(argument, argumentType, parameterTypes.current); |
| 967 } | 972 } |
| 968 } | 973 } |
| 969 arguments = arguments.tail; | 974 arguments = arguments.tail; |
| 970 } | 975 } |
| 971 if (parameterTypes.moveNext()) { | 976 if (parameterTypes.moveNext()) { |
| 972 // TODO(johnniwinther): Provide better information on the called | 977 // TODO(johnniwinther): Provide better information on the called |
| 973 // function. | 978 // function. |
| 974 reportWarning(reporter.createMessage(send, MessageKind.MISSING_ARGUMENT, | 979 reportWarning(reporter.createMessage(send, MessageKind.MISSING_ARGUMENT, |
| 975 {'argumentType': parameterTypes.current})); | 980 {'argumentType': parameterTypes.current})); |
| 976 } | 981 } |
| 977 } else { | 982 } else { |
| 978 while (!arguments.isEmpty) { | 983 while (!arguments.isEmpty) { |
| 979 DartType argumentType = analyze(arguments.head); | 984 ResolutionDartType argumentType = analyze(arguments.head); |
| 980 if (argumentTypes != null) argumentTypes.addLast(argumentType); | 985 if (argumentTypes != null) argumentTypes.addLast(argumentType); |
| 981 arguments = arguments.tail; | 986 arguments = arguments.tail; |
| 982 } | 987 } |
| 983 } | 988 } |
| 984 } | 989 } |
| 985 | 990 |
| 986 // Analyze the invocation [node] of [elementAccess]. | 991 // Analyze the invocation [node] of [elementAccess]. |
| 987 // | 992 // |
| 988 // If provided [argumentTypes] is filled with the argument types during | 993 // If provided [argumentTypes] is filled with the argument types during |
| 989 // analysis. | 994 // analysis. |
| 990 DartType analyzeInvocation(Send node, ElementAccess elementAccess, | 995 ResolutionDartType analyzeInvocation(Send node, ElementAccess elementAccess, |
| 991 [LinkBuilder<DartType> argumentTypes]) { | 996 [LinkBuilder<ResolutionDartType> argumentTypes]) { |
| 992 DartType type = elementAccess.computeType(resolution); | 997 ResolutionDartType type = elementAccess.computeType(resolution); |
| 993 if (elementAccess.isCallable(compiler)) { | 998 if (elementAccess.isCallable(compiler)) { |
| 994 analyzeArguments(node, elementAccess.element, type, argumentTypes); | 999 analyzeArguments(node, elementAccess.element, type, argumentTypes); |
| 995 } else { | 1000 } else { |
| 996 reportTypeWarning( | 1001 reportTypeWarning( |
| 997 node, MessageKind.NOT_CALLABLE, {'elementName': elementAccess.name}); | 1002 node, MessageKind.NOT_CALLABLE, {'elementName': elementAccess.name}); |
| 998 analyzeArguments( | 1003 analyzeArguments(node, elementAccess.element, |
| 999 node, elementAccess.element, const DynamicType(), argumentTypes); | 1004 const ResolutionDynamicType(), argumentTypes); |
| 1000 } | 1005 } |
| 1001 type.computeUnaliased(resolution); | 1006 type.computeUnaliased(resolution); |
| 1002 type = type.unaliased; | 1007 type = type.unaliased; |
| 1003 if (type.isFunctionType) { | 1008 if (type.isFunctionType) { |
| 1004 FunctionType funType = type; | 1009 ResolutionFunctionType funType = type; |
| 1005 return funType.returnType; | 1010 return funType.returnType; |
| 1006 } else { | 1011 } else { |
| 1007 return const DynamicType(); | 1012 return const ResolutionDynamicType(); |
| 1008 } | 1013 } |
| 1009 } | 1014 } |
| 1010 | 1015 |
| 1011 /** | 1016 /** |
| 1012 * Computes the [ElementAccess] for [name] on the [node] possibly using the | 1017 * Computes the [ElementAccess] for [name] on the [node] possibly using the |
| 1013 * [element] provided for [node] by the resolver. | 1018 * [element] provided for [node] by the resolver. |
| 1014 */ | 1019 */ |
| 1015 ElementAccess computeAccess( | 1020 ElementAccess computeAccess( |
| 1016 Send node, String name, Element element, MemberKind memberKind, | 1021 Send node, String name, Element element, MemberKind memberKind, |
| 1017 {bool lookupClassMember: false}) { | 1022 {bool lookupClassMember: false}) { |
| 1018 if (Elements.isMalformed(element)) { | 1023 if (Elements.isMalformed(element)) { |
| 1019 return const DynamicAccess(); | 1024 return const DynamicAccess(); |
| 1020 } | 1025 } |
| 1021 if (node.receiver != null) { | 1026 if (node.receiver != null) { |
| 1022 Element receiverElement = elements[node.receiver]; | 1027 Element receiverElement = elements[node.receiver]; |
| 1023 if (receiverElement != null) { | 1028 if (receiverElement != null) { |
| 1024 if (receiverElement.isPrefix) { | 1029 if (receiverElement.isPrefix) { |
| 1025 if (node.isConditional) { | 1030 if (node.isConditional) { |
| 1026 // Skip cases like `prefix?.topLevel`. | 1031 // Skip cases like `prefix?.topLevel`. |
| 1027 return const DynamicAccess(); | 1032 return const DynamicAccess(); |
| 1028 } | 1033 } |
| 1029 assert(invariant(node, element != null, | 1034 assert(invariant(node, element != null, |
| 1030 message: 'Prefixed node has no element.')); | 1035 message: 'Prefixed node has no element.')); |
| 1031 return computeResolvedAccess(node, name, element, memberKind); | 1036 return computeResolvedAccess(node, name, element, memberKind); |
| 1032 } | 1037 } |
| 1033 } | 1038 } |
| 1034 // e.foo() for some expression e. | 1039 // e.foo() for some expression e. |
| 1035 DartType receiverType = analyze(node.receiver); | 1040 ResolutionDartType receiverType = analyze(node.receiver); |
| 1036 if (receiverType.treatAsDynamic || receiverType.isVoid) { | 1041 if (receiverType.treatAsDynamic || receiverType.isVoid) { |
| 1037 return const DynamicAccess(); | 1042 return const DynamicAccess(); |
| 1038 } | 1043 } |
| 1039 return lookupMember( | 1044 return lookupMember( |
| 1040 node, receiverType, name, memberKind, elements[node.receiver], | 1045 node, receiverType, name, memberKind, elements[node.receiver], |
| 1041 lookupClassMember: | 1046 lookupClassMember: |
| 1042 lookupClassMember || element != null && element.isStatic); | 1047 lookupClassMember || element != null && element.isStatic); |
| 1043 } else { | 1048 } else { |
| 1044 return computeResolvedAccess(node, name, element, memberKind); | 1049 return computeResolvedAccess(node, name, element, memberKind); |
| 1045 } | 1050 } |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1097 return new PromotedAccess(element, typePromotion.type); | 1102 return new PromotedAccess(element, typePromotion.type); |
| 1098 } | 1103 } |
| 1099 } | 1104 } |
| 1100 return new ResolvedAccess(element); | 1105 return new ResolvedAccess(element); |
| 1101 } | 1106 } |
| 1102 | 1107 |
| 1103 /** | 1108 /** |
| 1104 * Computes the type of the access of [name] on the [node] possibly using the | 1109 * Computes the type of the access of [name] on the [node] possibly using the |
| 1105 * [element] provided for [node] by the resolver. | 1110 * [element] provided for [node] by the resolver. |
| 1106 */ | 1111 */ |
| 1107 DartType computeAccessType( | 1112 ResolutionDartType computeAccessType( |
| 1108 Send node, String name, Element element, MemberKind memberKind, | 1113 Send node, String name, Element element, MemberKind memberKind, |
| 1109 {bool lookupClassMember: false}) { | 1114 {bool lookupClassMember: false}) { |
| 1110 DartType type = computeAccess(node, name, element, memberKind, | 1115 ResolutionDartType type = computeAccess(node, name, element, memberKind, |
| 1111 lookupClassMember: lookupClassMember) | 1116 lookupClassMember: lookupClassMember) |
| 1112 .computeType(resolution); | 1117 .computeType(resolution); |
| 1113 if (type == null) { | 1118 if (type == null) { |
| 1114 reporter.internalError(node, 'Type is null on access of $name on $node.'); | 1119 reporter.internalError(node, 'Type is null on access of $name on $node.'); |
| 1115 } | 1120 } |
| 1116 return type; | 1121 return type; |
| 1117 } | 1122 } |
| 1118 | 1123 |
| 1119 /// Compute a version of [shownType] that is more specific that [knownType]. | 1124 /// Compute a version of [shownType] that is more specific that [knownType]. |
| 1120 /// This is used to provided better hints when trying to promote a supertype | 1125 /// This is used to provided better hints when trying to promote a supertype |
| 1121 /// to a raw subtype. For instance trying to promote `Iterable<int>` to `List` | 1126 /// to a raw subtype. For instance trying to promote `Iterable<int>` to `List` |
| 1122 /// we suggest the use of `List<int>`, which would make promotion valid. | 1127 /// we suggest the use of `List<int>`, which would make promotion valid. |
| 1123 DartType computeMoreSpecificType(DartType shownType, DartType knownType) { | 1128 ResolutionDartType computeMoreSpecificType( |
| 1129 ResolutionDartType shownType, ResolutionDartType knownType) { |
| 1124 if (knownType.isInterfaceType && | 1130 if (knownType.isInterfaceType && |
| 1125 shownType.isInterfaceType && | 1131 shownType.isInterfaceType && |
| 1126 types.isSubtype(shownType.asRaw(), knownType)) { | 1132 types.isSubtype(shownType.asRaw(), knownType)) { |
| 1127 // For the comments in the block, assume the hierarchy: | 1133 // For the comments in the block, assume the hierarchy: |
| 1128 // class A<T, V> {} | 1134 // class A<T, V> {} |
| 1129 // class B<S, U> extends A<S, int> {} | 1135 // class B<S, U> extends A<S, int> {} |
| 1130 // and a promotion from a [knownType] of `A<double, int>` to a | 1136 // and a promotion from a [knownType] of `A<double, int>` to a |
| 1131 // [shownType] of `B`. | 1137 // [shownType] of `B`. |
| 1132 InterfaceType knownInterfaceType = knownType; | 1138 ResolutionInterfaceType knownInterfaceType = knownType; |
| 1133 ClassElement shownClass = shownType.element; | 1139 ClassElement shownClass = shownType.element; |
| 1134 | 1140 |
| 1135 // Compute `B<double, dynamic>` as the subtype of `A<double, int>` using | 1141 // Compute `B<double, dynamic>` as the subtype of `A<double, int>` using |
| 1136 // the relation between `A<S, int>` and `A<double, int>`. | 1142 // the relation between `A<S, int>` and `A<double, int>`. |
| 1137 MoreSpecificSubtypeVisitor visitor = | 1143 MoreSpecificSubtypeVisitor visitor = |
| 1138 new MoreSpecificSubtypeVisitor(types); | 1144 new MoreSpecificSubtypeVisitor(types); |
| 1139 InterfaceType shownTypeGeneric = | 1145 ResolutionInterfaceType shownTypeGeneric = |
| 1140 visitor.computeMoreSpecific(shownClass, knownInterfaceType); | 1146 visitor.computeMoreSpecific(shownClass, knownInterfaceType); |
| 1141 | 1147 |
| 1142 if (shownTypeGeneric != null && | 1148 if (shownTypeGeneric != null && |
| 1143 types.isMoreSpecific(shownTypeGeneric, knownType)) { | 1149 types.isMoreSpecific(shownTypeGeneric, knownType)) { |
| 1144 // This should be the case but we double-check. | 1150 // This should be the case but we double-check. |
| 1145 // TODO(johnniwinther): Ensure that we don't suggest malbounded types. | 1151 // TODO(johnniwinther): Ensure that we don't suggest malbounded types. |
| 1146 return shownTypeGeneric; | 1152 return shownTypeGeneric; |
| 1147 } | 1153 } |
| 1148 } | 1154 } |
| 1149 return null; | 1155 return null; |
| 1150 } | 1156 } |
| 1151 | 1157 |
| 1152 DartType visitSend(Send node) { | 1158 ResolutionDartType visitSend(Send node) { |
| 1153 Element element = elements[node]; | 1159 Element element = elements[node]; |
| 1154 | 1160 |
| 1155 if (element != null && element.isConstructor) { | 1161 if (element != null && element.isConstructor) { |
| 1156 DartType receiverType; | 1162 ResolutionDartType receiverType; |
| 1157 if (node.receiver != null) { | 1163 if (node.receiver != null) { |
| 1158 receiverType = analyze(node.receiver); | 1164 receiverType = analyze(node.receiver); |
| 1159 } else if (node.selector.isSuper()) { | 1165 } else if (node.selector.isSuper()) { |
| 1160 // TODO(johnniwinther): Lookup super-member in class members. | 1166 // TODO(johnniwinther): Lookup super-member in class members. |
| 1161 receiverType = superType; | 1167 receiverType = superType; |
| 1162 } else { | 1168 } else { |
| 1163 assert(node.selector.isThis()); | 1169 assert(node.selector.isThis()); |
| 1164 receiverType = thisType; | 1170 receiverType = thisType; |
| 1165 } | 1171 } |
| 1166 DartType constructorType = computeConstructorType(element, receiverType); | 1172 ResolutionDartType constructorType = |
| 1173 computeConstructorType(element, receiverType); |
| 1167 analyzeArguments(node, element, constructorType); | 1174 analyzeArguments(node, element, constructorType); |
| 1168 return const DynamicType(); | 1175 return const ResolutionDynamicType(); |
| 1169 } | 1176 } |
| 1170 | 1177 |
| 1171 Identifier selector = node.selector.asIdentifier(); | 1178 Identifier selector = node.selector.asIdentifier(); |
| 1172 if (Elements.isClosureSend(node, element)) { | 1179 if (Elements.isClosureSend(node, element)) { |
| 1173 if (element != null) { | 1180 if (element != null) { |
| 1174 if (element.isError) { | 1181 if (element.isError) { |
| 1175 // foo() where foo is erroneous | 1182 // foo() where foo is erroneous |
| 1176 return analyzeInvocation(node, const DynamicAccess()); | 1183 return analyzeInvocation(node, const DynamicAccess()); |
| 1177 } else { | 1184 } else { |
| 1178 assert(invariant(node, element.isLocal, | 1185 assert(invariant(node, element.isLocal, |
| 1179 message: "Unexpected element $element in closure send.")); | 1186 message: "Unexpected element $element in closure send.")); |
| 1180 // foo() where foo is a local or a parameter. | 1187 // foo() where foo is a local or a parameter. |
| 1181 return analyzeInvocation(node, createPromotedAccess(element)); | 1188 return analyzeInvocation(node, createPromotedAccess(element)); |
| 1182 } | 1189 } |
| 1183 } else { | 1190 } else { |
| 1184 // exp() where exp is some complex expression like (o) or foo(). | 1191 // exp() where exp is some complex expression like (o) or foo(). |
| 1185 DartType type = analyze(node.selector); | 1192 ResolutionDartType type = analyze(node.selector); |
| 1186 return analyzeInvocation(node, new TypeAccess(type)); | 1193 return analyzeInvocation(node, new TypeAccess(type)); |
| 1187 } | 1194 } |
| 1188 } else if (Elements.isMalformed(element) && selector == null) { | 1195 } else if (Elements.isMalformed(element) && selector == null) { |
| 1189 // exp() where exp is an erroneous construct like `new Unresolved()`. | 1196 // exp() where exp is an erroneous construct like `new Unresolved()`. |
| 1190 DartType type = analyze(node.selector); | 1197 ResolutionDartType type = analyze(node.selector); |
| 1191 return analyzeInvocation(node, new TypeAccess(type)); | 1198 return analyzeInvocation(node, new TypeAccess(type)); |
| 1192 } | 1199 } |
| 1193 | 1200 |
| 1194 String name = selector.source; | 1201 String name = selector.source; |
| 1195 | 1202 |
| 1196 if (node.isOperator && identical(name, 'is')) { | 1203 if (node.isOperator && identical(name, 'is')) { |
| 1197 analyze(node.receiver); | 1204 analyze(node.receiver); |
| 1198 if (!node.isIsNotCheck) { | 1205 if (!node.isIsNotCheck) { |
| 1199 Element variable = elements[node.receiver]; | 1206 Element variable = elements[node.receiver]; |
| 1200 if (variable == null) { | 1207 if (variable == null) { |
| 1201 // Look for the variable element within parenthesized expressions. | 1208 // Look for the variable element within parenthesized expressions. |
| 1202 ParenthesizedExpression parentheses = | 1209 ParenthesizedExpression parentheses = |
| 1203 node.receiver.asParenthesizedExpression(); | 1210 node.receiver.asParenthesizedExpression(); |
| 1204 while (parentheses != null) { | 1211 while (parentheses != null) { |
| 1205 variable = elements[parentheses.expression]; | 1212 variable = elements[parentheses.expression]; |
| 1206 if (variable != null) break; | 1213 if (variable != null) break; |
| 1207 parentheses = parentheses.expression.asParenthesizedExpression(); | 1214 parentheses = parentheses.expression.asParenthesizedExpression(); |
| 1208 } | 1215 } |
| 1209 } | 1216 } |
| 1210 | 1217 |
| 1211 if (variable != null && (variable.isVariable || variable.isParameter)) { | 1218 if (variable != null && (variable.isVariable || variable.isParameter)) { |
| 1212 DartType knownType = getKnownType(variable); | 1219 ResolutionDartType knownType = getKnownType(variable); |
| 1213 if (!knownType.isDynamic) { | 1220 if (!knownType.isDynamic) { |
| 1214 DartType shownType = elements.getType(node.arguments.head); | 1221 ResolutionDartType shownType = |
| 1222 elements.getType(node.arguments.head); |
| 1215 TypePromotion typePromotion = | 1223 TypePromotion typePromotion = |
| 1216 new TypePromotion(node, variable, shownType); | 1224 new TypePromotion(node, variable, shownType); |
| 1217 if (!types.isMoreSpecific(shownType, knownType)) { | 1225 if (!types.isMoreSpecific(shownType, knownType)) { |
| 1218 String variableName = variable.name; | 1226 String variableName = variable.name; |
| 1219 if (!types.isSubtype(shownType, knownType)) { | 1227 if (!types.isSubtype(shownType, knownType)) { |
| 1220 typePromotion.addHint(reporter.createMessage( | 1228 typePromotion.addHint(reporter.createMessage( |
| 1221 node, MessageKind.NOT_MORE_SPECIFIC_SUBTYPE, { | 1229 node, MessageKind.NOT_MORE_SPECIFIC_SUBTYPE, { |
| 1222 'variableName': variableName, | 1230 'variableName': variableName, |
| 1223 'shownType': shownType, | 1231 'shownType': shownType, |
| 1224 'knownType': knownType | 1232 'knownType': knownType |
| 1225 })); | 1233 })); |
| 1226 } else { | 1234 } else { |
| 1227 DartType shownTypeSuggestion = | 1235 ResolutionDartType shownTypeSuggestion = |
| 1228 computeMoreSpecificType(shownType, knownType); | 1236 computeMoreSpecificType(shownType, knownType); |
| 1229 if (shownTypeSuggestion != null) { | 1237 if (shownTypeSuggestion != null) { |
| 1230 typePromotion.addHint(reporter.createMessage( | 1238 typePromotion.addHint(reporter.createMessage( |
| 1231 node, MessageKind.NOT_MORE_SPECIFIC_SUGGESTION, { | 1239 node, MessageKind.NOT_MORE_SPECIFIC_SUGGESTION, { |
| 1232 'variableName': variableName, | 1240 'variableName': variableName, |
| 1233 'shownType': shownType, | 1241 'shownType': shownType, |
| 1234 'shownTypeSuggestion': shownTypeSuggestion, | 1242 'shownTypeSuggestion': shownTypeSuggestion, |
| 1235 'knownType': knownType | 1243 'knownType': knownType |
| 1236 })); | 1244 })); |
| 1237 } else { | 1245 } else { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1248 } | 1256 } |
| 1249 } | 1257 } |
| 1250 } | 1258 } |
| 1251 return boolType; | 1259 return boolType; |
| 1252 } | 1260 } |
| 1253 if (node.isOperator && identical(name, 'as')) { | 1261 if (node.isOperator && identical(name, 'as')) { |
| 1254 analyze(node.receiver); | 1262 analyze(node.receiver); |
| 1255 return elements.getType(node.arguments.head); | 1263 return elements.getType(node.arguments.head); |
| 1256 } else if (node.isOperator) { | 1264 } else if (node.isOperator) { |
| 1257 final Node receiver = node.receiver; | 1265 final Node receiver = node.receiver; |
| 1258 final DartType receiverType = analyze(receiver); | 1266 final ResolutionDartType receiverType = analyze(receiver); |
| 1259 if (identical(name, '==') || | 1267 if (identical(name, '==') || |
| 1260 identical(name, '!=') | 1268 identical(name, '!=') |
| 1261 // TODO(johnniwinther): Remove these. | 1269 // TODO(johnniwinther): Remove these. |
| 1262 || | 1270 || |
| 1263 identical(name, '===') || | 1271 identical(name, '===') || |
| 1264 identical(name, '!==')) { | 1272 identical(name, '!==')) { |
| 1265 // Analyze argument. | 1273 // Analyze argument. |
| 1266 analyze(node.arguments.head); | 1274 analyze(node.arguments.head); |
| 1267 return boolType; | 1275 return boolType; |
| 1268 } else if (identical(name, '||')) { | 1276 } else if (identical(name, '||')) { |
| 1269 checkAssignable(receiver, receiverType, boolType); | 1277 checkAssignable(receiver, receiverType, boolType); |
| 1270 final Node argument = node.arguments.head; | 1278 final Node argument = node.arguments.head; |
| 1271 final DartType argumentType = analyze(argument); | 1279 final ResolutionDartType argumentType = analyze(argument); |
| 1272 checkAssignable(argument, argumentType, boolType); | 1280 checkAssignable(argument, argumentType, boolType); |
| 1273 return boolType; | 1281 return boolType; |
| 1274 } else if (identical(name, '&&')) { | 1282 } else if (identical(name, '&&')) { |
| 1275 checkAssignable(receiver, receiverType, boolType); | 1283 checkAssignable(receiver, receiverType, boolType); |
| 1276 final Node argument = node.arguments.head; | 1284 final Node argument = node.arguments.head; |
| 1277 | 1285 |
| 1278 final DartType argumentType = | 1286 final ResolutionDartType argumentType = |
| 1279 analyzeInPromotedContext(receiver, argument); | 1287 analyzeInPromotedContext(receiver, argument); |
| 1280 | 1288 |
| 1281 reshowTypePromotions(node, receiver, argument); | 1289 reshowTypePromotions(node, receiver, argument); |
| 1282 | 1290 |
| 1283 checkAssignable(argument, argumentType, boolType); | 1291 checkAssignable(argument, argumentType, boolType); |
| 1284 return boolType; | 1292 return boolType; |
| 1285 } else if (identical(name, '!')) { | 1293 } else if (identical(name, '!')) { |
| 1286 checkAssignable(receiver, receiverType, boolType); | 1294 checkAssignable(receiver, receiverType, boolType); |
| 1287 return boolType; | 1295 return boolType; |
| 1288 } else if (identical(name, '?')) { | 1296 } else if (identical(name, '?')) { |
| 1289 return boolType; | 1297 return boolType; |
| 1290 } else if (identical(name, '??')) { | 1298 } else if (identical(name, '??')) { |
| 1291 final Node argument = node.arguments.head; | 1299 final Node argument = node.arguments.head; |
| 1292 final DartType argumentType = analyze(argument); | 1300 final ResolutionDartType argumentType = analyze(argument); |
| 1293 return types.computeLeastUpperBound(receiverType, argumentType); | 1301 return types.computeLeastUpperBound(receiverType, argumentType); |
| 1294 } | 1302 } |
| 1295 String operatorName = selector.source; | 1303 String operatorName = selector.source; |
| 1296 if (identical(name, '-') && node.arguments.isEmpty) { | 1304 if (identical(name, '-') && node.arguments.isEmpty) { |
| 1297 operatorName = 'unary-'; | 1305 operatorName = 'unary-'; |
| 1298 } | 1306 } |
| 1299 assert(invariant( | 1307 assert(invariant( |
| 1300 node, | 1308 node, |
| 1301 identical(name, '+') || | 1309 identical(name, '+') || |
| 1302 identical(name, '=') || | 1310 identical(name, '=') || |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1317 identical(name, '>=') || | 1325 identical(name, '>=') || |
| 1318 identical(name, '[]'), | 1326 identical(name, '[]'), |
| 1319 message: 'Unexpected operator $name')); | 1327 message: 'Unexpected operator $name')); |
| 1320 | 1328 |
| 1321 // TODO(karlklose): handle `void` in expression context by calling | 1329 // TODO(karlklose): handle `void` in expression context by calling |
| 1322 // [analyzeNonVoid] instead of [analyze]. | 1330 // [analyzeNonVoid] instead of [analyze]. |
| 1323 ElementAccess access = receiverType.isVoid | 1331 ElementAccess access = receiverType.isVoid |
| 1324 ? const DynamicAccess() | 1332 ? const DynamicAccess() |
| 1325 : lookupMember( | 1333 : lookupMember( |
| 1326 node, receiverType, operatorName, MemberKind.OPERATOR, null); | 1334 node, receiverType, operatorName, MemberKind.OPERATOR, null); |
| 1327 LinkBuilder<DartType> argumentTypesBuilder = new LinkBuilder<DartType>(); | 1335 LinkBuilder<ResolutionDartType> argumentTypesBuilder = |
| 1328 DartType resultType = | 1336 new LinkBuilder<ResolutionDartType>(); |
| 1337 ResolutionDartType resultType = |
| 1329 analyzeInvocation(node, access, argumentTypesBuilder); | 1338 analyzeInvocation(node, access, argumentTypesBuilder); |
| 1330 if (receiverType == intType) { | 1339 if (receiverType == intType) { |
| 1331 if (identical(name, '+') || | 1340 if (identical(name, '+') || |
| 1332 identical(operatorName, '-') || | 1341 identical(operatorName, '-') || |
| 1333 identical(name, '*') || | 1342 identical(name, '*') || |
| 1334 identical(name, '%')) { | 1343 identical(name, '%')) { |
| 1335 DartType argumentType = argumentTypesBuilder.toLink().head; | 1344 ResolutionDartType argumentType = argumentTypesBuilder.toLink().head; |
| 1336 if (argumentType == intType) { | 1345 if (argumentType == intType) { |
| 1337 return intType; | 1346 return intType; |
| 1338 } else if (argumentType == doubleType) { | 1347 } else if (argumentType == doubleType) { |
| 1339 return doubleType; | 1348 return doubleType; |
| 1340 } | 1349 } |
| 1341 } | 1350 } |
| 1342 } | 1351 } |
| 1343 return resultType; | 1352 return resultType; |
| 1344 } else if (node.isPropertyAccess) { | 1353 } else if (node.isPropertyAccess) { |
| 1345 ElementAccess access = | 1354 ElementAccess access = |
| 1346 computeAccess(node, selector.source, element, MemberKind.GETTER); | 1355 computeAccess(node, selector.source, element, MemberKind.GETTER); |
| 1347 return access.computeType(resolution); | 1356 return access.computeType(resolution); |
| 1348 } else if (node.isFunctionObjectInvocation) { | 1357 } else if (node.isFunctionObjectInvocation) { |
| 1349 return unhandledExpression(); | 1358 return unhandledExpression(); |
| 1350 } else { | 1359 } else { |
| 1351 ElementAccess access = | 1360 ElementAccess access = |
| 1352 computeAccess(node, selector.source, element, MemberKind.METHOD); | 1361 computeAccess(node, selector.source, element, MemberKind.METHOD); |
| 1353 return analyzeInvocation(node, access); | 1362 return analyzeInvocation(node, access); |
| 1354 } | 1363 } |
| 1355 } | 1364 } |
| 1356 | 1365 |
| 1357 /// Returns the first type in the list or [:dynamic:] if the list is empty. | 1366 /// Returns the first type in the list or [:dynamic:] if the list is empty. |
| 1358 DartType firstType(List<DartType> list) { | 1367 ResolutionDartType firstType(List<ResolutionDartType> list) { |
| 1359 return list.isEmpty ? const DynamicType() : list.first; | 1368 return list.isEmpty ? const ResolutionDynamicType() : list.first; |
| 1360 } | 1369 } |
| 1361 | 1370 |
| 1362 /** | 1371 /** |
| 1363 * Returns the second type in the list or [:dynamic:] if the list is too | 1372 * Returns the second type in the list or [:dynamic:] if the list is too |
| 1364 * short. | 1373 * short. |
| 1365 */ | 1374 */ |
| 1366 DartType secondType(List<DartType> list) { | 1375 ResolutionDartType secondType(List<ResolutionDartType> list) { |
| 1367 return list.length < 2 ? const DynamicType() : list[1]; | 1376 return list.length < 2 ? const ResolutionDynamicType() : list[1]; |
| 1368 } | 1377 } |
| 1369 | 1378 |
| 1370 /** | 1379 /** |
| 1371 * Checks [: target o= value :] for some operator o, and returns the type | 1380 * Checks [: target o= value :] for some operator o, and returns the type |
| 1372 * of the result. This method also handles increment/decrement expressions | 1381 * of the result. This method also handles increment/decrement expressions |
| 1373 * like [: target++ :]. | 1382 * like [: target++ :]. |
| 1374 */ | 1383 */ |
| 1375 DartType checkAssignmentOperator( | 1384 ResolutionDartType checkAssignmentOperator(SendSet node, String operatorName, |
| 1376 SendSet node, String operatorName, Node valueNode, DartType value) { | 1385 Node valueNode, ResolutionDartType value) { |
| 1377 assert(invariant(node, !node.isIndex)); | 1386 assert(invariant(node, !node.isIndex)); |
| 1378 Element setterElement = elements[node]; | 1387 Element setterElement = elements[node]; |
| 1379 Element getterElement = elements[node.selector]; | 1388 Element getterElement = elements[node.selector]; |
| 1380 Identifier selector = node.selector; | 1389 Identifier selector = node.selector; |
| 1381 DartType getter = computeAccessType( | 1390 ResolutionDartType getter = computeAccessType( |
| 1382 node, selector.source, getterElement, MemberKind.GETTER); | 1391 node, selector.source, getterElement, MemberKind.GETTER); |
| 1383 DartType setter = computeAccessType( | 1392 ResolutionDartType setter = computeAccessType( |
| 1384 node, selector.source, setterElement, MemberKind.SETTER); | 1393 node, selector.source, setterElement, MemberKind.SETTER); |
| 1385 // [operator] is the type of operator+ or operator- on [target]. | 1394 // [operator] is the type of operator+ or operator- on [target]. |
| 1386 DartType operator = | 1395 ResolutionDartType operator = |
| 1387 lookupMemberType(node, getter, operatorName, MemberKind.OPERATOR); | 1396 lookupMemberType(node, getter, operatorName, MemberKind.OPERATOR); |
| 1388 if (operator is FunctionType) { | 1397 if (operator is ResolutionFunctionType) { |
| 1389 FunctionType operatorType = operator; | 1398 ResolutionFunctionType operatorType = operator; |
| 1390 // [result] is the type of target o value. | 1399 // [result] is the type of target o value. |
| 1391 DartType result = operatorType.returnType; | 1400 ResolutionDartType result = operatorType.returnType; |
| 1392 DartType operatorArgument = firstType(operatorType.parameterTypes); | 1401 ResolutionDartType operatorArgument = |
| 1402 firstType(operatorType.parameterTypes); |
| 1393 // Check target o value. | 1403 // Check target o value. |
| 1394 bool validValue = checkAssignable(valueNode, value, operatorArgument); | 1404 bool validValue = checkAssignable(valueNode, value, operatorArgument); |
| 1395 if (validValue || !(node.isPrefix || node.isPostfix)) { | 1405 if (validValue || !(node.isPrefix || node.isPostfix)) { |
| 1396 // Check target = result. | 1406 // Check target = result. |
| 1397 checkAssignable(node.assignmentOperator, result, setter); | 1407 checkAssignable(node.assignmentOperator, result, setter); |
| 1398 } | 1408 } |
| 1399 return node.isPostfix ? getter : result; | 1409 return node.isPostfix ? getter : result; |
| 1400 } | 1410 } |
| 1401 return const DynamicType(); | 1411 return const ResolutionDynamicType(); |
| 1402 } | 1412 } |
| 1403 | 1413 |
| 1404 /** | 1414 /** |
| 1405 * Checks [: base[key] o= value :] for some operator o, and returns the type | 1415 * Checks [: base[key] o= value :] for some operator o, and returns the type |
| 1406 * of the result. This method also handles increment/decrement expressions | 1416 * of the result. This method also handles increment/decrement expressions |
| 1407 * like [: base[key]++ :]. | 1417 * like [: base[key]++ :]. |
| 1408 */ | 1418 */ |
| 1409 DartType checkIndexAssignmentOperator( | 1419 ResolutionDartType checkIndexAssignmentOperator(SendSet node, |
| 1410 SendSet node, String operatorName, Node valueNode, DartType value) { | 1420 String operatorName, Node valueNode, ResolutionDartType value) { |
| 1411 assert(invariant(node, node.isIndex)); | 1421 assert(invariant(node, node.isIndex)); |
| 1412 final DartType base = analyze(node.receiver); | 1422 final ResolutionDartType base = analyze(node.receiver); |
| 1413 final Node keyNode = node.arguments.head; | 1423 final Node keyNode = node.arguments.head; |
| 1414 final DartType key = analyze(keyNode); | 1424 final ResolutionDartType key = analyze(keyNode); |
| 1415 | 1425 |
| 1416 // [indexGet] is the type of operator[] on [base]. | 1426 // [indexGet] is the type of operator[] on [base]. |
| 1417 DartType indexGet = lookupMemberType(node, base, '[]', MemberKind.OPERATOR); | 1427 ResolutionDartType indexGet = |
| 1418 if (indexGet is FunctionType) { | 1428 lookupMemberType(node, base, '[]', MemberKind.OPERATOR); |
| 1419 FunctionType indexGetType = indexGet; | 1429 if (indexGet is ResolutionFunctionType) { |
| 1420 DartType indexGetKey = firstType(indexGetType.parameterTypes); | 1430 ResolutionFunctionType indexGetType = indexGet; |
| 1431 ResolutionDartType indexGetKey = firstType(indexGetType.parameterTypes); |
| 1421 // Check base[key]. | 1432 // Check base[key]. |
| 1422 bool validKey = checkAssignable(keyNode, key, indexGetKey); | 1433 bool validKey = checkAssignable(keyNode, key, indexGetKey); |
| 1423 | 1434 |
| 1424 // [element] is the type of base[key]. | 1435 // [element] is the type of base[key]. |
| 1425 DartType element = indexGetType.returnType; | 1436 ResolutionDartType element = indexGetType.returnType; |
| 1426 // [operator] is the type of operator o on [element]. | 1437 // [operator] is the type of operator o on [element]. |
| 1427 DartType operator = | 1438 ResolutionDartType operator = |
| 1428 lookupMemberType(node, element, operatorName, MemberKind.OPERATOR); | 1439 lookupMemberType(node, element, operatorName, MemberKind.OPERATOR); |
| 1429 if (operator is FunctionType) { | 1440 if (operator is ResolutionFunctionType) { |
| 1430 FunctionType operatorType = operator; | 1441 ResolutionFunctionType operatorType = operator; |
| 1431 | 1442 |
| 1432 // Check base[key] o value. | 1443 // Check base[key] o value. |
| 1433 DartType operatorArgument = firstType(operatorType.parameterTypes); | 1444 ResolutionDartType operatorArgument = |
| 1445 firstType(operatorType.parameterTypes); |
| 1434 bool validValue = checkAssignable(valueNode, value, operatorArgument); | 1446 bool validValue = checkAssignable(valueNode, value, operatorArgument); |
| 1435 | 1447 |
| 1436 // [result] is the type of base[key] o value. | 1448 // [result] is the type of base[key] o value. |
| 1437 DartType result = operatorType.returnType; | 1449 ResolutionDartType result = operatorType.returnType; |
| 1438 | 1450 |
| 1439 // [indexSet] is the type of operator[]= on [base]. | 1451 // [indexSet] is the type of operator[]= on [base]. |
| 1440 DartType indexSet = | 1452 ResolutionDartType indexSet = |
| 1441 lookupMemberType(node, base, '[]=', MemberKind.OPERATOR); | 1453 lookupMemberType(node, base, '[]=', MemberKind.OPERATOR); |
| 1442 if (indexSet is FunctionType) { | 1454 if (indexSet is ResolutionFunctionType) { |
| 1443 FunctionType indexSetType = indexSet; | 1455 ResolutionFunctionType indexSetType = indexSet; |
| 1444 DartType indexSetKey = firstType(indexSetType.parameterTypes); | 1456 ResolutionDartType indexSetKey = |
| 1445 DartType indexSetValue = secondType(indexSetType.parameterTypes); | 1457 firstType(indexSetType.parameterTypes); |
| 1458 ResolutionDartType indexSetValue = |
| 1459 secondType(indexSetType.parameterTypes); |
| 1446 | 1460 |
| 1447 if (validKey || indexGetKey != indexSetKey) { | 1461 if (validKey || indexGetKey != indexSetKey) { |
| 1448 // Only check base[key] on []= if base[key] was valid for [] or | 1462 // Only check base[key] on []= if base[key] was valid for [] or |
| 1449 // if the key types differ. | 1463 // if the key types differ. |
| 1450 checkAssignable(keyNode, key, indexSetKey); | 1464 checkAssignable(keyNode, key, indexSetKey); |
| 1451 } | 1465 } |
| 1452 // Check base[key] = result | 1466 // Check base[key] = result |
| 1453 if (validValue || !(node.isPrefix || node.isPostfix)) { | 1467 if (validValue || !(node.isPrefix || node.isPostfix)) { |
| 1454 checkAssignable(node.assignmentOperator, result, indexSetValue); | 1468 checkAssignable(node.assignmentOperator, result, indexSetValue); |
| 1455 } | 1469 } |
| 1456 } | 1470 } |
| 1457 return node.isPostfix ? element : result; | 1471 return node.isPostfix ? element : result; |
| 1458 } | 1472 } |
| 1459 } | 1473 } |
| 1460 return const DynamicType(); | 1474 return const ResolutionDynamicType(); |
| 1461 } | 1475 } |
| 1462 | 1476 |
| 1463 visitSendSet(SendSet node) { | 1477 visitSendSet(SendSet node) { |
| 1464 Element element = elements[node]; | 1478 Element element = elements[node]; |
| 1465 Identifier selector = node.selector; | 1479 Identifier selector = node.selector; |
| 1466 final name = node.assignmentOperator.source; | 1480 final name = node.assignmentOperator.source; |
| 1467 if (identical(name, '=') || identical(name, '??=')) { | 1481 if (identical(name, '=') || identical(name, '??=')) { |
| 1468 // e1 = value | 1482 // e1 = value |
| 1469 if (node.isIndex) { | 1483 if (node.isIndex) { |
| 1470 // base[key] = value | 1484 // base[key] = value |
| 1471 final DartType base = analyze(node.receiver); | 1485 final ResolutionDartType base = analyze(node.receiver); |
| 1472 final Node keyNode = node.arguments.head; | 1486 final Node keyNode = node.arguments.head; |
| 1473 final DartType key = analyze(keyNode); | 1487 final ResolutionDartType key = analyze(keyNode); |
| 1474 final Node valueNode = node.arguments.tail.head; | 1488 final Node valueNode = node.arguments.tail.head; |
| 1475 final DartType value = analyze(valueNode); | 1489 final ResolutionDartType value = analyze(valueNode); |
| 1476 DartType indexSet = | 1490 ResolutionDartType indexSet = |
| 1477 lookupMemberType(node, base, '[]=', MemberKind.OPERATOR); | 1491 lookupMemberType(node, base, '[]=', MemberKind.OPERATOR); |
| 1478 DartType indexSetValue = const DynamicType(); | 1492 ResolutionDartType indexSetValue = const ResolutionDynamicType(); |
| 1479 if (indexSet is FunctionType) { | 1493 if (indexSet is ResolutionFunctionType) { |
| 1480 FunctionType indexSetType = indexSet; | 1494 ResolutionFunctionType indexSetType = indexSet; |
| 1481 DartType indexSetKey = firstType(indexSetType.parameterTypes); | 1495 ResolutionDartType indexSetKey = |
| 1496 firstType(indexSetType.parameterTypes); |
| 1482 checkAssignable(keyNode, key, indexSetKey); | 1497 checkAssignable(keyNode, key, indexSetKey); |
| 1483 indexSetValue = secondType(indexSetType.parameterTypes); | 1498 indexSetValue = secondType(indexSetType.parameterTypes); |
| 1484 checkAssignable(node.assignmentOperator, value, indexSetValue); | 1499 checkAssignable(node.assignmentOperator, value, indexSetValue); |
| 1485 } | 1500 } |
| 1486 return identical(name, '=') | 1501 return identical(name, '=') |
| 1487 ? value | 1502 ? value |
| 1488 : types.computeLeastUpperBound(value, indexSetValue); | 1503 : types.computeLeastUpperBound(value, indexSetValue); |
| 1489 } else { | 1504 } else { |
| 1490 // target = value | 1505 // target = value |
| 1491 DartType target; | 1506 ResolutionDartType target; |
| 1492 if (analyzingInitializer) { | 1507 if (analyzingInitializer) { |
| 1493 // Field declaration `Foo target = value;` or initializer | 1508 // Field declaration `Foo target = value;` or initializer |
| 1494 // `this.target = value`. Lookup the getter `target` in the class | 1509 // `this.target = value`. Lookup the getter `target` in the class |
| 1495 // members. | 1510 // members. |
| 1496 target = computeAccessType( | 1511 target = computeAccessType( |
| 1497 node, selector.source, element, MemberKind.GETTER, | 1512 node, selector.source, element, MemberKind.GETTER, |
| 1498 lookupClassMember: true); | 1513 lookupClassMember: true); |
| 1499 } else { | 1514 } else { |
| 1500 // Normal assignment `target = value`. | 1515 // Normal assignment `target = value`. |
| 1501 target = computeAccessType( | 1516 target = computeAccessType( |
| 1502 node, selector.source, element, MemberKind.SETTER); | 1517 node, selector.source, element, MemberKind.SETTER); |
| 1503 } | 1518 } |
| 1504 final Node valueNode = node.arguments.head; | 1519 final Node valueNode = node.arguments.head; |
| 1505 final DartType value = analyze(valueNode); | 1520 final ResolutionDartType value = analyze(valueNode); |
| 1506 checkAssignable(node.assignmentOperator, value, target); | 1521 checkAssignable(node.assignmentOperator, value, target); |
| 1507 return identical(name, '=') | 1522 return identical(name, '=') |
| 1508 ? value | 1523 ? value |
| 1509 : types.computeLeastUpperBound(value, target); | 1524 : types.computeLeastUpperBound(value, target); |
| 1510 } | 1525 } |
| 1511 } else if (identical(name, '++') || identical(name, '--')) { | 1526 } else if (identical(name, '++') || identical(name, '--')) { |
| 1512 // e++ or e-- | 1527 // e++ or e-- |
| 1513 String operatorName = identical(name, '++') ? '+' : '-'; | 1528 String operatorName = identical(name, '++') ? '+' : '-'; |
| 1514 if (node.isIndex) { | 1529 if (node.isIndex) { |
| 1515 // base[key]++, base[key]--, ++base[key], or --base[key] | 1530 // base[key]++, base[key]--, ++base[key], or --base[key] |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1556 break; | 1571 break; |
| 1557 case '>>=': | 1572 case '>>=': |
| 1558 operatorName = '>>'; | 1573 operatorName = '>>'; |
| 1559 break; | 1574 break; |
| 1560 default: | 1575 default: |
| 1561 reporter.internalError(node, 'Unexpected assignment operator $name.'); | 1576 reporter.internalError(node, 'Unexpected assignment operator $name.'); |
| 1562 } | 1577 } |
| 1563 if (node.isIndex) { | 1578 if (node.isIndex) { |
| 1564 // base[key] o= value for some operator o. | 1579 // base[key] o= value for some operator o. |
| 1565 final Node valueNode = node.arguments.tail.head; | 1580 final Node valueNode = node.arguments.tail.head; |
| 1566 final DartType value = analyze(valueNode); | 1581 final ResolutionDartType value = analyze(valueNode); |
| 1567 return checkIndexAssignmentOperator( | 1582 return checkIndexAssignmentOperator( |
| 1568 node, operatorName, valueNode, value); | 1583 node, operatorName, valueNode, value); |
| 1569 } else { | 1584 } else { |
| 1570 // target o= value for some operator o. | 1585 // target o= value for some operator o. |
| 1571 final Node valueNode = node.arguments.head; | 1586 final Node valueNode = node.arguments.head; |
| 1572 final DartType value = analyze(valueNode); | 1587 final ResolutionDartType value = analyze(valueNode); |
| 1573 return checkAssignmentOperator(node, operatorName, valueNode, value); | 1588 return checkAssignmentOperator(node, operatorName, valueNode, value); |
| 1574 } | 1589 } |
| 1575 } | 1590 } |
| 1576 } | 1591 } |
| 1577 | 1592 |
| 1578 DartType visitLiteralInt(LiteralInt node) { | 1593 ResolutionDartType visitLiteralInt(LiteralInt node) { |
| 1579 return intType; | 1594 return intType; |
| 1580 } | 1595 } |
| 1581 | 1596 |
| 1582 DartType visitLiteralDouble(LiteralDouble node) { | 1597 ResolutionDartType visitLiteralDouble(LiteralDouble node) { |
| 1583 return doubleType; | 1598 return doubleType; |
| 1584 } | 1599 } |
| 1585 | 1600 |
| 1586 DartType visitLiteralBool(LiteralBool node) { | 1601 ResolutionDartType visitLiteralBool(LiteralBool node) { |
| 1587 return boolType; | 1602 return boolType; |
| 1588 } | 1603 } |
| 1589 | 1604 |
| 1590 DartType visitLiteralString(LiteralString node) { | 1605 ResolutionDartType visitLiteralString(LiteralString node) { |
| 1591 return stringType; | 1606 return stringType; |
| 1592 } | 1607 } |
| 1593 | 1608 |
| 1594 DartType visitStringJuxtaposition(StringJuxtaposition node) { | 1609 ResolutionDartType visitStringJuxtaposition(StringJuxtaposition node) { |
| 1595 analyze(node.first); | 1610 analyze(node.first); |
| 1596 analyze(node.second); | 1611 analyze(node.second); |
| 1597 return stringType; | 1612 return stringType; |
| 1598 } | 1613 } |
| 1599 | 1614 |
| 1600 DartType visitLiteralNull(LiteralNull node) { | 1615 ResolutionDartType visitLiteralNull(LiteralNull node) { |
| 1601 return const DynamicType(); | 1616 return const ResolutionDynamicType(); |
| 1602 } | 1617 } |
| 1603 | 1618 |
| 1604 DartType visitLiteralSymbol(LiteralSymbol node) { | 1619 ResolutionDartType visitLiteralSymbol(LiteralSymbol node) { |
| 1605 return commonElements.symbolType; | 1620 return commonElements.symbolType; |
| 1606 } | 1621 } |
| 1607 | 1622 |
| 1608 DartType computeConstructorType( | 1623 ResolutionDartType computeConstructorType( |
| 1609 ConstructorElement constructor, DartType type) { | 1624 ConstructorElement constructor, ResolutionDartType type) { |
| 1610 if (Elements.isUnresolved(constructor)) return const DynamicType(); | 1625 if (Elements.isUnresolved(constructor)) |
| 1611 DartType constructorType = constructor.computeType(resolution); | 1626 return const ResolutionDynamicType(); |
| 1612 if (identical(type.kind, TypeKind.INTERFACE)) { | 1627 ResolutionDartType constructorType = constructor.computeType(resolution); |
| 1628 if (identical(type.kind, ResolutionTypeKind.INTERFACE)) { |
| 1613 if (constructor.isSynthesized) { | 1629 if (constructor.isSynthesized) { |
| 1614 // TODO(johnniwinther): Remove this when synthesized constructors handle | 1630 // TODO(johnniwinther): Remove this when synthesized constructors handle |
| 1615 // type variables correctly. | 1631 // type variables correctly. |
| 1616 InterfaceType interfaceType = type; | 1632 ResolutionInterfaceType interfaceType = type; |
| 1617 ClassElement receiverElement = interfaceType.element; | 1633 ClassElement receiverElement = interfaceType.element; |
| 1618 while (receiverElement.isMixinApplication) { | 1634 while (receiverElement.isMixinApplication) { |
| 1619 receiverElement = receiverElement.supertype.element; | 1635 receiverElement = receiverElement.supertype.element; |
| 1620 } | 1636 } |
| 1621 constructorType = constructorType | 1637 constructorType = constructorType |
| 1622 .substByContext(interfaceType.asInstanceOf(receiverElement)); | 1638 .substByContext(interfaceType.asInstanceOf(receiverElement)); |
| 1623 } else { | 1639 } else { |
| 1624 constructorType = constructorType.substByContext(type); | 1640 constructorType = constructorType.substByContext(type); |
| 1625 } | 1641 } |
| 1626 } | 1642 } |
| 1627 return constructorType; | 1643 return constructorType; |
| 1628 } | 1644 } |
| 1629 | 1645 |
| 1630 DartType visitNewExpression(NewExpression node) { | 1646 ResolutionDartType visitNewExpression(NewExpression node) { |
| 1631 Element element = elements[node.send]; | 1647 Element element = elements[node.send]; |
| 1632 if (Elements.isUnresolved(element)) return const DynamicType(); | 1648 if (Elements.isUnresolved(element)) return const ResolutionDynamicType(); |
| 1633 | 1649 |
| 1634 checkPrivateAccess(node, element, element.name); | 1650 checkPrivateAccess(node, element, element.name); |
| 1635 | 1651 |
| 1636 DartType newType = elements.getType(node); | 1652 ResolutionDartType newType = elements.getType(node); |
| 1637 assert(invariant(node, newType != null, | 1653 assert(invariant(node, newType != null, |
| 1638 message: "No new type registered in $elements.")); | 1654 message: "No new type registered in $elements.")); |
| 1639 DartType constructorType = computeConstructorType(element, newType); | 1655 ResolutionDartType constructorType = |
| 1656 computeConstructorType(element, newType); |
| 1640 analyzeArguments(node.send, element, constructorType); | 1657 analyzeArguments(node.send, element, constructorType); |
| 1641 return newType; | 1658 return newType; |
| 1642 } | 1659 } |
| 1643 | 1660 |
| 1644 DartType visitLiteralList(LiteralList node) { | 1661 ResolutionDartType visitLiteralList(LiteralList node) { |
| 1645 InterfaceType listType = elements.getType(node); | 1662 ResolutionInterfaceType listType = elements.getType(node); |
| 1646 DartType listElementType = firstType(listType.typeArguments); | 1663 ResolutionDartType listElementType = firstType(listType.typeArguments); |
| 1647 for (Link<Node> link = node.elements.nodes; | 1664 for (Link<Node> link = node.elements.nodes; |
| 1648 !link.isEmpty; | 1665 !link.isEmpty; |
| 1649 link = link.tail) { | 1666 link = link.tail) { |
| 1650 Node element = link.head; | 1667 Node element = link.head; |
| 1651 DartType elementType = analyze(element); | 1668 ResolutionDartType elementType = analyze(element); |
| 1652 checkAssignable(element, elementType, listElementType, | 1669 checkAssignable(element, elementType, listElementType, |
| 1653 isConst: node.isConst); | 1670 isConst: node.isConst); |
| 1654 } | 1671 } |
| 1655 return listType; | 1672 return listType; |
| 1656 } | 1673 } |
| 1657 | 1674 |
| 1658 visitNodeList(NodeList node) { | 1675 visitNodeList(NodeList node) { |
| 1659 for (Link<Node> link = node.nodes; !link.isEmpty; link = link.tail) { | 1676 for (Link<Node> link = node.nodes; !link.isEmpty; link = link.tail) { |
| 1660 analyzeUntyped(link.head, inInitializer: analyzingInitializer); | 1677 analyzeUntyped(link.head, inInitializer: analyzingInitializer); |
| 1661 } | 1678 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1675 if (identical(node.beginToken.stringValue, 'native')) { | 1692 if (identical(node.beginToken.stringValue, 'native')) { |
| 1676 return; | 1693 return; |
| 1677 } | 1694 } |
| 1678 | 1695 |
| 1679 final Node expression = node.expression; | 1696 final Node expression = node.expression; |
| 1680 | 1697 |
| 1681 // Executing a return statement return e; [...] It is a static type warning | 1698 // Executing a return statement return e; [...] It is a static type warning |
| 1682 // if the type of e may not be assigned to the declared return type of the | 1699 // if the type of e may not be assigned to the declared return type of the |
| 1683 // immediately enclosing function. | 1700 // immediately enclosing function. |
| 1684 if (expression != null) { | 1701 if (expression != null) { |
| 1685 DartType expressionType = analyze(expression); | 1702 ResolutionDartType expressionType = analyze(expression); |
| 1686 if (executableContext.isGenerativeConstructor) { | 1703 if (executableContext.isGenerativeConstructor) { |
| 1687 // The resolver already emitted an error for this expression. | 1704 // The resolver already emitted an error for this expression. |
| 1688 } else { | 1705 } else { |
| 1689 if (currentAsyncMarker == AsyncMarker.ASYNC) { | 1706 if (currentAsyncMarker == AsyncMarker.ASYNC) { |
| 1690 expressionType = | 1707 expressionType = |
| 1691 commonElements.futureType(types.flatten(expressionType)); | 1708 commonElements.futureType(types.flatten(expressionType)); |
| 1692 } | 1709 } |
| 1693 if (expectedReturnType.isVoid && | 1710 if (expectedReturnType.isVoid && |
| 1694 !types.isAssignable(expressionType, const VoidType())) { | 1711 !types.isAssignable(expressionType, const ResolutionVoidType())) { |
| 1695 reportTypeWarning(expression, MessageKind.RETURN_VALUE_IN_VOID); | 1712 reportTypeWarning(expression, MessageKind.RETURN_VALUE_IN_VOID); |
| 1696 } else { | 1713 } else { |
| 1697 checkAssignable(expression, expressionType, expectedReturnType); | 1714 checkAssignable(expression, expressionType, expectedReturnType); |
| 1698 } | 1715 } |
| 1699 } | 1716 } |
| 1700 } else if (currentAsyncMarker != AsyncMarker.SYNC) { | 1717 } else if (currentAsyncMarker != AsyncMarker.SYNC) { |
| 1701 // `return;` is allowed. | 1718 // `return;` is allowed. |
| 1702 } else if (!types.isAssignable(expectedReturnType, const VoidType())) { | 1719 } else if (!types.isAssignable( |
| 1720 expectedReturnType, const ResolutionVoidType())) { |
| 1703 // Let f be the function immediately enclosing a return statement of the | 1721 // Let f be the function immediately enclosing a return statement of the |
| 1704 // form 'return;' It is a static warning if both of the following | 1722 // form 'return;' It is a static warning if both of the following |
| 1705 // conditions hold: | 1723 // conditions hold: |
| 1706 // - f is not a generative constructor. | 1724 // - f is not a generative constructor. |
| 1707 // - The return type of f may not be assigned to void. | 1725 // - The return type of f may not be assigned to void. |
| 1708 reportTypeWarning( | 1726 reportTypeWarning( |
| 1709 node, MessageKind.RETURN_NOTHING, {'returnType': expectedReturnType}); | 1727 node, MessageKind.RETURN_NOTHING, {'returnType': expectedReturnType}); |
| 1710 } | 1728 } |
| 1711 } | 1729 } |
| 1712 | 1730 |
| 1713 DartType visitThrow(Throw node) { | 1731 ResolutionDartType visitThrow(Throw node) { |
| 1714 // TODO(johnniwinther): Handle reachability. | 1732 // TODO(johnniwinther): Handle reachability. |
| 1715 analyze(node.expression); | 1733 analyze(node.expression); |
| 1716 return const DynamicType(); | 1734 return const ResolutionDynamicType(); |
| 1717 } | 1735 } |
| 1718 | 1736 |
| 1719 DartType visitAwait(Await node) { | 1737 ResolutionDartType visitAwait(Await node) { |
| 1720 DartType expressionType = analyze(node.expression); | 1738 ResolutionDartType expressionType = analyze(node.expression); |
| 1721 if (resolution.target.supportsAsyncAwait) { | 1739 if (resolution.target.supportsAsyncAwait) { |
| 1722 return types.flatten(expressionType); | 1740 return types.flatten(expressionType); |
| 1723 } else { | 1741 } else { |
| 1724 return const DynamicType(); | 1742 return const ResolutionDynamicType(); |
| 1725 } | 1743 } |
| 1726 } | 1744 } |
| 1727 | 1745 |
| 1728 DartType visitYield(Yield node) { | 1746 ResolutionDartType visitYield(Yield node) { |
| 1729 DartType resultType = analyze(node.expression); | 1747 ResolutionDartType resultType = analyze(node.expression); |
| 1730 if (!node.hasStar) { | 1748 if (!node.hasStar) { |
| 1731 if (currentAsyncMarker.isAsync) { | 1749 if (currentAsyncMarker.isAsync) { |
| 1732 resultType = commonElements.streamType(resultType); | 1750 resultType = commonElements.streamType(resultType); |
| 1733 } else { | 1751 } else { |
| 1734 resultType = commonElements.iterableType(resultType); | 1752 resultType = commonElements.iterableType(resultType); |
| 1735 } | 1753 } |
| 1736 } else { | 1754 } else { |
| 1737 if (currentAsyncMarker.isAsync) { | 1755 if (currentAsyncMarker.isAsync) { |
| 1738 // The static type of expression must be assignable to Stream. | 1756 // The static type of expression must be assignable to Stream. |
| 1739 checkAssignable(node, resultType, commonElements.streamType()); | 1757 checkAssignable(node, resultType, commonElements.streamType()); |
| 1740 } else { | 1758 } else { |
| 1741 // The static type of expression must be assignable to Iterable. | 1759 // The static type of expression must be assignable to Iterable. |
| 1742 checkAssignable(node, resultType, commonElements.iterableType()); | 1760 checkAssignable(node, resultType, commonElements.iterableType()); |
| 1743 } | 1761 } |
| 1744 } | 1762 } |
| 1745 // The static type of the result must be assignable to the declared type. | 1763 // The static type of the result must be assignable to the declared type. |
| 1746 checkAssignable(node, resultType, expectedReturnType); | 1764 checkAssignable(node, resultType, expectedReturnType); |
| 1747 } | 1765 } |
| 1748 | 1766 |
| 1749 DartType visitTypeAnnotation(TypeAnnotation node) { | 1767 ResolutionDartType visitTypeAnnotation(TypeAnnotation node) { |
| 1750 return elements.getType(node); | 1768 return elements.getType(node); |
| 1751 } | 1769 } |
| 1752 | 1770 |
| 1753 DartType analyzeVariableTypeAnnotation(VariableDefinitions node) { | 1771 ResolutionDartType analyzeVariableTypeAnnotation(VariableDefinitions node) { |
| 1754 DartType type = analyzeWithDefault(node.type, const DynamicType()); | 1772 ResolutionDartType type = |
| 1773 analyzeWithDefault(node.type, const ResolutionDynamicType()); |
| 1755 if (type.isVoid) { | 1774 if (type.isVoid) { |
| 1756 reportTypeWarning(node.type, MessageKind.VOID_VARIABLE); | 1775 reportTypeWarning(node.type, MessageKind.VOID_VARIABLE); |
| 1757 type = const DynamicType(); | 1776 type = const ResolutionDynamicType(); |
| 1758 } | 1777 } |
| 1759 return type; | 1778 return type; |
| 1760 } | 1779 } |
| 1761 | 1780 |
| 1762 void analyzeVariableInitializer( | 1781 void analyzeVariableInitializer( |
| 1763 Spannable spannable, DartType declaredType, Node initializer) { | 1782 Spannable spannable, ResolutionDartType declaredType, Node initializer) { |
| 1764 if (initializer == null) return; | 1783 if (initializer == null) return; |
| 1765 | 1784 |
| 1766 DartType expressionType = analyzeNonVoid(initializer); | 1785 ResolutionDartType expressionType = analyzeNonVoid(initializer); |
| 1767 checkAssignable(spannable, expressionType, declaredType); | 1786 checkAssignable(spannable, expressionType, declaredType); |
| 1768 } | 1787 } |
| 1769 | 1788 |
| 1770 visitVariableDefinitions(VariableDefinitions node) { | 1789 visitVariableDefinitions(VariableDefinitions node) { |
| 1771 DartType type = analyzeVariableTypeAnnotation(node); | 1790 ResolutionDartType type = analyzeVariableTypeAnnotation(node); |
| 1772 for (Link<Node> link = node.definitions.nodes; | 1791 for (Link<Node> link = node.definitions.nodes; |
| 1773 !link.isEmpty; | 1792 !link.isEmpty; |
| 1774 link = link.tail) { | 1793 link = link.tail) { |
| 1775 Node definition = link.head; | 1794 Node definition = link.head; |
| 1776 invariant(definition, definition is Identifier || definition is SendSet, | 1795 invariant(definition, definition is Identifier || definition is SendSet, |
| 1777 message: 'expected identifier or initialization'); | 1796 message: 'expected identifier or initialization'); |
| 1778 if (definition is SendSet) { | 1797 if (definition is SendSet) { |
| 1779 SendSet initialization = definition; | 1798 SendSet initialization = definition; |
| 1780 analyzeVariableInitializer(initialization.assignmentOperator, type, | 1799 analyzeVariableInitializer(initialization.assignmentOperator, type, |
| 1781 initialization.arguments.head); | 1800 initialization.arguments.head); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1792 // } | 1811 // } |
| 1793 } | 1812 } |
| 1794 } | 1813 } |
| 1795 } | 1814 } |
| 1796 | 1815 |
| 1797 visitWhile(While node) { | 1816 visitWhile(While node) { |
| 1798 checkCondition(node.condition); | 1817 checkCondition(node.condition); |
| 1799 analyzeUntyped(node.body); | 1818 analyzeUntyped(node.body); |
| 1800 } | 1819 } |
| 1801 | 1820 |
| 1802 DartType visitParenthesizedExpression(ParenthesizedExpression node) { | 1821 ResolutionDartType visitParenthesizedExpression( |
| 1822 ParenthesizedExpression node) { |
| 1803 Expression expression = node.expression; | 1823 Expression expression = node.expression; |
| 1804 DartType type = analyze(expression); | 1824 ResolutionDartType type = analyze(expression); |
| 1805 for (TypePromotion typePromotion in getShownTypePromotionsFor(expression)) { | 1825 for (TypePromotion typePromotion in getShownTypePromotionsFor(expression)) { |
| 1806 showTypePromotion(node, typePromotion); | 1826 showTypePromotion(node, typePromotion); |
| 1807 } | 1827 } |
| 1808 return type; | 1828 return type; |
| 1809 } | 1829 } |
| 1810 | 1830 |
| 1811 DartType visitConditional(Conditional node) { | 1831 ResolutionDartType visitConditional(Conditional node) { |
| 1812 Expression condition = node.condition; | 1832 Expression condition = node.condition; |
| 1813 Expression thenExpression = node.thenExpression; | 1833 Expression thenExpression = node.thenExpression; |
| 1814 | 1834 |
| 1815 checkCondition(condition); | 1835 checkCondition(condition); |
| 1816 | 1836 |
| 1817 DartType thenType = analyzeInPromotedContext(condition, thenExpression); | 1837 ResolutionDartType thenType = |
| 1838 analyzeInPromotedContext(condition, thenExpression); |
| 1818 | 1839 |
| 1819 DartType elseType = analyze(node.elseExpression); | 1840 ResolutionDartType elseType = analyze(node.elseExpression); |
| 1820 return types.computeLeastUpperBound(thenType, elseType); | 1841 return types.computeLeastUpperBound(thenType, elseType); |
| 1821 } | 1842 } |
| 1822 | 1843 |
| 1823 visitStringInterpolation(StringInterpolation node) { | 1844 visitStringInterpolation(StringInterpolation node) { |
| 1824 node.visitChildren(this); | 1845 node.visitChildren(this); |
| 1825 return stringType; | 1846 return stringType; |
| 1826 } | 1847 } |
| 1827 | 1848 |
| 1828 visitStringInterpolationPart(StringInterpolationPart node) { | 1849 visitStringInterpolationPart(StringInterpolationPart node) { |
| 1829 node.visitChildren(this); | 1850 node.visitChildren(this); |
| 1830 return stringType; | 1851 return stringType; |
| 1831 } | 1852 } |
| 1832 | 1853 |
| 1833 visitEmptyStatement(EmptyStatement node) { | 1854 visitEmptyStatement(EmptyStatement node) { |
| 1834 // Nothing to do here. | 1855 // Nothing to do here. |
| 1835 } | 1856 } |
| 1836 | 1857 |
| 1837 visitBreakStatement(BreakStatement node) { | 1858 visitBreakStatement(BreakStatement node) { |
| 1838 // Nothing to do here. | 1859 // Nothing to do here. |
| 1839 } | 1860 } |
| 1840 | 1861 |
| 1841 visitContinueStatement(ContinueStatement node) { | 1862 visitContinueStatement(ContinueStatement node) { |
| 1842 // Nothing to do here. | 1863 // Nothing to do here. |
| 1843 } | 1864 } |
| 1844 | 1865 |
| 1845 DartType computeForInElementType(ForIn node) { | 1866 ResolutionDartType computeForInElementType(ForIn node) { |
| 1846 VariableDefinitions declaredIdentifier = | 1867 VariableDefinitions declaredIdentifier = |
| 1847 node.declaredIdentifier.asVariableDefinitions(); | 1868 node.declaredIdentifier.asVariableDefinitions(); |
| 1848 if (declaredIdentifier != null) { | 1869 if (declaredIdentifier != null) { |
| 1849 return analyzeWithDefault(declaredIdentifier.type, const DynamicType()); | 1870 return analyzeWithDefault( |
| 1871 declaredIdentifier.type, const ResolutionDynamicType()); |
| 1850 } else { | 1872 } else { |
| 1851 return analyze(node.declaredIdentifier); | 1873 return analyze(node.declaredIdentifier); |
| 1852 } | 1874 } |
| 1853 } | 1875 } |
| 1854 | 1876 |
| 1855 visitAsyncForIn(AsyncForIn node) { | 1877 visitAsyncForIn(AsyncForIn node) { |
| 1856 DartType elementType = computeForInElementType(node); | 1878 ResolutionDartType elementType = computeForInElementType(node); |
| 1857 DartType expressionType = analyze(node.expression); | 1879 ResolutionDartType expressionType = analyze(node.expression); |
| 1858 if (resolution.target.supportsAsyncAwait) { | 1880 if (resolution.target.supportsAsyncAwait) { |
| 1859 DartType streamOfDynamic = commonElements.streamType(); | 1881 ResolutionDartType streamOfDynamic = commonElements.streamType(); |
| 1860 if (!types.isAssignable(expressionType, streamOfDynamic)) { | 1882 if (!types.isAssignable(expressionType, streamOfDynamic)) { |
| 1861 reportMessage(node.expression, MessageKind.NOT_ASSIGNABLE, | 1883 reportMessage(node.expression, MessageKind.NOT_ASSIGNABLE, |
| 1862 {'fromType': expressionType, 'toType': streamOfDynamic}, | 1884 {'fromType': expressionType, 'toType': streamOfDynamic}, |
| 1863 isHint: true); | 1885 isHint: true); |
| 1864 } else { | 1886 } else { |
| 1865 InterfaceType interfaceType = | 1887 ResolutionInterfaceType interfaceType = |
| 1866 Types.computeInterfaceType(resolution, expressionType); | 1888 Types.computeInterfaceType(resolution, expressionType); |
| 1867 if (interfaceType != null) { | 1889 if (interfaceType != null) { |
| 1868 InterfaceType streamType = | 1890 ResolutionInterfaceType streamType = |
| 1869 interfaceType.asInstanceOf(streamOfDynamic.element); | 1891 interfaceType.asInstanceOf(streamOfDynamic.element); |
| 1870 if (streamType != null) { | 1892 if (streamType != null) { |
| 1871 DartType streamElementType = streamType.typeArguments.first; | 1893 ResolutionDartType streamElementType = |
| 1894 streamType.typeArguments.first; |
| 1872 if (!types.isAssignable(streamElementType, elementType)) { | 1895 if (!types.isAssignable(streamElementType, elementType)) { |
| 1873 reportMessage( | 1896 reportMessage( |
| 1874 node.expression, | 1897 node.expression, |
| 1875 MessageKind.FORIN_NOT_ASSIGNABLE, | 1898 MessageKind.FORIN_NOT_ASSIGNABLE, |
| 1876 { | 1899 { |
| 1877 'currentType': streamElementType, | 1900 'currentType': streamElementType, |
| 1878 'expressionType': expressionType, | 1901 'expressionType': expressionType, |
| 1879 'elementType': elementType | 1902 'elementType': elementType |
| 1880 }, | 1903 }, |
| 1881 isHint: true); | 1904 isHint: true); |
| 1882 } | 1905 } |
| 1883 } | 1906 } |
| 1884 } | 1907 } |
| 1885 } | 1908 } |
| 1886 } | 1909 } |
| 1887 analyzeUntyped(node.body); | 1910 analyzeUntyped(node.body); |
| 1888 } | 1911 } |
| 1889 | 1912 |
| 1890 visitSyncForIn(SyncForIn node) { | 1913 visitSyncForIn(SyncForIn node) { |
| 1891 DartType elementType = computeForInElementType(node); | 1914 ResolutionDartType elementType = computeForInElementType(node); |
| 1892 DartType expressionType = analyze(node.expression); | 1915 ResolutionDartType expressionType = analyze(node.expression); |
| 1893 DartType iteratorType = lookupMemberType(node.expression, expressionType, | 1916 ResolutionDartType iteratorType = lookupMemberType(node.expression, |
| 1894 Identifiers.iterator, MemberKind.GETTER); | 1917 expressionType, Identifiers.iterator, MemberKind.GETTER); |
| 1895 DartType currentType = lookupMemberType( | 1918 ResolutionDartType currentType = lookupMemberType( |
| 1896 node.expression, iteratorType, Identifiers.current, MemberKind.GETTER, | 1919 node.expression, iteratorType, Identifiers.current, MemberKind.GETTER, |
| 1897 isHint: true); | 1920 isHint: true); |
| 1898 if (!types.isAssignable(currentType, elementType)) { | 1921 if (!types.isAssignable(currentType, elementType)) { |
| 1899 reportMessage( | 1922 reportMessage( |
| 1900 node.expression, | 1923 node.expression, |
| 1901 MessageKind.FORIN_NOT_ASSIGNABLE, | 1924 MessageKind.FORIN_NOT_ASSIGNABLE, |
| 1902 { | 1925 { |
| 1903 'currentType': currentType, | 1926 'currentType': currentType, |
| 1904 'expressionType': expressionType, | 1927 'expressionType': expressionType, |
| 1905 'elementType': elementType | 1928 'elementType': elementType |
| 1906 }, | 1929 }, |
| 1907 isHint: true); | 1930 isHint: true); |
| 1908 } | 1931 } |
| 1909 analyzeUntyped(node.body); | 1932 analyzeUntyped(node.body); |
| 1910 } | 1933 } |
| 1911 | 1934 |
| 1912 visitLabeledStatement(LabeledStatement node) { | 1935 visitLabeledStatement(LabeledStatement node) { |
| 1913 analyzeUntyped(node.statement); | 1936 analyzeUntyped(node.statement); |
| 1914 } | 1937 } |
| 1915 | 1938 |
| 1916 visitLiteralMap(LiteralMap node) { | 1939 visitLiteralMap(LiteralMap node) { |
| 1917 InterfaceType mapType = elements.getType(node); | 1940 ResolutionInterfaceType mapType = elements.getType(node); |
| 1918 DartType mapKeyType = firstType(mapType.typeArguments); | 1941 ResolutionDartType mapKeyType = firstType(mapType.typeArguments); |
| 1919 DartType mapValueType = secondType(mapType.typeArguments); | 1942 ResolutionDartType mapValueType = secondType(mapType.typeArguments); |
| 1920 bool isConst = node.isConst; | 1943 bool isConst = node.isConst; |
| 1921 for (Link<Node> link = node.entries.nodes; | 1944 for (Link<Node> link = node.entries.nodes; |
| 1922 !link.isEmpty; | 1945 !link.isEmpty; |
| 1923 link = link.tail) { | 1946 link = link.tail) { |
| 1924 LiteralMapEntry entry = link.head; | 1947 LiteralMapEntry entry = link.head; |
| 1925 DartType keyType = analyze(entry.key); | 1948 ResolutionDartType keyType = analyze(entry.key); |
| 1926 checkAssignable(entry.key, keyType, mapKeyType, isConst: isConst); | 1949 checkAssignable(entry.key, keyType, mapKeyType, isConst: isConst); |
| 1927 DartType valueType = analyze(entry.value); | 1950 ResolutionDartType valueType = analyze(entry.value); |
| 1928 checkAssignable(entry.value, valueType, mapValueType, isConst: isConst); | 1951 checkAssignable(entry.value, valueType, mapValueType, isConst: isConst); |
| 1929 } | 1952 } |
| 1930 return mapType; | 1953 return mapType; |
| 1931 } | 1954 } |
| 1932 | 1955 |
| 1933 visitNamedArgument(NamedArgument node) { | 1956 visitNamedArgument(NamedArgument node) { |
| 1934 // Named arguments are visited as part of analyzing invocations of | 1957 // Named arguments are visited as part of analyzing invocations of |
| 1935 // unresolved methods. For instance [: foo(a: 42); :] where 'foo' is neither | 1958 // unresolved methods. For instance [: foo(a: 42); :] where 'foo' is neither |
| 1936 // found in the enclosing scope nor through lookup on 'this' or | 1959 // found in the enclosing scope nor through lookup on 'this' or |
| 1937 // [: x.foo(b: 42); :] where 'foo' cannot be not found through lookup on | 1960 // [: x.foo(b: 42); :] where 'foo' cannot be not found through lookup on |
| 1938 // the static type of 'x'. | 1961 // the static type of 'x'. |
| 1939 return analyze(node.expression); | 1962 return analyze(node.expression); |
| 1940 } | 1963 } |
| 1941 | 1964 |
| 1942 visitSwitchStatement(SwitchStatement node) { | 1965 visitSwitchStatement(SwitchStatement node) { |
| 1943 // TODO(johnniwinther): Handle reachability based on reachability of | 1966 // TODO(johnniwinther): Handle reachability based on reachability of |
| 1944 // switch cases. | 1967 // switch cases. |
| 1945 // TODO(johnniwinther): Provide hint of duplicate case constants. | 1968 // TODO(johnniwinther): Provide hint of duplicate case constants. |
| 1946 | 1969 |
| 1947 DartType expressionType = analyze(node.expression); | 1970 ResolutionDartType expressionType = analyze(node.expression); |
| 1948 | 1971 |
| 1949 // Check that all the case expressions are assignable to the expression. | 1972 // Check that all the case expressions are assignable to the expression. |
| 1950 bool hasDefaultCase = false; | 1973 bool hasDefaultCase = false; |
| 1951 for (SwitchCase switchCase in node.cases) { | 1974 for (SwitchCase switchCase in node.cases) { |
| 1952 if (switchCase.isDefaultCase) { | 1975 if (switchCase.isDefaultCase) { |
| 1953 hasDefaultCase = true; | 1976 hasDefaultCase = true; |
| 1954 } | 1977 } |
| 1955 for (Node labelOrCase in switchCase.labelsAndCases) { | 1978 for (Node labelOrCase in switchCase.labelsAndCases) { |
| 1956 CaseMatch caseMatch = labelOrCase.asCaseMatch(); | 1979 CaseMatch caseMatch = labelOrCase.asCaseMatch(); |
| 1957 if (caseMatch == null) continue; | 1980 if (caseMatch == null) continue; |
| 1958 | 1981 |
| 1959 DartType caseType = analyze(caseMatch.expression); | 1982 ResolutionDartType caseType = analyze(caseMatch.expression); |
| 1960 checkAssignable(caseMatch, expressionType, caseType); | 1983 checkAssignable(caseMatch, expressionType, caseType); |
| 1961 } | 1984 } |
| 1962 | 1985 |
| 1963 analyzeUntyped(switchCase); | 1986 analyzeUntyped(switchCase); |
| 1964 } | 1987 } |
| 1965 | 1988 |
| 1966 if (!hasDefaultCase && expressionType.isEnumType) { | 1989 if (!hasDefaultCase && expressionType.isEnumType) { |
| 1967 compiler.enqueuer.resolution.addDeferredAction(executableContext, () { | 1990 compiler.enqueuer.resolution.addDeferredAction(executableContext, () { |
| 1968 Map<ConstantValue, FieldElement> enumValues = | 1991 Map<ConstantValue, FieldElement> enumValues = |
| 1969 <ConstantValue, FieldElement>{}; | 1992 <ConstantValue, FieldElement>{}; |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2026 | 2049 |
| 2027 visitTypedef(Typedef node) { | 2050 visitTypedef(Typedef node) { |
| 2028 // Do not typecheck [Typedef] nodes. | 2051 // Do not typecheck [Typedef] nodes. |
| 2029 } | 2052 } |
| 2030 | 2053 |
| 2031 visitNode(Node node) { | 2054 visitNode(Node node) { |
| 2032 reporter.internalError(node, | 2055 reporter.internalError(node, |
| 2033 'Unexpected node ${node.getObjectDescription()} in the type checker.'); | 2056 'Unexpected node ${node.getObjectDescription()} in the type checker.'); |
| 2034 } | 2057 } |
| 2035 } | 2058 } |
| OLD | NEW |