Skip to content

Commit e038d8a

Browse files
committed
[dart2js] Add implicit null to type for optional non-nullable parameters.
This ensures any code downstream of this knows that it can receive a null and null checks are not removed during SSA. Change-Id: I8c3d706875a9b70ed8407d00053fb381df168a49 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/406480 Reviewed-by: Mayank Patke <[email protected]>
1 parent 1c91d21 commit e038d8a

File tree

4 files changed

+57
-21
lines changed

4 files changed

+57
-21
lines changed

pkg/compiler/lib/src/inferrer/builder.dart

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -287,16 +287,25 @@ class KernelTypeGraphBuilder extends ir.VisitorDefault<TypeInformation?>
287287
required bool isOptional,
288288
}) {
289289
Local local = _localsMap.getLocalVariable(node);
290-
_state.setLocal(
291-
_inferrer,
292-
_capturedAndBoxed,
293-
local,
294-
_inferrer.typeOfParameter(local),
295-
);
290+
final parameterType = _inferrer.typeOfParameter(local);
291+
_state.setLocal(_inferrer, _capturedAndBoxed, local, parameterType);
292+
296293
if (isOptional) {
297294
TypeInformation type;
298295
if (node.initializer != null) {
299296
type = visit(node.initializer)!;
297+
if (_inferrer.abstractValueDomain.isNull(type.type).isDefinitelyTrue &&
298+
!node.type.isPotentiallyNullable) {
299+
// TODO(52582): Make optional nonnullable parameters nullable until
300+
// such a case from redirecting factories is a compile-time error.
301+
//
302+
// In rare cases (e.g. optional parameters on redirecting factories)
303+
// the CFE can give us a non-nullable parameter with a null
304+
// initializer. Ideally we would take the type of the initializer on
305+
// the target parameter but instead we're conservative and treat the
306+
// parameter as nullable.
307+
parameterType.isOptionalNoDefault = true;
308+
}
300309
} else {
301310
type = _types.nullType;
302311
}

pkg/compiler/lib/src/inferrer/engine.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1262,7 +1262,7 @@ class InferrerEngine {
12621262
}
12631263

12641264
/// Returns the type of [element].
1265-
TypeInformation typeOfParameter(Local element) {
1265+
ParameterTypeInformation typeOfParameter(Local element) {
12661266
return types.getInferredTypeOfParameter(element);
12671267
}
12681268

pkg/compiler/lib/src/inferrer/type_graph_nodes.dart

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -48,27 +48,28 @@ enum _Flag {
4848
isClosureParameter, // 6
4949
isInitializingFormal, // 7
5050
isVirtual, // 8
51+
isOptionalNoDefault, // 9
5152
// ---Flags for [CallSiteTypeInformation]---
52-
inLoop, // 9
53+
inLoop, // 10
5354
// ---Flags for [DynamicCallSiteTypeInformation]---
54-
isConditional, // 10
55-
hasClosureCallTargets, // 11
56-
targetsIncludeComplexNoSuchMethod, // 12
57-
hasTargetsIncludeComplexNoSuchMethod, // 13
55+
isConditional, // 11
56+
hasClosureCallTargets, // 12
57+
targetsIncludeComplexNoSuchMethod, // 13
58+
hasTargetsIncludeComplexNoSuchMethod, // 14
5859
// ---Flags for [PhiElementTypeInformation]---
59-
isTry, // 14
60+
isTry, // 15
6061
// ---Flags for [ValueInMapTypeInformation]---
61-
valueInMapNonNull, // 15
62+
valueInMapNonNull, // 16
6263
// ---Flags for [MemberTypeInformation]---
63-
isCalled, // 16
64-
isCalledMoreThanOnce, // 17
64+
isCalled, // 17
65+
isCalledMoreThanOnce, // 18
6566
// ---Flags for [ApplyableTypeInformation]---
66-
mightBePassedToFunctionApply, // 18
67+
mightBePassedToFunctionApply, // 19
6768
// ---Flags for [InferredTypeInformation]---
68-
inferred, // 19
69+
inferred, // 20
6970
// ---Flags for [TracedTypeInformation]---
70-
notBailedOut, // 20
71-
analyzed, // 21
71+
notBailedOut, // 21
72+
analyzed, // 22
7273
}
7374

7475
/// Common class for all nodes in the graph. The current nodes are:
@@ -831,6 +832,9 @@ class ParameterTypeInformation extends ElementTypeInformation {
831832
bool get _isInitializingFormal => _flags.contains(_Flag.isInitializingFormal);
832833
bool _isTearOffClosureParameter = false;
833834
bool get _isVirtual => _flags.contains(_Flag.isVirtual);
835+
bool get isOptionalNoDefault => _flags.contains(_Flag.isOptionalNoDefault);
836+
set isOptionalNoDefault(bool value) =>
837+
_flags = _flags.update(_Flag.isOptionalNoDefault, value);
834838

835839
ParameterTypeInformation.localFunction(
836840
super.abstractValueDomain,
@@ -968,7 +972,11 @@ class ParameterTypeInformation extends ElementTypeInformation {
968972
AbstractValue mask,
969973
InferrerEngine inferrer,
970974
) {
971-
return _narrowType(inferrer.abstractValueDomain, mask, _type);
975+
final staticType =
976+
isOptionalNoDefault
977+
? inferrer.abstractValueDomain.includeNull(_type)
978+
: _type;
979+
return _narrowType(inferrer.abstractValueDomain, mask, staticType);
972980
}
973981

974982
AbstractValue checkedType(InferrerEngine inferrer) {
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
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.
4+
5+
class B implements A {
6+
/*member: B.foo:[exact=B]*/
7+
B.foo([int? /*[null]*/ x]);
8+
}
9+
10+
class A {
11+
/*member: A._#foo#tearOff:[exact=B]*/
12+
factory A.foo([int /*[null]*/ x]) = B.foo;
13+
}
14+
15+
/*member: main:[null]*/
16+
void main() {
17+
final f = A.foo;
18+
f();
19+
}

0 commit comments

Comments
 (0)