| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 simple_types_inferrer; | 5 library simple_types_inferrer; |
| 6 | 6 |
| 7 import '../closure.dart' show ClosureRepresentationInfo; | 7 import '../closure.dart' show ClosureRepresentationInfo; |
| 8 import '../common.dart'; | 8 import '../common.dart'; |
| 9 import '../common/names.dart' show Identifiers, Selectors; | 9 import '../common/names.dart' show Identifiers, Selectors; |
| 10 import '../compiler.dart' show Compiler; | 10 import '../compiler.dart' show Compiler; |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 56 SetBulkMixin<TypeInformation, dynamic> | 56 SetBulkMixin<TypeInformation, dynamic> |
| 57 implements SemanticSendVisitor<TypeInformation, dynamic> { | 57 implements SemanticSendVisitor<TypeInformation, dynamic> { |
| 58 final Compiler compiler; | 58 final Compiler compiler; |
| 59 final MemberElement analyzedElement; | 59 final MemberElement analyzedElement; |
| 60 final ResolvedAst resolvedAst; | 60 final ResolvedAst resolvedAst; |
| 61 final TypeSystem<ast.Node> types; | 61 final TypeSystem<ast.Node> types; |
| 62 final Map<JumpTarget, List<LocalsHandler>> breaksFor = | 62 final Map<JumpTarget, List<LocalsHandler>> breaksFor = |
| 63 new Map<JumpTarget, List<LocalsHandler>>(); | 63 new Map<JumpTarget, List<LocalsHandler>>(); |
| 64 final Map<JumpTarget, List<LocalsHandler>> continuesFor = | 64 final Map<JumpTarget, List<LocalsHandler>> continuesFor = |
| 65 new Map<JumpTarget, List<LocalsHandler>>(); | 65 new Map<JumpTarget, List<LocalsHandler>>(); |
| 66 LocalsHandler locals; | 66 LocalsHandler<ast.Node> locals; |
| 67 final List<TypeInformation> cascadeReceiverStack = | 67 final List<TypeInformation> cascadeReceiverStack = |
| 68 new List<TypeInformation>(); | 68 new List<TypeInformation>(); |
| 69 | 69 |
| 70 TypeInformation returnType; | 70 TypeInformation returnType; |
| 71 bool visitingInitializers = false; | 71 bool visitingInitializers = false; |
| 72 bool isConstructorRedirect = false; | 72 bool isConstructorRedirect = false; |
| 73 bool seenSuperConstructorCall = false; | 73 bool seenSuperConstructorCall = false; |
| 74 SideEffects sideEffects = new SideEffects.empty(); | 74 SideEffects sideEffects = new SideEffects.empty(); |
| 75 final MemberElement outermostElement; | 75 final MemberElement outermostElement; |
| 76 final InferrerEngine inferrer; | 76 final InferrerEngine inferrer; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 89 this.types = inferrer.types, | 89 this.types = inferrer.types, |
| 90 this.memberData = inferrer.dataOfMember(analyzedElement.memberContext) { | 90 this.memberData = inferrer.dataOfMember(analyzedElement.memberContext) { |
| 91 assert(analyzedElement.isDeclaration); | 91 assert(analyzedElement.isDeclaration); |
| 92 assert(outermostElement != null); | 92 assert(outermostElement != null); |
| 93 assert(outermostElement.isDeclaration); | 93 assert(outermostElement.isDeclaration); |
| 94 if (locals != null) return; | 94 if (locals != null) return; |
| 95 ast.Node node; | 95 ast.Node node; |
| 96 if (resolvedAst.kind == ResolvedAstKind.PARSED) { | 96 if (resolvedAst.kind == ResolvedAstKind.PARSED) { |
| 97 node = resolvedAst.node; | 97 node = resolvedAst.node; |
| 98 } | 98 } |
| 99 FieldInitializationScope fieldScope = | 99 FieldInitializationScope<ast.Node> fieldScope = |
| 100 analyzedElement.isGenerativeConstructor | 100 analyzedElement.isGenerativeConstructor |
| 101 ? new FieldInitializationScope(types) | 101 ? new FieldInitializationScope<ast.Node>(types) |
| 102 : null; | 102 : null; |
| 103 locals = | 103 locals = new LocalsHandler<ast.Node>( |
| 104 new LocalsHandler(inferrer, types, compiler.options, node, fieldScope); | 104 inferrer, types, compiler.options, node, fieldScope); |
| 105 } | 105 } |
| 106 | 106 |
| 107 ElementGraphBuilder( | 107 ElementGraphBuilder( |
| 108 MemberElement element, Compiler compiler, InferrerEngine inferrer, | 108 MemberElement element, Compiler compiler, InferrerEngine inferrer, |
| 109 [LocalsHandler handler]) | 109 [LocalsHandler handler]) |
| 110 : this.internal(element, element.resolvedAst, | 110 : this.internal(element, element.resolvedAst, |
| 111 element.memberContext.declaration, inferrer, compiler, handler); | 111 element.memberContext.declaration, inferrer, compiler, handler); |
| 112 | 112 |
| 113 TreeElements get elements => resolvedAst.elements; | 113 TreeElements get elements => resolvedAst.elements; |
| 114 | 114 |
| (...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 369 isChecks.add(node); | 369 isChecks.add(node); |
| 370 } | 370 } |
| 371 | 371 |
| 372 void potentiallyAddNullCheck(ast.Send node, ast.Node receiver) { | 372 void potentiallyAddNullCheck(ast.Send node, ast.Node receiver) { |
| 373 if (!accumulateIsChecks) return; | 373 if (!accumulateIsChecks) return; |
| 374 if (!Elements.isLocal(elements[receiver])) return; | 374 if (!Elements.isLocal(elements[receiver])) return; |
| 375 isChecks.add(node); | 375 isChecks.add(node); |
| 376 } | 376 } |
| 377 | 377 |
| 378 void updateIsChecks(List<ast.Node> tests, {bool usePositive}) { | 378 void updateIsChecks(List<ast.Node> tests, {bool usePositive}) { |
| 379 void narrow(Element element, ResolutionDartType type, ast.Node node) { | |
| 380 if (element is LocalElement) { | |
| 381 TypeInformation existing = locals.use(element); | |
| 382 TypeInformation newType = | |
| 383 types.narrowType(existing, type, isNullable: false); | |
| 384 locals.update(element, newType, node); | |
| 385 } | |
| 386 } | |
| 387 | |
| 388 if (tests == null) return; | 379 if (tests == null) return; |
| 389 for (ast.Send node in tests) { | 380 for (ast.Send node in tests) { |
| 390 if (node.isTypeTest) { | 381 if (node.isTypeTest) { |
| 391 if (node.isIsNotCheck) { | 382 if (node.isIsNotCheck) { |
| 392 if (usePositive) continue; | 383 if (usePositive) continue; |
| 393 } else { | 384 } else { |
| 394 if (!usePositive) continue; | 385 if (!usePositive) continue; |
| 395 } | 386 } |
| 396 ResolutionDartType type = | 387 ResolutionDartType type = |
| 397 elements.getType(node.typeAnnotationFromIsCheckOrCast); | 388 elements.getType(node.typeAnnotationFromIsCheckOrCast); |
| 398 narrow(elements[node.receiver], type, node); | 389 Element element = elements[node.receiver]; |
| 390 if (Elements.isLocal(element)) { |
| 391 LocalElement local = element; |
| 392 locals.narrow(local, type, node); |
| 393 } |
| 399 } else { | 394 } else { |
| 400 Element receiverElement = elements[node.receiver]; | 395 Element receiverElement = elements[node.receiver]; |
| 401 Element argumentElement = elements[node.arguments.first]; | 396 Element argumentElement = elements[node.arguments.first]; |
| 402 String operator = node.selector.asOperator().source; | 397 String operator = node.selector.asOperator().source; |
| 403 if ((operator == '==' && usePositive) || | 398 if ((operator == '==' && usePositive) || |
| 404 (operator == '!=' && !usePositive)) { | 399 (operator == '!=' && !usePositive)) { |
| 405 // Type the elements as null. | 400 // Type the elements as null. |
| 406 if (Elements.isLocal(receiverElement)) { | 401 if (Elements.isLocal(receiverElement)) { |
| 407 locals.update(receiverElement, types.nullType, node); | 402 LocalElement local = receiverElement; |
| 403 locals.update(local, types.nullType, node, local.type); |
| 408 } | 404 } |
| 409 if (Elements.isLocal(argumentElement)) { | 405 if (Elements.isLocal(argumentElement)) { |
| 410 locals.update(argumentElement, types.nullType, node); | 406 LocalElement local = argumentElement; |
| 407 locals.update(local, types.nullType, node, local.type); |
| 411 } | 408 } |
| 412 } else { | 409 } else { |
| 413 // Narrow the elements to a non-null type. | 410 // Narrow the elements to a non-null type. |
| 414 ResolutionInterfaceType objectType = | 411 ResolutionInterfaceType objectType = |
| 415 closedWorld.commonElements.objectType; | 412 closedWorld.commonElements.objectType; |
| 416 if (Elements.isLocal(receiverElement)) { | 413 if (Elements.isLocal(receiverElement)) { |
| 417 narrow(receiverElement, objectType, node); | 414 LocalElement local = receiverElement; |
| 415 locals.narrow(local, objectType, node); |
| 418 } | 416 } |
| 419 if (Elements.isLocal(argumentElement)) { | 417 if (Elements.isLocal(argumentElement)) { |
| 420 narrow(argumentElement, objectType, node); | 418 LocalElement local = argumentElement; |
| 419 locals.narrow(local, objectType, node); |
| 421 } | 420 } |
| 422 } | 421 } |
| 423 } | 422 } |
| 424 } | 423 } |
| 425 } | 424 } |
| 426 | 425 |
| 427 @override | 426 @override |
| 428 TypeInformation visitIndex( | 427 TypeInformation visitIndex( |
| 429 ast.Send node, ast.Node receiver, ast.Node index, _) { | 428 ast.Send node, ast.Node receiver, ast.Node index, _) { |
| 430 return handleDynamicInvoke(node); | 429 return handleDynamicInvoke(node); |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 589 TypeInformation type = types.allocateDiamondPhi(firstType, secondType); | 588 TypeInformation type = types.allocateDiamondPhi(firstType, secondType); |
| 590 return type; | 589 return type; |
| 591 } | 590 } |
| 592 | 591 |
| 593 TypeInformation visitVariableDefinitions(ast.VariableDefinitions node) { | 592 TypeInformation visitVariableDefinitions(ast.VariableDefinitions node) { |
| 594 for (Link<ast.Node> link = node.definitions.nodes; | 593 for (Link<ast.Node> link = node.definitions.nodes; |
| 595 !link.isEmpty; | 594 !link.isEmpty; |
| 596 link = link.tail) { | 595 link = link.tail) { |
| 597 ast.Node definition = link.head; | 596 ast.Node definition = link.head; |
| 598 if (definition is ast.Identifier) { | 597 if (definition is ast.Identifier) { |
| 599 locals.update(elements[definition], types.nullType, node); | 598 LocalElement local = elements[definition]; |
| 599 locals.update(local, types.nullType, node, local.type); |
| 600 } else { | 600 } else { |
| 601 assert(definition.asSendSet() != null); | 601 assert(definition.asSendSet() != null); |
| 602 handleSendSet(definition); | 602 handleSendSet(definition); |
| 603 } | 603 } |
| 604 } | 604 } |
| 605 return null; | 605 return null; |
| 606 } | 606 } |
| 607 | 607 |
| 608 bool handleCondition(ast.Node node, List<ast.Send> tests) { | 608 bool handleCondition(ast.Node node, List<ast.Send> tests) { |
| 609 bool oldConditionIsSimple = conditionIsSimple; | 609 bool oldConditionIsSimple = conditionIsSimple; |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 745 ast.Node exception = node.exception; | 745 ast.Node exception = node.exception; |
| 746 if (exception != null) { | 746 if (exception != null) { |
| 747 ResolutionDartType type = elements.getType(node.type); | 747 ResolutionDartType type = elements.getType(node.type); |
| 748 TypeInformation mask; | 748 TypeInformation mask; |
| 749 if (type == null || type.treatAsDynamic || type.isTypeVariable) { | 749 if (type == null || type.treatAsDynamic || type.isTypeVariable) { |
| 750 mask = types.dynamicType; | 750 mask = types.dynamicType; |
| 751 } else { | 751 } else { |
| 752 ResolutionInterfaceType interfaceType = type; | 752 ResolutionInterfaceType interfaceType = type; |
| 753 mask = types.nonNullSubtype(interfaceType.element); | 753 mask = types.nonNullSubtype(interfaceType.element); |
| 754 } | 754 } |
| 755 locals.update(elements[exception], mask, node); | 755 LocalElement local = elements[exception]; |
| 756 locals.update(local, mask, node, local.type); |
| 756 } | 757 } |
| 757 ast.Node trace = node.trace; | 758 ast.Node trace = node.trace; |
| 758 if (trace != null) { | 759 if (trace != null) { |
| 759 locals.update(elements[trace], types.dynamicType, node); | 760 LocalElement local = elements[trace]; |
| 761 locals.update(local, types.dynamicType, node, local.type); |
| 760 } | 762 } |
| 761 visit(node.block); | 763 visit(node.block); |
| 762 return null; | 764 return null; |
| 763 } | 765 } |
| 764 | 766 |
| 765 TypeInformation visitParenthesizedExpression( | 767 TypeInformation visitParenthesizedExpression( |
| 766 ast.ParenthesizedExpression node) { | 768 ast.ParenthesizedExpression node) { |
| 767 return visit(node.expression); | 769 return visit(node.expression); |
| 768 } | 770 } |
| 769 | 771 |
| (...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 987 InitializingFormalElement initializingFormal = element; | 989 InitializingFormalElement initializingFormal = element; |
| 988 if (initializingFormal.fieldElement.isFinal) { | 990 if (initializingFormal.fieldElement.isFinal) { |
| 989 inferrer.recordTypeOfField( | 991 inferrer.recordTypeOfField( |
| 990 initializingFormal.fieldElement, parameterType); | 992 initializingFormal.fieldElement, parameterType); |
| 991 } else { | 993 } else { |
| 992 locals.updateField(initializingFormal.fieldElement, parameterType); | 994 locals.updateField(initializingFormal.fieldElement, parameterType); |
| 993 inferrer.recordTypeOfField( | 995 inferrer.recordTypeOfField( |
| 994 initializingFormal.fieldElement, parameterType); | 996 initializingFormal.fieldElement, parameterType); |
| 995 } | 997 } |
| 996 } | 998 } |
| 997 locals.update(element, parameterType, node); | 999 locals.update(element, parameterType, node, element.type); |
| 998 }); | 1000 }); |
| 999 ClassElement cls = analyzedConstructor.enclosingClass; | 1001 ClassElement cls = analyzedConstructor.enclosingClass; |
| 1000 Spannable spannable = node; | 1002 Spannable spannable = node; |
| 1001 if (analyzedConstructor.isSynthesized) { | 1003 if (analyzedConstructor.isSynthesized) { |
| 1002 spannable = analyzedConstructor; | 1004 spannable = analyzedConstructor; |
| 1003 synthesizeForwardingCall( | 1005 synthesizeForwardingCall( |
| 1004 spannable, analyzedConstructor.definingConstructor); | 1006 spannable, analyzedConstructor.definingConstructor); |
| 1005 } else { | 1007 } else { |
| 1006 visitingInitializers = true; | 1008 visitingInitializers = true; |
| 1007 if (node.initializers != null) { | 1009 if (node.initializers != null) { |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1051 // TODO(johnniwinther): Avoid analyzing [analyzedElement] in this | 1053 // TODO(johnniwinther): Avoid analyzing [analyzedElement] in this |
| 1052 // case; it's never called. | 1054 // case; it's never called. |
| 1053 returnType = types.nonNullEmpty(); | 1055 returnType = types.nonNullEmpty(); |
| 1054 } | 1056 } |
| 1055 } else { | 1057 } else { |
| 1056 returnType = types.nonNullExact(cls); | 1058 returnType = types.nonNullExact(cls); |
| 1057 } | 1059 } |
| 1058 } else { | 1060 } else { |
| 1059 signature.forEachParameter((FormalElement _element) { | 1061 signature.forEachParameter((FormalElement _element) { |
| 1060 ParameterElement element = _element; | 1062 ParameterElement element = _element; |
| 1061 locals.update(element, inferrer.typeOfParameter(element), node); | 1063 locals.update( |
| 1064 element, inferrer.typeOfParameter(element), node, element.type); |
| 1062 }); | 1065 }); |
| 1063 visit(node.body); | 1066 visit(node.body); |
| 1064 switch (function.asyncMarker) { | 1067 switch (function.asyncMarker) { |
| 1065 case AsyncMarker.SYNC: | 1068 case AsyncMarker.SYNC: |
| 1066 if (returnType == null) { | 1069 if (returnType == null) { |
| 1067 // No return in the body. | 1070 // No return in the body. |
| 1068 returnType = locals.seenReturnOrThrow | 1071 returnType = locals.seenReturnOrThrow |
| 1069 ? types.nonNullEmpty() // Body always throws. | 1072 ? types.nonNullEmpty() // Body always throws. |
| 1070 : types.nullType; | 1073 : types.nullType; |
| 1071 } else if (!locals.seenReturnOrThrow) { | 1074 } else if (!locals.seenReturnOrThrow) { |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1137 }); | 1140 }); |
| 1138 } | 1141 } |
| 1139 | 1142 |
| 1140 TypeInformation visitFunctionDeclaration(ast.FunctionDeclaration node) { | 1143 TypeInformation visitFunctionDeclaration(ast.FunctionDeclaration node) { |
| 1141 LocalFunctionElement element = | 1144 LocalFunctionElement element = |
| 1142 elements.getFunctionDefinition(node.function); | 1145 elements.getFunctionDefinition(node.function); |
| 1143 TypeInformation type = | 1146 TypeInformation type = |
| 1144 inferrer.concreteTypes.putIfAbsent(node.function, () { | 1147 inferrer.concreteTypes.putIfAbsent(node.function, () { |
| 1145 return types.allocateClosure(element.callMethod); | 1148 return types.allocateClosure(element.callMethod); |
| 1146 }); | 1149 }); |
| 1147 locals.update(element, type, node); | 1150 locals.update(element, type, node, element.type); |
| 1148 visit(node.function); | 1151 visit(node.function); |
| 1149 return type; | 1152 return type; |
| 1150 } | 1153 } |
| 1151 | 1154 |
| 1152 TypeInformation visitStringInterpolation(ast.StringInterpolation node) { | 1155 TypeInformation visitStringInterpolation(ast.StringInterpolation node) { |
| 1153 // Interpolation could have any effects since it could call any toString() | 1156 // Interpolation could have any effects since it could call any toString() |
| 1154 // method. | 1157 // method. |
| 1155 // TODO(sra): This could be modelled by a call to toString() but with a | 1158 // TODO(sra): This could be modelled by a call to toString() but with a |
| 1156 // guaranteed String return type. Interpolation of known types would get | 1159 // guaranteed String return type. Interpolation of known types would get |
| 1157 // specialized effects. This would not currently be effective since the JS | 1160 // specialized effects. This would not currently be effective since the JS |
| (...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1350 | 1353 |
| 1351 if (Elements.isStaticOrTopLevelField(element)) { | 1354 if (Elements.isStaticOrTopLevelField(element)) { |
| 1352 handleStaticSend(node, setterSelector, setterMask, element, | 1355 handleStaticSend(node, setterSelector, setterMask, element, |
| 1353 new ArgumentsTypes([newType], null)); | 1356 new ArgumentsTypes([newType], null)); |
| 1354 } else if (Elements.isUnresolved(element) || | 1357 } else if (Elements.isUnresolved(element) || |
| 1355 element.isSetter || | 1358 element.isSetter || |
| 1356 element.isField) { | 1359 element.isField) { |
| 1357 handleDynamicSend(CallType.complex, node, setterSelector, setterMask, | 1360 handleDynamicSend(CallType.complex, node, setterSelector, setterMask, |
| 1358 receiverType, new ArgumentsTypes([newType], null)); | 1361 receiverType, new ArgumentsTypes([newType], null)); |
| 1359 } else if (element.isLocal) { | 1362 } else if (element.isLocal) { |
| 1360 locals.update(element, newType, node); | 1363 LocalElement local = element; |
| 1364 locals.update(local, newType, node, local.type, |
| 1365 isSetIfNull: node.isIfNullAssignment); |
| 1361 } | 1366 } |
| 1362 | 1367 |
| 1363 return node.isPostfix ? getterType : newType; | 1368 return node.isPostfix ? getterType : newType; |
| 1364 } | 1369 } |
| 1365 } | 1370 } |
| 1366 | 1371 |
| 1367 /// Handle compound index set, like `foo[0] += 42` or `foo[0]++`. | 1372 /// Handle compound index set, like `foo[0] += 42` or `foo[0]++`. |
| 1368 TypeInformation handleCompoundIndexSet( | 1373 TypeInformation handleCompoundIndexSet( |
| 1369 ast.SendSet node, | 1374 ast.SendSet node, |
| 1370 TypeInformation receiverType, | 1375 TypeInformation receiverType, |
| (...skipping 629 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2000 (node.asSendSet().receiver != null) && | 2005 (node.asSendSet().receiver != null) && |
| 2001 node.asSendSet().receiver.isThis()) { | 2006 node.asSendSet().receiver.isThis()) { |
| 2002 Iterable<MemberEntity> targets = closedWorld.locateMembers( | 2007 Iterable<MemberEntity> targets = closedWorld.locateMembers( |
| 2003 setterSelector, types.newTypedSelector(thisType, setterMask)); | 2008 setterSelector, types.newTypedSelector(thisType, setterMask)); |
| 2004 // We just recognized a field initialization of the form: | 2009 // We just recognized a field initialization of the form: |
| 2005 // `this.foo = 42`. If there is only one target, we can update | 2010 // `this.foo = 42`. If there is only one target, we can update |
| 2006 // its type. | 2011 // its type. |
| 2007 if (targets.length == 1) { | 2012 if (targets.length == 1) { |
| 2008 MemberElement single = targets.first; | 2013 MemberElement single = targets.first; |
| 2009 if (single.isField) { | 2014 if (single.isField) { |
| 2010 locals.updateField(single, rhsType); | 2015 FieldElement field = single; |
| 2016 locals.updateField(field, rhsType); |
| 2011 } | 2017 } |
| 2012 } | 2018 } |
| 2013 } | 2019 } |
| 2014 handleDynamicSend(CallType.access, node, setterSelector, setterMask, | 2020 handleDynamicSend(CallType.access, node, setterSelector, setterMask, |
| 2015 receiverType, arguments); | 2021 receiverType, arguments); |
| 2016 } else if (element.isField) { | 2022 } else if (element.isField) { |
| 2017 FieldElement field = element; | 2023 FieldElement field = element; |
| 2018 if (field.isFinal) { | 2024 if (field.isFinal) { |
| 2019 inferrer.recordTypeOfField(field, rhsType); | 2025 inferrer.recordTypeOfField(field, rhsType); |
| 2020 } else { | 2026 } else { |
| 2021 if (analyzedElement.isGenerativeConstructor) { | 2027 if (analyzedElement.isGenerativeConstructor) { |
| 2022 locals.updateField(field, rhsType); | 2028 locals.updateField(field, rhsType); |
| 2023 } | 2029 } |
| 2024 if (visitingInitializers) { | 2030 if (visitingInitializers) { |
| 2025 inferrer.recordTypeOfField(field, rhsType); | 2031 inferrer.recordTypeOfField(field, rhsType); |
| 2026 } else { | 2032 } else { |
| 2027 handleDynamicSend(CallType.complex, node, setterSelector, setterMask, | 2033 handleDynamicSend(CallType.complex, node, setterSelector, setterMask, |
| 2028 receiverType, arguments); | 2034 receiverType, arguments); |
| 2029 } | 2035 } |
| 2030 } | 2036 } |
| 2031 } else if (element.isLocal) { | 2037 } else if (element.isLocal) { |
| 2032 locals.update(element, rhsType, node); | 2038 LocalElement local = element; |
| 2039 ast.SendSet sendSet = node.asSendSet(); |
| 2040 bool isSetIfNull = sendSet != null && sendSet.isIfNullAssignment; |
| 2041 locals.update(local, rhsType, node, local.type, isSetIfNull: isSetIfNull); |
| 2033 } | 2042 } |
| 2034 return rhsType; | 2043 return rhsType; |
| 2035 } | 2044 } |
| 2036 | 2045 |
| 2037 /// Handle a super access or invocation that results in a `noSuchMethod` call. | 2046 /// Handle a super access or invocation that results in a `noSuchMethod` call. |
| 2038 TypeInformation handleErroneousSuperSend(ast.Send node) { | 2047 TypeInformation handleErroneousSuperSend(ast.Send node) { |
| 2039 ArgumentsTypes arguments = | 2048 ArgumentsTypes arguments = |
| 2040 node.isPropertyAccess ? null : analyzeArguments(node.arguments); | 2049 node.isPropertyAccess ? null : analyzeArguments(node.arguments); |
| 2041 Selector selector = elements.getSelector(node); | 2050 Selector selector = elements.getSelector(node); |
| 2042 TypeMask mask = memberData.typeOfSend(node); | 2051 TypeMask mask = memberData.typeOfSend(node); |
| (...skipping 733 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2776 ast.Send send = node.asSend(); | 2785 ast.Send send = node.asSend(); |
| 2777 bool isConditional = false; | 2786 bool isConditional = false; |
| 2778 if (send != null) { | 2787 if (send != null) { |
| 2779 isConditional = send.isConditional; | 2788 isConditional = send.isConditional; |
| 2780 ast.Node receiver = send.receiver; | 2789 ast.Node receiver = send.receiver; |
| 2781 if (receiver != null) { | 2790 if (receiver != null) { |
| 2782 Element element = elements[receiver]; | 2791 Element element = elements[receiver]; |
| 2783 if (Elements.isLocal(element) && !capturedVariables.contains(element)) { | 2792 if (Elements.isLocal(element) && !capturedVariables.contains(element)) { |
| 2784 TypeInformation refinedType = types.refineReceiver( | 2793 TypeInformation refinedType = types.refineReceiver( |
| 2785 selector, mask, receiverType, send.isConditional); | 2794 selector, mask, receiverType, send.isConditional); |
| 2786 locals.update(element, refinedType, node); | 2795 LocalElement local = element; |
| 2796 locals.update(local, refinedType, node, local.type); |
| 2787 } | 2797 } |
| 2788 } | 2798 } |
| 2789 } | 2799 } |
| 2790 | 2800 |
| 2791 return inferrer.registerCalledSelector( | 2801 return inferrer.registerCalledSelector( |
| 2792 callType, | 2802 callType, |
| 2793 node, | 2803 node, |
| 2794 selector, | 2804 selector, |
| 2795 mask, | 2805 mask, |
| 2796 receiverType, | 2806 receiverType, |
| (...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2983 node, | 2993 node, |
| 2984 iteratorSelector, | 2994 iteratorSelector, |
| 2985 iteratorMask, | 2995 iteratorMask, |
| 2986 expressionType, | 2996 expressionType, |
| 2987 new ArgumentsTypes.empty()); | 2997 new ArgumentsTypes.empty()); |
| 2988 | 2998 |
| 2989 return handleForInLoop(node, iteratorType, currentSelector, currentMask, | 2999 return handleForInLoop(node, iteratorType, currentSelector, currentMask, |
| 2990 moveNextSelector, moveNextMask); | 3000 moveNextSelector, moveNextMask); |
| 2991 } | 3001 } |
| 2992 } | 3002 } |
| OLD | NEW |