@@ -75,16 +75,22 @@ class ConstantEvaluationEngine {
75
75
*/
76
76
final ConstantEvaluationValidator validator;
77
77
78
+ /** Whether we are running in strong mode. */
79
+ final bool strongMode;
80
+
78
81
/**
79
82
* Initialize a newly created [ConstantEvaluationEngine] . The [typeProvider]
80
83
* is used to access known types. [_declaredVariables] is the set of
81
84
* variables declared on the command line using '-D'. The [validator] , if
82
85
* given, is used to verify correct dependency analysis when running unit
83
86
* tests.
84
87
*/
85
- ConstantEvaluationEngine (this . typeProvider, this ._declaredVariables,
88
+ ConstantEvaluationEngine (TypeProvider typeProvider, this ._declaredVariables,
86
89
{ConstantEvaluationValidator validator, TypeSystem typeSystem})
87
- : validator =
90
+ : typeProvider = typeProvider,
91
+ strongMode =
92
+ typeProvider.objectType.element.context.analysisOptions.strongMode,
93
+ validator =
88
94
validator ?? new ConstantEvaluationValidator_ForProduction (),
89
95
typeSystem = typeSystem ?? new TypeSystemImpl ();
90
96
@@ -409,7 +415,7 @@ class ConstantEvaluationEngine {
409
415
410
416
DartObjectImpl evaluateConstructorCall (
411
417
AstNode node,
412
- NodeList <Expression > arguments,
418
+ List <Expression > arguments,
413
419
ConstructorElement constructor,
414
420
ConstantVisitor constantVisitor,
415
421
ErrorReporter errorReporter) {
@@ -515,25 +521,49 @@ class ConstantEvaluationEngine {
515
521
// so consider it an unknown value to suppress further errors.
516
522
return new DartObjectImpl .validWithUnknownValue (definingClass);
517
523
}
518
- HashMap <String , DartObjectImpl > fieldMap =
519
- new HashMap <String , DartObjectImpl >();
524
+
525
+ // In strong mode, we allow constants to have type arguments.
526
+ //
527
+ // They will be added to the lexical environment when evaluating
528
+ // subexpressions.
529
+ HashMap <String , DartObjectImpl > typeArgumentMap;
530
+ if (strongMode) {
531
+ // Instantiate the constructor with the in-scope type arguments.
532
+ definingClass = constantVisitor.evaluateType (definingClass);
533
+ constructor = ConstructorMember .from (constructorBase, definingClass);
534
+
535
+ typeArgumentMap = new HashMap <String , DartObjectImpl >.fromIterables (
536
+ definingClass.typeParameters.map ((t) => t.name),
537
+ definingClass.typeArguments.map (constantVisitor.typeConstant));
538
+ }
539
+
540
+ var fieldMap = new HashMap <String , DartObjectImpl >();
541
+ var fieldInitVisitor = new ConstantVisitor (this , errorReporter,
542
+ lexicalEnvironment: typeArgumentMap);
520
543
// Start with final fields that are initialized at their declaration site.
521
- for (FieldElement field in constructor.enclosingElement.fields) {
544
+ List <FieldElement > fields = constructor.enclosingElement.fields;
545
+ for (int i = 0 ; i < fields.length; i++ ) {
546
+ FieldElement field = fields[i];
522
547
if ((field.isFinal || field.isConst) &&
523
548
! field.isStatic &&
524
549
field is ConstFieldElementImpl ) {
525
550
validator.beforeGetFieldEvaluationResult (field);
526
- EvaluationResultImpl evaluationResult = field.evaluationResult;
551
+
552
+ DartObjectImpl fieldValue;
553
+ if (strongMode) {
554
+ fieldValue = field.constantInitializer.accept (fieldInitVisitor);
555
+ } else {
556
+ fieldValue = field.evaluationResult? .value;
557
+ }
527
558
// It is possible that the evaluation result is null.
528
559
// This happens for example when we have duplicate fields.
529
560
// class Test {final x = 1; final x = 2; const Test();}
530
- if (evaluationResult == null ) {
561
+ if (fieldValue == null ) {
531
562
continue ;
532
563
}
533
564
// Match the value and the type.
534
565
DartType fieldType =
535
566
FieldMember .from (field, constructor.returnType).type;
536
- DartObjectImpl fieldValue = evaluationResult.value;
537
567
if (fieldValue != null && ! runtimeTypeMatch (fieldValue, fieldType)) {
538
568
errorReporter.reportErrorForNode (
539
569
CheckedModeCompileTimeErrorCode
@@ -549,6 +579,7 @@ class ConstantEvaluationEngine {
549
579
new HashMap <String , DartObjectImpl >();
550
580
List <ParameterElement > parameters = constructor.parameters;
551
581
int parameterCount = parameters.length;
582
+
552
583
for (int i = 0 ; i < parameterCount; i++ ) {
553
584
ParameterElement parameter = parameters[i];
554
585
ParameterElement baseParameter = parameter;
@@ -574,12 +605,23 @@ class ConstantEvaluationEngine {
574
605
// The parameter is an optional positional parameter for which no value
575
606
// was provided, so use the default value.
576
607
validator.beforeGetParameterDefault (baseParameter);
577
- EvaluationResultImpl evaluationResult = baseParameter.evaluationResult;
578
- if (evaluationResult == null ) {
579
- // No default was provided, so the default value is null.
580
- argumentValue = typeProvider.nullObject;
581
- } else if (evaluationResult.value != null ) {
582
- argumentValue = evaluationResult.value;
608
+ if (strongMode && baseParameter is ConstVariableElement ) {
609
+ var defaultValue =
610
+ (baseParameter as ConstVariableElement ).constantInitializer;
611
+ if (defaultValue == null ) {
612
+ argumentValue = typeProvider.nullObject;
613
+ } else {
614
+ argumentValue = defaultValue.accept (fieldInitVisitor);
615
+ }
616
+ } else {
617
+ EvaluationResultImpl evaluationResult =
618
+ baseParameter.evaluationResult;
619
+ if (evaluationResult == null ) {
620
+ // No default was provided, so the default value is null.
621
+ argumentValue = typeProvider.nullObject;
622
+ } else if (evaluationResult.value != null ) {
623
+ argumentValue = evaluationResult.value;
624
+ }
583
625
}
584
626
}
585
627
if (argumentValue != null ) {
@@ -677,6 +719,7 @@ class ConstantEvaluationEngine {
677
719
if (superArguments == null ) {
678
720
superArguments = new NodeList <Expression >(null );
679
721
}
722
+
680
723
evaluateSuperConstructorCall (node, fieldMap, superConstructor,
681
724
superArguments, initializerVisitor, errorReporter);
682
725
}
@@ -688,7 +731,7 @@ class ConstantEvaluationEngine {
688
731
AstNode node,
689
732
HashMap <String , DartObjectImpl > fieldMap,
690
733
ConstructorElement superConstructor,
691
- NodeList <Expression > superArguments,
734
+ List <Expression > superArguments,
692
735
ConstantVisitor initializerVisitor,
693
736
ErrorReporter errorReporter) {
694
737
if (superConstructor != null && superConstructor.isConst) {
@@ -1231,6 +1274,7 @@ class ConstantVisitor extends UnifyingAstVisitor<DartObjectImpl> {
1231
1274
// problem - the error has already been reported.
1232
1275
return null ;
1233
1276
}
1277
+
1234
1278
return evaluationEngine.evaluateConstructorCall (
1235
1279
node, node.argumentList.arguments, constructor, this , _errorReporter);
1236
1280
}
@@ -1274,9 +1318,9 @@ class ConstantVisitor extends UnifyingAstVisitor<DartObjectImpl> {
1274
1318
return null ;
1275
1319
}
1276
1320
DartType elementType = _typeProvider.dynamicType;
1277
- if (node.typeArguments != null &&
1278
- node.typeArguments.arguments .length == 1 ) {
1279
- DartType type = node.typeArguments.arguments [0 ].type ;
1321
+ NodeList < TypeName > typeArgs = node.typeArguments ? .arguments;
1322
+ if (typeArgs ? .length == 1 ) {
1323
+ DartType type = visitTypeName (typeArgs [0 ]) ? . toTypeValue () ;
1280
1324
if (type != null ) {
1281
1325
elementType = type;
1282
1326
}
@@ -1309,13 +1353,13 @@ class ConstantVisitor extends UnifyingAstVisitor<DartObjectImpl> {
1309
1353
}
1310
1354
DartType keyType = _typeProvider.dynamicType;
1311
1355
DartType valueType = _typeProvider.dynamicType;
1312
- if (node.typeArguments != null &&
1313
- node.typeArguments.arguments .length == 2 ) {
1314
- DartType keyTypeCandidate = node.typeArguments.arguments [0 ].type ;
1356
+ NodeList < TypeName > typeArgs = node.typeArguments ? .arguments;
1357
+ if (typeArgs ? .length == 2 ) {
1358
+ DartType keyTypeCandidate = visitTypeName (typeArgs [0 ]) ? . toTypeValue () ;
1315
1359
if (keyTypeCandidate != null ) {
1316
1360
keyType = keyTypeCandidate;
1317
1361
}
1318
- DartType valueTypeCandidate = node.typeArguments.arguments [1 ].type ;
1362
+ DartType valueTypeCandidate = visitTypeName (typeArgs [1 ]) ? . toTypeValue () ;
1319
1363
if (valueTypeCandidate != null ) {
1320
1364
valueType = valueTypeCandidate;
1321
1365
}
@@ -1465,6 +1509,57 @@ class ConstantVisitor extends UnifyingAstVisitor<DartObjectImpl> {
1465
1509
_typeProvider.symbolType, new SymbolState (buffer.toString ()));
1466
1510
}
1467
1511
1512
+ @override
1513
+ DartObjectImpl visitTypeName (TypeName node) {
1514
+ DartType type = evaluateType (node.type);
1515
+ if (type == null ) {
1516
+ return super .visitTypeName (node);
1517
+ }
1518
+ return typeConstant (type);
1519
+ }
1520
+
1521
+ /**
1522
+ * Given a [type] , returns the constant value that contains that type value.
1523
+ */
1524
+ DartObjectImpl typeConstant (DartType type) {
1525
+ return new DartObjectImpl (_typeProvider.typeType, new TypeState (type));
1526
+ }
1527
+
1528
+ /**
1529
+ * Given a [type] that may contain free type variables, evaluate them against
1530
+ * the current lexical environment and return the substituted type.
1531
+ */
1532
+ DartType evaluateType (DartType type) {
1533
+ if (type is TypeParameterType ) {
1534
+ // Constants may only refer to type parameters in strong mode.
1535
+ if (! evaluationEngine.strongMode) {
1536
+ return null ;
1537
+ }
1538
+
1539
+ String name = type.name;
1540
+ if (_lexicalEnvironment != null ) {
1541
+ return _lexicalEnvironment[name]? .toTypeValue () ?? type;
1542
+ }
1543
+ return type;
1544
+ }
1545
+ if (type is ParameterizedType ) {
1546
+ List <DartType > typeArguments;
1547
+ for (int i = 0 ; i < type.typeArguments.length; i++ ) {
1548
+ DartType ta = type.typeArguments[i];
1549
+ DartType t = evaluateType (ta);
1550
+ if (! identical (t, ta)) {
1551
+ if (typeArguments == null ) {
1552
+ typeArguments = type.typeArguments.toList (growable: false );
1553
+ }
1554
+ typeArguments[i] = t;
1555
+ }
1556
+ }
1557
+ if (typeArguments == null ) return type;
1558
+ return type.substitute2 (typeArguments, type.typeArguments);
1559
+ }
1560
+ return type;
1561
+ }
1562
+
1468
1563
/**
1469
1564
* Create an error associated with the given [node] . The error will have the
1470
1565
* given error [code] .
@@ -1497,10 +1592,13 @@ class ConstantVisitor extends UnifyingAstVisitor<DartObjectImpl> {
1497
1592
}
1498
1593
return new DartObjectImpl (functionType, new FunctionState (function));
1499
1594
}
1500
- } else if (variableElement is ClassElement ||
1501
- variableElement is FunctionTypeAliasElement ||
1502
- variableElement is DynamicElementImpl ) {
1503
- return new DartObjectImpl (_typeProvider.typeType, new TypeState (element));
1595
+ } else if (variableElement is TypeDefiningElement ) {
1596
+ // Constants may only refer to type parameters in strong mode.
1597
+ if (evaluationEngine.strongMode ||
1598
+ variableElement is ! TypeParameterElement ) {
1599
+ return new DartObjectImpl (
1600
+ _typeProvider.typeType, new TypeState (variableElement.type));
1601
+ }
1504
1602
}
1505
1603
// TODO(brianwilkerson) Figure out which error to report.
1506
1604
_error (node, null );
0 commit comments