@@ -6,6 +6,8 @@ import 'dart:core' hide MapEntry;
6
6
7
7
import 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis.dart' ;
8
8
9
+ import 'package:_fe_analyzer_shared/src/util/link.dart' ;
10
+
9
11
import 'package:front_end/src/fasta/kernel/internal_ast.dart' ;
10
12
import 'package:front_end/src/fasta/type_inference/type_demotion.dart' ;
11
13
@@ -502,7 +504,6 @@ class TypeInferrerImpl implements TypeInferrer {
502
504
typeSchemaEnvironment = engine.typeSchemaEnvironment,
503
505
isTopLevel = topLevel,
504
506
typePromoter = new TypePromoter (engine.typeSchemaEnvironment),
505
- // TODO(dmitryas): Pass in the actual assigned variables.
506
507
flowAnalysis = new FlowAnalysis (
507
508
new TypeOperationsCfe (engine.typeSchemaEnvironment),
508
509
assignedVariables);
@@ -1482,6 +1483,29 @@ class TypeInferrerImpl implements TypeInferrer {
1482
1483
variable.type = inferredType;
1483
1484
}
1484
1485
1486
+ Link <NullAwareGuard > inferSyntheticVariableNullAware (
1487
+ VariableDeclarationImpl variable) {
1488
+ assert (variable.isImplicitlyTyped);
1489
+ assert (variable.initializer != null );
1490
+ ExpressionInferenceResult result = inferExpression (
1491
+ variable.initializer, const UnknownType (), true ,
1492
+ isVoidAllowed: true );
1493
+ variable.initializer = result.nullAwareAction..parent = variable;
1494
+ DartType inferredType = inferDeclarationType (result.inferredType);
1495
+ instrumentation? .record (uriForInstrumentation, variable.fileOffset, 'type' ,
1496
+ new InstrumentationValueForType (inferredType));
1497
+ variable.type = inferredType;
1498
+ return result.nullAwareGuards;
1499
+ }
1500
+
1501
+ NullAwareGuard createNullAwareGuard (VariableDeclaration variable) {
1502
+ Member equalsMember =
1503
+ findInterfaceMember (variable.type, equalsName, variable.fileOffset)
1504
+ .member;
1505
+ return new NullAwareGuard (
1506
+ variable, variable.fileOffset, equalsMember, this );
1507
+ }
1508
+
1485
1509
/// Performs type inference on the given [expression] .
1486
1510
///
1487
1511
/// [typeContext] is the expected type of the expression, based on surrounding
@@ -2111,7 +2135,7 @@ class TypeInferrerImpl implements TypeInferrer {
2111
2135
2112
2136
ExpressionInferenceResult _inferDynamicInvocation (
2113
2137
int fileOffset,
2114
- NullAwareGuard nullAwareGuard ,
2138
+ Link < NullAwareGuard > nullAwareGuards ,
2115
2139
Expression receiver,
2116
2140
Name name,
2117
2141
Arguments arguments,
@@ -2124,12 +2148,12 @@ class TypeInferrerImpl implements TypeInferrer {
2124
2148
inferredType,
2125
2149
new MethodInvocationImpl (receiver, name, arguments)
2126
2150
..fileOffset = fileOffset,
2127
- nullAwareGuard );
2151
+ nullAwareGuards );
2128
2152
}
2129
2153
2130
2154
ExpressionInferenceResult _inferMissingInvocation (
2131
2155
int fileOffset,
2132
- NullAwareGuard nullAwareGuard ,
2156
+ Link < NullAwareGuard > nullAwareGuards ,
2133
2157
Expression receiver,
2134
2158
DartType receiverType,
2135
2159
ObjectAccessTarget target,
@@ -2145,12 +2169,13 @@ class TypeInferrerImpl implements TypeInferrer {
2145
2169
receiverType: receiverType);
2146
2170
assert (name != equalsName);
2147
2171
// TODO(johnniwinther): Use InvalidType instead.
2148
- return new ExpressionInferenceResult (const DynamicType (), error);
2172
+ return new ExpressionInferenceResult .nullAware (
2173
+ const DynamicType (), error, nullAwareGuards);
2149
2174
}
2150
2175
2151
2176
ExpressionInferenceResult _inferExtensionInvocation (
2152
2177
int fileOffset,
2153
- NullAwareGuard nullAwareGuard ,
2178
+ Link < NullAwareGuard > nullAwareGuards ,
2154
2179
Expression receiver,
2155
2180
DartType receiverType,
2156
2181
ObjectAccessTarget target,
@@ -2183,12 +2208,12 @@ class TypeInferrerImpl implements TypeInferrer {
2183
2208
typeSchemaEnvironment, helper.uri, getTypeArgumentsInfo (arguments));
2184
2209
}
2185
2210
return new ExpressionInferenceResult .nullAware (
2186
- inferredType, staticInvocation, nullAwareGuard );
2211
+ inferredType, staticInvocation, nullAwareGuards );
2187
2212
}
2188
2213
2189
2214
ExpressionInferenceResult _inferFunctionInvocation (
2190
2215
int fileOffset,
2191
- NullAwareGuard nullAwareGuard ,
2216
+ Link < NullAwareGuard > nullAwareGuards ,
2192
2217
Expression receiver,
2193
2218
DartType receiverType,
2194
2219
ObjectAccessTarget target,
@@ -2204,12 +2229,12 @@ class TypeInferrerImpl implements TypeInferrer {
2204
2229
inferredType,
2205
2230
new MethodInvocation (receiver, callName, arguments)
2206
2231
..fileOffset = fileOffset,
2207
- nullAwareGuard );
2232
+ nullAwareGuards );
2208
2233
}
2209
2234
2210
2235
ExpressionInferenceResult _inferInstanceMethodInvocation (
2211
2236
int fileOffset,
2212
- NullAwareGuard nullAwareGuard ,
2237
+ Link < NullAwareGuard > nullAwareGuards ,
2213
2238
Expression receiver,
2214
2239
DartType receiverType,
2215
2240
ObjectAccessTarget target,
@@ -2297,12 +2322,12 @@ class TypeInferrerImpl implements TypeInferrer {
2297
2322
..fileOffset = fileOffset;
2298
2323
2299
2324
return new ExpressionInferenceResult .nullAware (
2300
- inferredType, replacement, nullAwareGuard );
2325
+ inferredType, replacement, nullAwareGuards );
2301
2326
}
2302
2327
2303
2328
ExpressionInferenceResult _inferInstanceGetterInvocation (
2304
2329
int fileOffset,
2305
- NullAwareGuard nullAwareGuard ,
2330
+ Link < NullAwareGuard > nullAwareGuards ,
2306
2331
Expression receiver,
2307
2332
DartType receiverType,
2308
2333
ObjectAccessTarget target,
@@ -2395,12 +2420,12 @@ class TypeInferrerImpl implements TypeInferrer {
2395
2420
..fileOffset = fileOffset;
2396
2421
2397
2422
return new ExpressionInferenceResult .nullAware (
2398
- inferredType, replacement, nullAwareGuard );
2423
+ inferredType, replacement, nullAwareGuards );
2399
2424
}
2400
2425
2401
2426
ExpressionInferenceResult _inferInstanceFieldInvocation (
2402
2427
int fileOffset,
2403
- NullAwareGuard nullAwareGuard ,
2428
+ Link < NullAwareGuard > nullAwareGuards ,
2404
2429
Expression receiver,
2405
2430
DartType receiverType,
2406
2431
ObjectAccessTarget target,
@@ -2470,7 +2495,7 @@ class TypeInferrerImpl implements TypeInferrer {
2470
2495
..fileOffset = fileOffset;
2471
2496
2472
2497
return new ExpressionInferenceResult .nullAware (
2473
- inferredType, replacement, nullAwareGuard );
2498
+ inferredType, replacement, nullAwareGuards );
2474
2499
}
2475
2500
2476
2501
/// Performs the core type inference algorithm for method invocations (this
@@ -2481,9 +2506,9 @@ class TypeInferrerImpl implements TypeInferrer {
2481
2506
ExpressionInferenceResult result =
2482
2507
inferExpression (node.receiver, const UnknownType (), true );
2483
2508
Expression receiver;
2484
- NullAwareGuard nullAwareGuard ;
2509
+ Link < NullAwareGuard > nullAwareGuards ;
2485
2510
if (isNonNullableByDefault) {
2486
- nullAwareGuard = result.nullAwareGuard ;
2511
+ nullAwareGuards = result.nullAwareGuards ;
2487
2512
receiver = result.nullAwareAction;
2488
2513
} else {
2489
2514
receiver = result.expression;
@@ -2499,7 +2524,7 @@ class TypeInferrerImpl implements TypeInferrer {
2499
2524
if (member.kind == ProcedureKind .Getter ) {
2500
2525
return _inferInstanceGetterInvocation (
2501
2526
node.fileOffset,
2502
- nullAwareGuard ,
2527
+ nullAwareGuards ,
2503
2528
receiver,
2504
2529
receiverType,
2505
2530
target,
@@ -2509,7 +2534,7 @@ class TypeInferrerImpl implements TypeInferrer {
2509
2534
} else {
2510
2535
return _inferInstanceMethodInvocation (
2511
2536
node.fileOffset,
2512
- nullAwareGuard ,
2537
+ nullAwareGuards ,
2513
2538
receiver,
2514
2539
receiverType,
2515
2540
target,
@@ -2518,18 +2543,18 @@ class TypeInferrerImpl implements TypeInferrer {
2518
2543
isImplicitCall: node.isImplicitCall);
2519
2544
}
2520
2545
} else {
2521
- return _inferInstanceFieldInvocation (node.fileOffset, nullAwareGuard ,
2546
+ return _inferInstanceFieldInvocation (node.fileOffset, nullAwareGuards ,
2522
2547
receiver, receiverType, target, node.arguments, typeContext,
2523
2548
isImplicitCall: node.isImplicitCall);
2524
2549
}
2525
2550
break ;
2526
2551
case ObjectAccessTargetKind .callFunction:
2527
- return _inferFunctionInvocation (node.fileOffset, nullAwareGuard ,
2552
+ return _inferFunctionInvocation (node.fileOffset, nullAwareGuards ,
2528
2553
receiver, receiverType, target, node.arguments, typeContext);
2529
2554
case ObjectAccessTargetKind .extensionMember:
2530
2555
return _inferExtensionInvocation (
2531
2556
node.fileOffset,
2532
- nullAwareGuard ,
2557
+ nullAwareGuards ,
2533
2558
receiver,
2534
2559
receiverType,
2535
2560
target,
@@ -2539,7 +2564,7 @@ class TypeInferrerImpl implements TypeInferrer {
2539
2564
case ObjectAccessTargetKind .missing:
2540
2565
return _inferMissingInvocation (
2541
2566
node.fileOffset,
2542
- nullAwareGuard ,
2567
+ nullAwareGuards ,
2543
2568
receiver,
2544
2569
receiverType,
2545
2570
target,
@@ -2550,7 +2575,7 @@ class TypeInferrerImpl implements TypeInferrer {
2550
2575
case ObjectAccessTargetKind .dynamic :
2551
2576
case ObjectAccessTargetKind .invalid:
2552
2577
case ObjectAccessTargetKind .unresolved:
2553
- return _inferDynamicInvocation (node.fileOffset, nullAwareGuard ,
2578
+ return _inferDynamicInvocation (node.fileOffset, nullAwareGuards ,
2554
2579
receiver, node.name, node.arguments, typeContext);
2555
2580
}
2556
2581
return unhandled ('$target ' , 'inferMethodInvocation' , node.fileOffset,
@@ -3256,10 +3281,10 @@ class ExpressionInferenceResult {
3256
3281
3257
3282
factory ExpressionInferenceResult .nullAware (
3258
3283
DartType inferredType, Expression expression,
3259
- [NullAwareGuard nullAwareGuard ]) {
3260
- if (nullAwareGuard != null ) {
3284
+ [Link < NullAwareGuard > nullAwareGuards = const Link < NullAwareGuard >() ]) {
3285
+ if (nullAwareGuards != null && nullAwareGuards.isNotEmpty ) {
3261
3286
return new NullAwareExpressionInferenceResult (
3262
- inferredType, nullAwareGuard , expression);
3287
+ inferredType, nullAwareGuards , expression);
3263
3288
} else {
3264
3289
return new ExpressionInferenceResult (inferredType, expression);
3265
3290
}
@@ -3268,13 +3293,13 @@ class ExpressionInferenceResult {
3268
3293
ExpressionInferenceResult (this .inferredType, this .expression)
3269
3294
: assert (expression != null );
3270
3295
3271
- /// The guard used for null-aware access if the expression is part of a
3272
- /// null-shorting, and `null` otherwise .
3273
- NullAwareGuard get nullAwareGuard => null ;
3296
+ /// The guards used for null-aware access if the expression is part of a
3297
+ /// null-shorting.
3298
+ Link < NullAwareGuard > get nullAwareGuards => const Link < NullAwareGuard >() ;
3274
3299
3275
- /// If the expression is part of a null-shorting, the action performed on
3276
- /// the variable in [nullAwareGuard] . Otherwise, this is the same as
3277
- /// [expression] .
3300
+ /// If the expression is part of a null-shorting, this is the action performed
3301
+ /// on the guarded variable, found as the first guard in [nullAwareGuards] .
3302
+ /// Otherwise, this is the same as [expression] .
3278
3303
Expression get nullAwareAction => expression;
3279
3304
3280
3305
String toString () => 'ExpressionInferenceResult($inferredType ,$expression )' ;
@@ -3291,11 +3316,25 @@ class NullAwareGuard {
3291
3316
/// The [Member] used for the == call.
3292
3317
final Member _nullAwareEquals;
3293
3318
3294
- NullAwareGuard (
3295
- this ._nullAwareVariable, this ._nullAwareFileOffset, this ._nullAwareEquals)
3319
+ final TypeInferrerImpl _inferrer;
3320
+
3321
+ NullAwareGuard (this ._nullAwareVariable, this ._nullAwareFileOffset,
3322
+ this ._nullAwareEquals, this ._inferrer)
3296
3323
: assert (_nullAwareVariable != null ),
3297
3324
assert (_nullAwareFileOffset != null ),
3298
- assert (_nullAwareEquals != null );
3325
+ assert (_nullAwareEquals != null ),
3326
+ assert (_inferrer != null ) {
3327
+ // Ensure the initializer of [_nullAwareVariable] is promoted to
3328
+ // non-nullable.
3329
+ _inferrer.flowAnalysis
3330
+ .nullAwareAccess_rightBegin (_nullAwareVariable.initializer);
3331
+ // Ensure [_nullAwareVariable] is promoted to non-nullable.
3332
+ // TODO(johnniwinther): Avoid creating a [VariableGet] to promote the
3333
+ // variable.
3334
+ VariableGet read = new VariableGet (_nullAwareVariable);
3335
+ _inferrer.flowAnalysis.variableRead (read, _nullAwareVariable);
3336
+ _inferrer.flowAnalysis.nullAwareAccess_rightBegin (read);
3337
+ }
3299
3338
3300
3339
/// Creates the null-guarded application of [nullAwareAction] with the
3301
3340
/// [inferredType] .
@@ -3307,6 +3346,10 @@ class NullAwareGuard {
3307
3346
///
3308
3347
Expression createExpression (
3309
3348
DartType inferredType, Expression nullAwareAction) {
3349
+ // End non-nullable promotion of [_nullAwareVariable].
3350
+ _inferrer.flowAnalysis.nullAwareAccess_end ();
3351
+ // End non-nullable promotion of the initializer of [_nullAwareVariable].
3352
+ _inferrer.flowAnalysis.nullAwareAccess_end ();
3310
3353
MethodInvocation equalsNull = createEqualsNull (_nullAwareFileOffset,
3311
3354
createVariableGet (_nullAwareVariable), _nullAwareEquals);
3312
3355
ConditionalExpression condition = new ConditionalExpression (
@@ -3330,28 +3373,33 @@ class NullAwareExpressionInferenceResult implements ExpressionInferenceResult {
3330
3373
final DartType inferredType;
3331
3374
3332
3375
@override
3333
- final NullAwareGuard nullAwareGuard ;
3376
+ final Link < NullAwareGuard > nullAwareGuards ;
3334
3377
3335
3378
@override
3336
3379
final Expression nullAwareAction;
3337
3380
3338
3381
Expression _expression;
3339
3382
3340
3383
NullAwareExpressionInferenceResult (
3341
- this .inferredType, this .nullAwareGuard , this .nullAwareAction)
3342
- : assert (nullAwareGuard != null ),
3384
+ this .inferredType, this .nullAwareGuards , this .nullAwareAction)
3385
+ : assert (nullAwareGuards.isNotEmpty ),
3343
3386
assert (nullAwareAction != null );
3344
3387
3345
3388
Expression get expression {
3346
3389
if (_expression == null ) {
3347
- _expression ?? =
3348
- nullAwareGuard.createExpression (inferredType, nullAwareAction);
3390
+ _expression = nullAwareAction;
3391
+ Link <NullAwareGuard > nullAwareGuard = nullAwareGuards;
3392
+ while (nullAwareGuard.isNotEmpty) {
3393
+ _expression =
3394
+ nullAwareGuard.head.createExpression (inferredType, _expression);
3395
+ nullAwareGuard = nullAwareGuard.tail;
3396
+ }
3349
3397
}
3350
3398
return _expression;
3351
3399
}
3352
3400
3353
3401
String toString () =>
3354
- 'NullAwareExpressionInferenceResult($inferredType ,$nullAwareGuard ,'
3402
+ 'NullAwareExpressionInferenceResult($inferredType ,$nullAwareGuards ,'
3355
3403
'$nullAwareAction )' ;
3356
3404
}
3357
3405
0 commit comments