diff --git a/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart b/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart index 54370490442..9a0d773fb46 100644 --- a/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart +++ b/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart @@ -71,6 +71,7 @@ class AssignedVariables { void declare(Variable variable) { assert(!_isFinished); _stack.last._declared.add(variable); + _anywhere._declared.add(variable); } /// This method may be called during pre-traversal, to mark the end of a @@ -1737,7 +1738,8 @@ class FlowModel { Map>? newVariableInfo; for (Variable variable in writtenVariables) { - VariableModel info = infoFor(variable); + VariableModel? info = variableInfo[variable]; + if (info == null) continue; VariableModel newInfo = info.discardPromotionsAndMarkNotUnassigned(); if (!identical(info, newInfo)) { @@ -1749,16 +1751,8 @@ class FlowModel { for (Variable variable in capturedVariables) { VariableModel? info = variableInfo[variable]; - if (info == null) { - (newVariableInfo ??= - new Map>.of( - variableInfo))[variable] = new VariableModel( - promotedTypes: null, - tested: const [], - assigned: false, - unassigned: false, - ssaNode: null); - } else if (!info.writeCaptured) { + if (info == null) continue; + if (!info.writeCaptured) { (newVariableInfo ??= new Map>.of( variableInfo))[variable] = info.writeCapture(); @@ -3487,6 +3481,15 @@ class _FlowAnalysisImpl anywhere = _assignedVariables._anywhere; + Set implicitlyDeclaredVars = { + ...anywhere._read, + ...anywhere._written + }; + implicitlyDeclaredVars.removeAll(anywhere._declared); + for (Variable variable in implicitlyDeclaredVars) { + declare(variable, true); + } } @override diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/assigned_variables/data/constructor.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/assigned_variables/data/constructor.dart index 20220737ab1..1b7e73194cf 100644 --- a/pkg/_fe_analyzer_shared/test/flow_analysis/assigned_variables/data/constructor.dart +++ b/pkg/_fe_analyzer_shared/test/flow_analysis/assigned_variables/data/constructor.dart @@ -12,3 +12,10 @@ class C { class D { const D(bool b) : assert(b); } + +class E { + final String a; + final String? b; + + const E(this.a, {this.b}); +} diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/assigned_variables/data/topLevelVariable.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/assigned_variables/data/topLevelVariable.dart index b2b8e7df5aa..40b86c3b16e 100644 --- a/pkg/_fe_analyzer_shared/test/flow_analysis/assigned_variables/data/topLevelVariable.dart +++ b/pkg/_fe_analyzer_shared/test/flow_analysis/assigned_variables/data/topLevelVariable.dart @@ -2,6 +2,9 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -dynamic /*member: x:assigned={a}*/ x = /*declared={a, b}*/ (int a, int b) { +dynamic /*member: x1:assigned={a}*/ x1 = /*declared={a, b}*/ (int a, int b) { a = 0; }; + +/*member: x2:none*/ +final x2 = new List.filled(0, null); diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart index e85803ae204..a3700cdecea 100644 --- a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart +++ b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart @@ -3197,6 +3197,25 @@ main() { x.expr.as_('int').stmt, checkNotPromoted(x), ]); }); + + test('issue 47991', () { + var h = Harness(); + var b = Var('b', 'bool'); + var i = Var('i', 'int', isFinal: true); + h.run([ + localFunction([ + declareInitialized(b, expr('bool').or(expr('bool'))), + declare(i, initialized: false), + if_(b.expr, [ + checkUnassigned(i, true), + i.write(expr('int')).stmt, + ], [ + checkUnassigned(i, true), + i.write(expr('int')).stmt, + ]), + ]), + ]); + }); }); group('Reachability', () { diff --git a/tests/language/final/initialize_inside_closure_test.dart b/tests/language/final/initialize_inside_closure_test.dart new file mode 100644 index 00000000000..f8fbcc86917 --- /dev/null +++ b/tests/language/final/initialize_inside_closure_test.dart @@ -0,0 +1,20 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +// Regression test - see https://github.com/dart-lang/sdk/issues/47991 + +import 'dart:math'; + +void main() { + () { + final should = Random().nextBool() || Random().nextBool(); + final int a; + + if (should) { + a = 1; + } else { + a = 2; + } + }; +}