mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 12:14:36 +00:00
[analyzer] Mark const iterables unknown if there is a unknown bool in an If Statement entry
Bools from environment such as `dart.library.js_util` are represented as unknown bools. They currently produce a `NON_BOOL_CONDITION` error when used in if statements in const lists, which is not the behaviour we want. This CL marks iterables with these unknown bools in if statements as unknown and avoids other calculations like `==` upstream. Bug: https://github.com/dart-lang/sdk/issues/53363, https://github.com/dart-lang/sdk/issues/51607 Change-Id: Ibd3e6dbc6a507c93516bc2782d59d0e1e452f17d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/326261 Commit-Queue: Kallen Tu <kallentu@google.com> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
parent
aac74693f5
commit
40aacb3482
|
@ -9,7 +9,6 @@ import 'package:analyzer/dart/analysis/features.dart';
|
|||
import 'package:analyzer/dart/ast/syntactic_entity.dart';
|
||||
import 'package:analyzer/dart/ast/token.dart';
|
||||
import 'package:analyzer/dart/ast/visitor.dart';
|
||||
import 'package:analyzer/dart/constant/value.dart';
|
||||
import 'package:analyzer/dart/element/element.dart';
|
||||
import 'package:analyzer/dart/element/nullability_suffix.dart';
|
||||
import 'package:analyzer/dart/element/type.dart';
|
||||
|
@ -1008,26 +1007,19 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
|
|||
return InvalidConstant.forEntity(
|
||||
node, CompileTimeErrorCode.MISSING_CONST_IN_LIST_LITERAL);
|
||||
}
|
||||
var elements = <DartObjectImpl>[];
|
||||
for (CollectionElement element in node.elements) {
|
||||
var result = _addElementsToList(elements, element);
|
||||
if (result is InvalidConstant) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
var nodeType = node.staticType;
|
||||
DartType elementType =
|
||||
var elementType =
|
||||
nodeType is InterfaceType && nodeType.typeArguments.isNotEmpty
|
||||
? nodeType.typeArguments[0]
|
||||
: _typeProvider.dynamicType;
|
||||
InterfaceType listType = _typeProvider.listType(elementType);
|
||||
return DartObjectImpl(
|
||||
var listType = _typeProvider.listType(elementType);
|
||||
var list = <DartObjectImpl>[];
|
||||
return _buildListConstant(
|
||||
list,
|
||||
node.elements,
|
||||
typeSystem,
|
||||
listType,
|
||||
ListState(
|
||||
elementType: elementType,
|
||||
elements: elements,
|
||||
),
|
||||
elementType,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1245,22 +1237,8 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
|
|||
return InvalidConstant.forEntity(
|
||||
node, CompileTimeErrorCode.MISSING_CONST_IN_MAP_LITERAL);
|
||||
}
|
||||
Map<DartObjectImpl, DartObjectImpl> map = {};
|
||||
for (CollectionElement element in node.elements) {
|
||||
var result = _addElementsToMap(map, element);
|
||||
if (result is InvalidConstant) {
|
||||
if (!node.isMap) {
|
||||
// We don't report the error if we know this is an ambiguous map or
|
||||
// set. [CompileTimeErrorCode.AMBIGUOUS_SET_OR_MAP_LITERAL_BOTH]
|
||||
// or [CompileTimeErrorCode.AMBIGUOUS_SET_OR_MAP_LITERAL_EITHER] is
|
||||
// already reported elsewhere.
|
||||
result.avoidReporting = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
DartType keyType = _typeProvider.dynamicType;
|
||||
DartType valueType = _typeProvider.dynamicType;
|
||||
var keyType = _typeProvider.dynamicType;
|
||||
var valueType = _typeProvider.dynamicType;
|
||||
var nodeType = node.staticType;
|
||||
if (nodeType is InterfaceType) {
|
||||
var typeArguments = nodeType.typeArguments;
|
||||
|
@ -1269,27 +1247,30 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
|
|||
valueType = typeArguments[1];
|
||||
}
|
||||
}
|
||||
InterfaceType mapType = _typeProvider.mapType(keyType, valueType);
|
||||
return DartObjectImpl(typeSystem, mapType, MapState(map));
|
||||
var mapType = _typeProvider.mapType(keyType, valueType);
|
||||
var map = <DartObjectImpl, DartObjectImpl>{};
|
||||
var result = _buildMapConstant(map, node.elements, typeSystem, mapType);
|
||||
if (result is InvalidConstant && !node.isMap) {
|
||||
// We don't report the error if we know this is an ambiguous map or
|
||||
// set. [CompileTimeErrorCode.AMBIGUOUS_SET_OR_MAP_LITERAL_BOTH]
|
||||
// or [CompileTimeErrorCode.AMBIGUOUS_SET_OR_MAP_LITERAL_EITHER] is
|
||||
// already reported elsewhere.
|
||||
result.avoidReporting = true;
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
if (!node.isConst) {
|
||||
return InvalidConstant.forEntity(
|
||||
node, CompileTimeErrorCode.MISSING_CONST_IN_SET_LITERAL);
|
||||
}
|
||||
Set<DartObjectImpl> set = <DartObjectImpl>{};
|
||||
for (CollectionElement element in node.elements) {
|
||||
var result = _addElementsToSet(set, element);
|
||||
if (result is InvalidConstant) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
var nodeType = node.staticType;
|
||||
DartType elementType =
|
||||
var elementType =
|
||||
nodeType is InterfaceType && nodeType.typeArguments.isNotEmpty
|
||||
? nodeType.typeArguments[0]
|
||||
: _typeProvider.dynamicType;
|
||||
InterfaceType setType = _typeProvider.setType(elementType);
|
||||
return DartObjectImpl(typeSystem, setType, SetState(set));
|
||||
var setType = _typeProvider.setType(elementType);
|
||||
var set = <DartObjectImpl>{};
|
||||
return _buildSetConstant(set, node.elements, typeSystem, setType);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1342,11 +1323,20 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
|
|||
@override
|
||||
Constant visitTypeLiteral(TypeLiteral node) => evaluateConstant(node.type);
|
||||
|
||||
/// Add the entries produced by evaluating the given collection [element] to
|
||||
/// the given [list]. Return an [InvalidConstant] if the evaluation of one or
|
||||
/// more of the elements failed.
|
||||
InvalidConstant? _addElementsToList(
|
||||
List<DartObject> list, CollectionElement element) {
|
||||
/// Builds a list constant by adding the evaluated entries of [elements] to
|
||||
/// the given [list].
|
||||
///
|
||||
/// The [typeSystem], [listType], and [elementType] are used to create a valid
|
||||
/// constant. We return an [InvalidConstant] if the evaluation of any of the
|
||||
/// elements failed.
|
||||
Constant _buildListConstant(
|
||||
List<DartObjectImpl> list,
|
||||
List<CollectionElement> elements,
|
||||
TypeSystemImpl typeSystem,
|
||||
DartType listType,
|
||||
DartType elementType,
|
||||
) {
|
||||
for (var element in elements) {
|
||||
switch (element) {
|
||||
case Expression():
|
||||
var expression = evaluateConstant(element);
|
||||
|
@ -1355,7 +1345,6 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
|
|||
return expression;
|
||||
case DartObjectImpl():
|
||||
list.add(expression);
|
||||
return null;
|
||||
}
|
||||
case ForElement():
|
||||
return InvalidConstant.forEntity(
|
||||
|
@ -1366,17 +1355,39 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
|
|||
case InvalidConstant():
|
||||
return condition;
|
||||
case DartObjectImpl():
|
||||
var conditionValue = condition.toBoolValue();
|
||||
if (conditionValue == null) {
|
||||
return InvalidConstant.forEntity(
|
||||
element.expression, CompileTimeErrorCode.NON_BOOL_CONDITION);
|
||||
} else if (conditionValue) {
|
||||
return _addElementsToList(list, element.thenElement);
|
||||
} else if (element.elseElement != null) {
|
||||
return _addElementsToList(list, element.elseElement!);
|
||||
// If the condition is unknown, we mark this list as unknown.
|
||||
if (condition.isUnknown) {
|
||||
return DartObjectImpl.validWithUnknownValue(
|
||||
typeSystem,
|
||||
listType,
|
||||
listElementType: elementType,
|
||||
);
|
||||
}
|
||||
var conditionValue = condition.toBoolValue();
|
||||
Constant? branchResult;
|
||||
if (conditionValue == null) {
|
||||
return InvalidConstant.forEntity(element.expression,
|
||||
CompileTimeErrorCode.NON_BOOL_CONDITION);
|
||||
} else if (conditionValue) {
|
||||
branchResult = _buildListConstant(
|
||||
list,
|
||||
[element.thenElement],
|
||||
typeSystem,
|
||||
listType,
|
||||
elementType,
|
||||
);
|
||||
} else if (element.elseElement != null) {
|
||||
branchResult = _buildListConstant(
|
||||
list,
|
||||
[element.elseElement!],
|
||||
typeSystem,
|
||||
listType,
|
||||
elementType,
|
||||
);
|
||||
}
|
||||
if (branchResult is InvalidConstant) {
|
||||
return branchResult;
|
||||
}
|
||||
// There's no else element, but the condition value is false.
|
||||
return null;
|
||||
}
|
||||
case MapLiteralEntry():
|
||||
return InvalidConstant.forEntity(
|
||||
|
@ -1389,7 +1400,7 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
|
|||
case DartObjectImpl():
|
||||
// Special case for ...?
|
||||
if (spread.isNull && element.isNullAware) {
|
||||
return null;
|
||||
continue;
|
||||
}
|
||||
var listValue = spread.toListValue() ?? spread.toSetValue();
|
||||
if (listValue == null) {
|
||||
|
@ -1397,16 +1408,32 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
|
|||
CompileTimeErrorCode.CONST_SPREAD_EXPECTED_LIST_OR_SET);
|
||||
}
|
||||
list.addAll(listValue);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Add the entries produced by evaluating the given map [element] to the
|
||||
/// given [map]. Return an [InvalidConstant] if the evaluation of one or
|
||||
/// more of the elements failed.
|
||||
InvalidConstant? _addElementsToMap(
|
||||
Map<DartObjectImpl, DartObjectImpl> map, CollectionElement element) {
|
||||
return DartObjectImpl(
|
||||
typeSystem,
|
||||
listType,
|
||||
ListState(
|
||||
elementType: elementType,
|
||||
elements: list,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Builds a map constant by adding the evaluated entries of [elements] to
|
||||
/// the given [map].
|
||||
///
|
||||
/// The [typeSystem] and [mapType] are used to create a valid map constant.
|
||||
/// We return an [InvalidConstant] if the evaluation of any of the elements
|
||||
/// failed.
|
||||
Constant _buildMapConstant(
|
||||
Map<DartObjectImpl, DartObjectImpl> map,
|
||||
List<CollectionElement> elements,
|
||||
TypeSystemImpl typeSystem,
|
||||
DartType mapType) {
|
||||
for (var element in elements) {
|
||||
switch (element) {
|
||||
case Expression():
|
||||
return InvalidConstant.forEntity(
|
||||
|
@ -1420,17 +1447,26 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
|
|||
case InvalidConstant():
|
||||
return condition;
|
||||
case DartObjectImpl():
|
||||
// If the condition is unknown, we mark this map as unknown.
|
||||
if (condition.isUnknown) {
|
||||
return DartObjectImpl.validWithUnknownValue(
|
||||
typeSystem, mapType);
|
||||
}
|
||||
Constant? branchResult;
|
||||
var conditionValue = condition.toBoolValue();
|
||||
if (conditionValue == null) {
|
||||
return InvalidConstant.forEntity(
|
||||
element.expression, CompileTimeErrorCode.NON_BOOL_CONDITION);
|
||||
return InvalidConstant.forEntity(element.expression,
|
||||
CompileTimeErrorCode.NON_BOOL_CONDITION);
|
||||
} else if (conditionValue) {
|
||||
return _addElementsToMap(map, element.thenElement);
|
||||
branchResult = _buildMapConstant(
|
||||
map, [element.thenElement], typeSystem, mapType);
|
||||
} else if (element.elseElement != null) {
|
||||
return _addElementsToMap(map, element.elseElement!);
|
||||
branchResult = _buildMapConstant(
|
||||
map, [element.elseElement!], typeSystem, mapType);
|
||||
}
|
||||
if (branchResult is InvalidConstant) {
|
||||
return branchResult;
|
||||
}
|
||||
// There's no else element, but the condition value is false.
|
||||
return null;
|
||||
}
|
||||
case MapLiteralEntry():
|
||||
var keyResult = evaluateConstant(element.key);
|
||||
|
@ -1446,7 +1482,6 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
|
|||
map[keyResult] = valueResult;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
case SpreadElement():
|
||||
var spread = evaluateConstant(element.expression);
|
||||
switch (spread) {
|
||||
|
@ -1455,7 +1490,7 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
|
|||
case DartObjectImpl():
|
||||
// Special case for ...?
|
||||
if (spread.isNull && element.isNullAware) {
|
||||
return null;
|
||||
continue;
|
||||
}
|
||||
var mapValue = spread.toMapValue();
|
||||
if (mapValue == null) {
|
||||
|
@ -1463,16 +1498,25 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
|
|||
CompileTimeErrorCode.CONST_SPREAD_EXPECTED_MAP);
|
||||
}
|
||||
map.addAll(mapValue);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Add the entries produced by evaluating the given collection [element] to
|
||||
/// the given [set]. Return an [InvalidConstant] if the evaluation of one or
|
||||
/// more of the elements failed.
|
||||
InvalidConstant? _addElementsToSet(
|
||||
Set<DartObject> set, CollectionElement element) {
|
||||
return DartObjectImpl(typeSystem, mapType, MapState(map));
|
||||
}
|
||||
|
||||
/// Builds a set constant by adding the evaluated entries of [elements] to
|
||||
/// the given [set].
|
||||
///
|
||||
/// The [typeSystem] and [setType] are used to create a valid set constant.
|
||||
/// We return an [InvalidConstant] if the evaluation of any of the elements
|
||||
/// failed.
|
||||
Constant _buildSetConstant(
|
||||
Set<DartObjectImpl> set,
|
||||
List<CollectionElement> elements,
|
||||
TypeSystemImpl typeSystem,
|
||||
DartType setType) {
|
||||
for (var element in elements) {
|
||||
switch (element) {
|
||||
case Expression():
|
||||
var expression = evaluateConstant(element);
|
||||
|
@ -1481,7 +1525,6 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
|
|||
return expression;
|
||||
case DartObjectImpl():
|
||||
set.add(expression);
|
||||
return null;
|
||||
}
|
||||
case ForElement():
|
||||
return InvalidConstant.forEntity(
|
||||
|
@ -1492,17 +1535,26 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
|
|||
case InvalidConstant():
|
||||
return condition;
|
||||
case DartObjectImpl():
|
||||
// If the condition is unknown, we mark this set as unknown.
|
||||
if (condition.isUnknown) {
|
||||
return DartObjectImpl.validWithUnknownValue(
|
||||
typeSystem, setType);
|
||||
}
|
||||
Constant? branchResult;
|
||||
var conditionValue = condition.toBoolValue();
|
||||
if (conditionValue == null) {
|
||||
return InvalidConstant.forEntity(
|
||||
element.expression, CompileTimeErrorCode.NON_BOOL_CONDITION);
|
||||
return InvalidConstant.forEntity(element.expression,
|
||||
CompileTimeErrorCode.NON_BOOL_CONDITION);
|
||||
} else if (conditionValue) {
|
||||
return _addElementsToSet(set, element.thenElement);
|
||||
branchResult = _buildSetConstant(
|
||||
set, [element.thenElement], typeSystem, setType);
|
||||
} else if (element.elseElement != null) {
|
||||
return _addElementsToSet(set, element.elseElement!);
|
||||
branchResult = _buildSetConstant(
|
||||
set, [element.elseElement!], typeSystem, setType);
|
||||
}
|
||||
if (branchResult is InvalidConstant) {
|
||||
return branchResult;
|
||||
}
|
||||
// There's no else element, but the condition value is false.
|
||||
return null;
|
||||
}
|
||||
case MapLiteralEntry():
|
||||
return InvalidConstant.forEntity(
|
||||
|
@ -1515,7 +1567,7 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
|
|||
case DartObjectImpl():
|
||||
// Special case for ...?
|
||||
if (spread.isNull && element.isNullAware) {
|
||||
return null;
|
||||
continue;
|
||||
}
|
||||
var setValue = spread.toSetValue() ?? spread.toListValue();
|
||||
if (setValue == null) {
|
||||
|
@ -1523,11 +1575,13 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
|
|||
CompileTimeErrorCode.CONST_SPREAD_EXPECTED_LIST_OR_SET);
|
||||
}
|
||||
set.addAll(setValue);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return DartObjectImpl(typeSystem, setType, SetState(set));
|
||||
}
|
||||
|
||||
/// Returns the result of concatenating [astNodes].
|
||||
///
|
||||
/// If there's an [InvalidConstant] found, it will return early.
|
||||
|
|
|
@ -192,15 +192,24 @@ class DartObjectImpl implements DartObject, Constant {
|
|||
|
||||
/// Create an object to represent an unknown value.
|
||||
factory DartObjectImpl.validWithUnknownValue(
|
||||
TypeSystemImpl typeSystem,
|
||||
DartType type,
|
||||
) {
|
||||
TypeSystemImpl typeSystem, DartType type,
|
||||
{DartType? listElementType}) {
|
||||
if (type.isDartCoreBool) {
|
||||
return DartObjectImpl(typeSystem, type, BoolState.UNKNOWN_VALUE);
|
||||
} else if (type.isDartCoreDouble) {
|
||||
return DartObjectImpl(typeSystem, type, DoubleState.UNKNOWN_VALUE);
|
||||
} else if (type.isDartCoreInt) {
|
||||
return DartObjectImpl(typeSystem, type, IntState.UNKNOWN_VALUE);
|
||||
} else if (type.isDartCoreList) {
|
||||
return DartObjectImpl(
|
||||
typeSystem,
|
||||
type,
|
||||
ListState.unknown(
|
||||
listElementType ?? typeSystem.typeProvider.dynamicType));
|
||||
} else if (type.isDartCoreMap) {
|
||||
return DartObjectImpl(typeSystem, type, MapState.UNKNOWN);
|
||||
} else if (type.isDartCoreSet) {
|
||||
return DartObjectImpl(typeSystem, type, SetState.UNKNOWN);
|
||||
} else if (type.isDartCoreString) {
|
||||
return DartObjectImpl(typeSystem, type, StringState.UNKNOWN_VALUE);
|
||||
}
|
||||
|
@ -2472,10 +2481,18 @@ class ListState extends InstanceState {
|
|||
final DartType elementType;
|
||||
final List<DartObjectImpl> elements;
|
||||
|
||||
/// Whether the list contains an element that has an unknown value.
|
||||
final bool _isUnknown;
|
||||
|
||||
ListState({
|
||||
required this.elementType,
|
||||
required this.elements,
|
||||
});
|
||||
bool isUnknown = false,
|
||||
}) : _isUnknown = isUnknown;
|
||||
|
||||
/// Creates a state that represents a list whose value is not known.
|
||||
factory ListState.unknown(DartType elementType) =>
|
||||
ListState(elementType: elementType, elements: [], isUnknown: true);
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
|
@ -2487,6 +2504,9 @@ class ListState extends InstanceState {
|
|||
return value;
|
||||
}
|
||||
|
||||
@override
|
||||
bool get isUnknown => _isUnknown;
|
||||
|
||||
@override
|
||||
String get typeName => "List";
|
||||
|
||||
|
@ -2523,6 +2543,9 @@ class ListState extends InstanceState {
|
|||
|
||||
@override
|
||||
BoolState isIdentical(TypeSystemImpl typeSystem, InstanceState rightOperand) {
|
||||
if (isUnknown || rightOperand.isUnknown) {
|
||||
return BoolState.UNKNOWN_VALUE;
|
||||
}
|
||||
return BoolState.from(this == rightOperand);
|
||||
}
|
||||
|
||||
|
@ -2546,12 +2569,18 @@ class ListState extends InstanceState {
|
|||
|
||||
/// The state of an object representing a map.
|
||||
class MapState extends InstanceState {
|
||||
/// A state that represents a map whose value is not known.
|
||||
static MapState UNKNOWN = MapState({}, isUnknown: true);
|
||||
|
||||
/// The entries in the map.
|
||||
final Map<DartObjectImpl, DartObjectImpl> entries;
|
||||
|
||||
/// Initialize a newly created state to represent a map with the given
|
||||
/// Whether the map contains an entry that has an unknown value.
|
||||
final bool _isUnknown;
|
||||
|
||||
/// Initializes a newly created state to represent a map with the given
|
||||
/// [entries].
|
||||
MapState(this.entries);
|
||||
MapState(this.entries, {bool isUnknown = false}) : _isUnknown = isUnknown;
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
|
@ -2562,6 +2591,9 @@ class MapState extends InstanceState {
|
|||
return value;
|
||||
}
|
||||
|
||||
@override
|
||||
bool get isUnknown => _isUnknown;
|
||||
|
||||
@override
|
||||
String get typeName => "Map";
|
||||
|
||||
|
@ -2600,6 +2632,9 @@ class MapState extends InstanceState {
|
|||
|
||||
@override
|
||||
BoolState isIdentical(TypeSystemImpl typeSystem, InstanceState rightOperand) {
|
||||
if (isUnknown || rightOperand.isUnknown) {
|
||||
return BoolState.UNKNOWN_VALUE;
|
||||
}
|
||||
return BoolState.from(this == rightOperand);
|
||||
}
|
||||
|
||||
|
@ -2818,12 +2853,18 @@ class RecordState extends InstanceState {
|
|||
|
||||
/// The state of an object representing a set.
|
||||
class SetState extends InstanceState {
|
||||
/// A state that represents a set whose value is not known.
|
||||
static SetState UNKNOWN = SetState({}, isUnknown: true);
|
||||
|
||||
/// The elements of the set.
|
||||
final Set<DartObjectImpl> elements;
|
||||
|
||||
/// Initialize a newly created state to represent a set with the given
|
||||
/// Whether the set contains an entry that has an unknown value.
|
||||
final bool _isUnknown;
|
||||
|
||||
/// Initializes a newly created state to represent a set with the given
|
||||
/// [elements].
|
||||
SetState(this.elements);
|
||||
SetState(this.elements, {bool isUnknown = false}) : _isUnknown = isUnknown;
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
|
@ -2834,6 +2875,9 @@ class SetState extends InstanceState {
|
|||
return value;
|
||||
}
|
||||
|
||||
@override
|
||||
bool get isUnknown => _isUnknown;
|
||||
|
||||
@override
|
||||
String get typeName => "Set";
|
||||
|
||||
|
@ -2871,6 +2915,9 @@ class SetState extends InstanceState {
|
|||
|
||||
@override
|
||||
BoolState isIdentical(TypeSystemImpl typeSystem, InstanceState rightOperand) {
|
||||
if (isUnknown || rightOperand.isUnknown) {
|
||||
return BoolState.UNKNOWN_VALUE;
|
||||
}
|
||||
return BoolState.from(this == rightOperand);
|
||||
}
|
||||
|
||||
|
|
|
@ -4476,16 +4476,166 @@ A
|
|||
|
||||
/// See https://github.com/dart-lang/sdk/issues/50045
|
||||
test_bool_fromEnvironment_dartLibraryJsUtil() async {
|
||||
await resolveTestCode('''
|
||||
await assertNoErrorsInCode('''
|
||||
const a = bool.fromEnvironment('dart.library.js_util');
|
||||
''');
|
||||
|
||||
assertDartObjectText(_topLevelVar('a'), '''
|
||||
final result = _topLevelVar('a');
|
||||
assertDartObjectText(result, '''
|
||||
<unknown> bool
|
||||
variable: self::@variable::a
|
||||
''');
|
||||
}
|
||||
|
||||
test_bool_fromEnvironment_dartLibraryJsUtil_ifStatement_list() async {
|
||||
await assertNoErrorsInCode('''
|
||||
const a = bool.fromEnvironment('dart.library.js_util');
|
||||
const x = [3, if (a) ...[1] else ...[1, 2], 4];
|
||||
''');
|
||||
final result = _topLevelVar('x');
|
||||
assertDartObjectText(result, '''
|
||||
<unknown> List<int>
|
||||
variable: self::@variable::x
|
||||
''');
|
||||
}
|
||||
|
||||
test_bool_fromEnvironment_dartLibraryJsUtil_ifStatement_list_eqeq_known() async {
|
||||
await assertNoErrorsInCode('''
|
||||
const a = bool.fromEnvironment('dart.library.js_util');
|
||||
const b = [3, if (a) ...[1] else ...[1, 2], 4];
|
||||
const left = [3, 1, 2, 4] == b;
|
||||
const right = b == [3, 1, 2, 4];
|
||||
''');
|
||||
final leftResult = _topLevelVar('left');
|
||||
assertDartObjectText(leftResult, '''
|
||||
<unknown> bool
|
||||
variable: self::@variable::left
|
||||
''');
|
||||
final rightResult = _topLevelVar('right');
|
||||
assertDartObjectText(rightResult, '''
|
||||
<unknown> bool
|
||||
variable: self::@variable::right
|
||||
''');
|
||||
}
|
||||
|
||||
test_bool_fromEnvironment_dartLibraryJsUtil_ifStatement_list_eqeq_unknown() async {
|
||||
await assertNoErrorsInCode('''
|
||||
const a = bool.fromEnvironment('dart.library.js_util');
|
||||
const b = [3, if (a) ...[1] else ...[1, 2], 4];
|
||||
const left = [3, if (a) ...[1] else ...[1, 2], 4] == b;
|
||||
const right = b == [3, if (a) ...[1] else ...[1, 2], 4];
|
||||
''');
|
||||
final leftResult = _topLevelVar('left');
|
||||
assertDartObjectText(leftResult, '''
|
||||
<unknown> bool
|
||||
variable: self::@variable::left
|
||||
''');
|
||||
final rightResult = _topLevelVar('right');
|
||||
assertDartObjectText(rightResult, '''
|
||||
<unknown> bool
|
||||
variable: self::@variable::right
|
||||
''');
|
||||
}
|
||||
|
||||
test_bool_fromEnvironment_dartLibraryJsUtil_ifStatement_map() async {
|
||||
await assertNoErrorsInCode('''
|
||||
const a = bool.fromEnvironment('dart.library.js_util');
|
||||
const x = {3:'3', if (a) 1:'1' else 2:'2', 4:'4'};
|
||||
''');
|
||||
final result = _topLevelVar('x');
|
||||
assertDartObjectText(result, '''
|
||||
<unknown> Map<int, String>
|
||||
variable: self::@variable::x
|
||||
''');
|
||||
}
|
||||
|
||||
test_bool_fromEnvironment_dartLibraryJsUtil_ifStatement_map_eqeq_known() async {
|
||||
await assertNoErrorsInCode('''
|
||||
const a = bool.fromEnvironment('dart.library.js_util');
|
||||
const b = {3:'3', if (a) 1:'1' else 2:'2', 4:'4'};
|
||||
const left = {3:'3', 2:'2', 4:'4'} == b;
|
||||
const right = b == {3:'3', 2:'2', 4:'4'};
|
||||
''');
|
||||
final leftResult = _topLevelVar('left');
|
||||
assertDartObjectText(leftResult, '''
|
||||
<unknown> bool
|
||||
variable: self::@variable::left
|
||||
''');
|
||||
final rightResult = _topLevelVar('right');
|
||||
assertDartObjectText(rightResult, '''
|
||||
<unknown> bool
|
||||
variable: self::@variable::right
|
||||
''');
|
||||
}
|
||||
|
||||
test_bool_fromEnvironment_dartLibraryJsUtil_ifStatement_map_eqeq_unknown() async {
|
||||
await assertNoErrorsInCode('''
|
||||
const a = bool.fromEnvironment('dart.library.js_util');
|
||||
const b = {3:'3', if (a) 1:'1' else 2:'2', 4:'4'};
|
||||
const left = {3:'3', if (a) 1:'1' else 2:'2', 4:'4'} == b;
|
||||
const right = b == {3:'3', if (a) 1:'1' else 2:'2', 4:'4'};
|
||||
''');
|
||||
final leftResult = _topLevelVar('left');
|
||||
assertDartObjectText(leftResult, '''
|
||||
<unknown> bool
|
||||
variable: self::@variable::left
|
||||
''');
|
||||
final rightResult = _topLevelVar('right');
|
||||
assertDartObjectText(rightResult, '''
|
||||
<unknown> bool
|
||||
variable: self::@variable::right
|
||||
''');
|
||||
}
|
||||
|
||||
test_bool_fromEnvironment_dartLibraryJsUtil_ifStatement_set() async {
|
||||
await assertNoErrorsInCode('''
|
||||
const a = bool.fromEnvironment('dart.library.js_util');
|
||||
const x = {3, if (a) ...[1] else ...[1, 2], 4};
|
||||
''');
|
||||
final result = _topLevelVar('x');
|
||||
assertDartObjectText(result, '''
|
||||
<unknown> Set<int>
|
||||
variable: self::@variable::x
|
||||
''');
|
||||
}
|
||||
|
||||
test_bool_fromEnvironment_dartLibraryJsUtil_ifStatement_set_eqeq_known() async {
|
||||
await assertNoErrorsInCode('''
|
||||
const a = bool.fromEnvironment('dart.library.js_util');
|
||||
const b = {3, if (a) ...[1] else ...[1, 2], 4};
|
||||
const left = {3, 1, 4} == b;
|
||||
const right = b == {3, 1, 4};
|
||||
''');
|
||||
final leftResult = _topLevelVar('left');
|
||||
assertDartObjectText(leftResult, '''
|
||||
<unknown> bool
|
||||
variable: self::@variable::left
|
||||
''');
|
||||
final rightResult = _topLevelVar('right');
|
||||
assertDartObjectText(rightResult, '''
|
||||
<unknown> bool
|
||||
variable: self::@variable::right
|
||||
''');
|
||||
}
|
||||
|
||||
test_bool_fromEnvironment_dartLibraryJsUtil_ifStatement_set_eqeq_unknown() async {
|
||||
await assertNoErrorsInCode('''
|
||||
const a = bool.fromEnvironment('dart.library.js_util');
|
||||
const b = {3, if (a) ...[1] else ...[1, 2], 4};
|
||||
const left = {3, if (a) ...[1] else ...[1, 2], 4} == b;
|
||||
const right = b == {3, if (a) ...[1] else ...[1, 2], 4};
|
||||
''');
|
||||
final leftResult = _topLevelVar('left');
|
||||
assertDartObjectText(leftResult, '''
|
||||
<unknown> bool
|
||||
variable: self::@variable::left
|
||||
''');
|
||||
final rightResult = _topLevelVar('right');
|
||||
assertDartObjectText(rightResult, '''
|
||||
<unknown> bool
|
||||
variable: self::@variable::right
|
||||
''');
|
||||
}
|
||||
|
||||
test_fieldInitializer_functionReference_withTypeParameter() async {
|
||||
await assertNoErrorsInCode('''
|
||||
void g<U>(U a) {}
|
||||
|
|
|
@ -198,17 +198,6 @@ B g() => B([f()]);
|
|||
assertCanBeConst("B([", false);
|
||||
}
|
||||
|
||||
void test_false_argument_list_nonBool() async {
|
||||
await resolve('''
|
||||
const bool kIsWeb = bool.fromEnvironment('dart.library.js_util');
|
||||
class A {
|
||||
const A(List<int> l);
|
||||
}
|
||||
A f() => A([if (!kIsWeb) ...[1, 2, 3] else ...[1]]);
|
||||
''');
|
||||
assertCanBeConst("A([", false);
|
||||
}
|
||||
|
||||
void test_false_argument_nonConstConstructor() async {
|
||||
await resolve('''
|
||||
class A {}
|
||||
|
@ -274,6 +263,17 @@ f<U>() => A<U>();
|
|||
assertCanBeConst("A<U>", false);
|
||||
}
|
||||
|
||||
void test_true_argument_list_nonBool() async {
|
||||
await resolve('''
|
||||
const bool kIsWeb = bool.fromEnvironment('dart.library.js_util');
|
||||
class A {
|
||||
const A(List<int> l);
|
||||
}
|
||||
A f() => A([if (!kIsWeb) ...[1, 2, 3] else ...[1]]);
|
||||
''');
|
||||
assertCanBeConst("A([", true);
|
||||
}
|
||||
|
||||
void test_true_computeDependencies() async {
|
||||
newFile('$testPackageLibPath/a.dart', r'''
|
||||
const a = 0;
|
||||
|
|
Loading…
Reference in a new issue