From 445c0842c7ae5ea89bd225050169c057ed0ca76e Mon Sep 17 00:00:00 2001 From: Konstantin Shcheglov Date: Thu, 16 Jan 2020 22:30:09 +0000 Subject: [PATCH] Use nullable context type for operand of null-check operator. (2) Initial: https://dart-review.googlesource.com/c/sdk/+/131343 Reverted: https://dart-review.googlesource.com/c/sdk/+/131461 Bug: https://github.com/dart-lang/sdk/issues/39694 Change-Id: I6287338ce347ddc45d6cc1f3cb16fdccbc75c891 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/132200 Reviewed-by: Brian Wilkerson Commit-Queue: Konstantin Shcheglov --- .../resolver/postfix_expression_resolver.dart | 32 +++++++++++++++---- .../resolution/postfix_expression_test.dart | 30 +++++++++++++++++ 2 files changed, 55 insertions(+), 7 deletions(-) diff --git a/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart index f88eeaf7aa9e1..36866f73297c9 100644 --- a/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart +++ b/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart @@ -51,6 +51,11 @@ class PostfixExpressionResolver { TypeSystemImpl get _typeSystem => _resolver.typeSystem; void resolve(PostfixExpressionImpl node) { + if (node.operator.type == TokenType.BANG) { + _resolveNullCheck(node); + return; + } + node.operand.accept(_resolver); var receiverType = getReadType( @@ -58,11 +63,6 @@ class PostfixExpressionResolver { elementTypeProvider: _elementTypeProvider, ); - if (node.operator.type == TokenType.BANG) { - _resolveNullCheck(node, receiverType); - return; - } - _assignmentShared.checkLateFinalAlreadyAssigned(node.operand); _resolve1(node, receiverType); @@ -197,11 +197,29 @@ class PostfixExpressionResolver { _inferenceHelper.recordStaticType(node, receiverType); } - void _resolveNullCheck(PostfixExpressionImpl node, DartType operandType) { + void _resolveNullCheck(PostfixExpressionImpl node) { + var operand = node.operand; + + var contextType = InferenceContext.getContext(node); + if (contextType != null) { + if (_isNonNullableByDefault) { + contextType = _typeSystem.makeNullable(contextType); + } + InferenceContext.setType(operand, contextType); + } + + operand.accept(_resolver); + operand = node.operand; + + var operandType = getReadType( + operand, + elementTypeProvider: _elementTypeProvider, + ); + var type = _typeSystem.promoteToNonNull(operandType); _inferenceHelper.recordStaticType(node, type); - _flowAnalysis?.flow?.nonNullAssert_end(node.operand); + _flowAnalysis?.flow?.nonNullAssert_end(operand); } /// Return `true` if we should report an error for the lookup [result] on diff --git a/pkg/analyzer/test/src/dart/resolution/postfix_expression_test.dart b/pkg/analyzer/test/src/dart/resolution/postfix_expression_test.dart index c8e1653c45fd1..0413283949c5f 100644 --- a/pkg/analyzer/test/src/dart/resolution/postfix_expression_test.dart +++ b/pkg/analyzer/test/src/dart/resolution/postfix_expression_test.dart @@ -119,6 +119,14 @@ f(int? x) { ); } + test_nullCheck_functionExpressionInvocation_rewrite() async { + await assertNoErrorsInCode(r''' +main(Function f2) { + f2(42)!; +} +'''); + } + test_nullCheck_null() async { await assertNoErrorsInCode(''' main(Null x) { @@ -129,6 +137,28 @@ main(Null x) { assertType(findNode.postfix('x!'), 'Never'); } + test_nullCheck_nullableContext() async { + await assertNoErrorsInCode(r''' +T f(T t) => t; + +int g() => f(null)!; +'''); + + assertMethodInvocation2( + findNode.methodInvocation('f(null)'), + element: findElement.topFunction('f'), + typeArgumentTypes: ['int?'], + invokeType: 'int? Function(int?)', + type: 'int?', + ); + + assertPostfixExpression( + findNode.postfix('f(null)!'), + element: null, + type: 'int', + ); + } + test_nullCheck_typeParameter() async { await assertNoErrorsInCode(r''' f(T? x) {