[cfe] Remove isNonNullableByDefault from TypeSchemaEnvironment

Change-Id: Ife1951833bf5e6f5146e33734ae3b0cd3805bdc7
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/368640
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
This commit is contained in:
Johnni Winther 2024-05-30 12:34:59 +00:00 committed by Commit Queue
parent 450ddd82f8
commit 1b9ccb9b08
14 changed files with 265 additions and 400 deletions

View file

@ -53,15 +53,13 @@ abstract class ClosureContext {
if (isGenerator) {
if (isAsync) {
DartType yieldContext = inferrer.getTypeArgumentOf(
inferrer.typeSchemaEnvironment
.getUnionFreeType(returnContext, isNonNullableByDefault: true),
inferrer.typeSchemaEnvironment.getUnionFreeType(returnContext),
inferrer.coreTypes.streamClass);
return new _AsyncStarClosureContext(
inferrer, yieldContext, declaredReturnType, needToInferReturnType);
} else {
DartType yieldContext = inferrer.getTypeArgumentOf(
inferrer.typeSchemaEnvironment
.getUnionFreeType(returnContext, isNonNullableByDefault: true),
inferrer.typeSchemaEnvironment.getUnionFreeType(returnContext),
inferrer.coreTypes.iterableClass);
return new _SyncStarClosureContext(
inferrer, yieldContext, declaredReturnType, needToInferReturnType);
@ -313,8 +311,7 @@ class _SyncClosureContext implements ClosureContext {
_returnExpressionTypes![i]);
}
return _inferredReturnType =
demoteTypeInLibrary(inferredReturnType, isNonNullableByDefault: true);
return _inferredReturnType = demoteTypeInLibrary(inferredReturnType);
}
@override
@ -603,8 +600,7 @@ class _AsyncClosureContext implements ClosureContext {
inferredType, _returnStatements![i], _returnExpressionTypes![i]);
}
return _inferredReturnType =
demoteTypeInLibrary(inferredType, isNonNullableByDefault: true);
return _inferredReturnType = demoteTypeInLibrary(inferredType);
}
@override
@ -764,11 +760,9 @@ class _SyncStarClosureContext implements ClosureContext {
inferredType = inferrer.computeGreatestClosure2(_declaredReturnType);
}
DartType demotedType =
demoteTypeInLibrary(inferredType, isNonNullableByDefault: true);
DartType demotedType = demoteTypeInLibrary(inferredType);
_emittedValueType = inferrer.getTypeArgumentOf(
inferrer.typeSchemaEnvironment
.getUnionFreeType(demotedType, isNonNullableByDefault: true),
inferrer.typeSchemaEnvironment.getUnionFreeType(demotedType),
inferrer.coreTypes.iterableClass);
return demotedType;
}
@ -900,11 +894,9 @@ class _AsyncStarClosureContext implements ClosureContext {
inferredType = inferrer.computeGreatestClosure2(_declaredReturnType);
}
DartType demotedType =
demoteTypeInLibrary(inferredType, isNonNullableByDefault: true);
DartType demotedType = demoteTypeInLibrary(inferredType);
_emittedValueType = inferrer.getTypeArgumentOf(
inferrer.typeSchemaEnvironment
.getUnionFreeType(demotedType, isNonNullableByDefault: true),
inferrer.typeSchemaEnvironment.getUnionFreeType(demotedType),
inferrer.coreTypes.streamClass);
return demotedType;
}

View file

@ -2664,14 +2664,12 @@ class InferenceVisitorImpl extends InferenceVisitorBase
if (inferenceNeeded) {
gatherer = typeSchemaEnvironment.setupGenericTypeInference(
listType, typeParametersToInfer, typeContext,
isNonNullableByDefault: true,
isConst: node.isConst,
typeOperations: operations,
inferenceResultForTesting: dataForTesting?.typeInferenceResult,
treeNodeForTesting: node);
inferredTypes = typeSchemaEnvironment.choosePreliminaryTypes(
gatherer, typeParametersToInfer, null,
isNonNullableByDefault: true);
gatherer, typeParametersToInfer, null);
inferredTypeArgument = inferredTypes[0];
} else {
inferredTypeArgument = node.typeArgument;
@ -2689,8 +2687,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
gatherer!.constrainArguments(formalTypes, actualTypes,
treeNodeForTesting: node);
inferredTypes = typeSchemaEnvironment.chooseFinalTypes(
gatherer, typeParametersToInfer, inferredTypes!,
isNonNullableByDefault: true);
gatherer, typeParametersToInfer, inferredTypes!);
if (dataForTesting != null) {
dataForTesting!.typeInferenceResult.inferredTypeArguments[node] =
inferredTypes;
@ -4637,14 +4634,12 @@ class InferenceVisitorImpl extends InferenceVisitorBase
if (inferenceNeeded) {
gatherer = typeSchemaEnvironment.setupGenericTypeInference(
mapType, typeParametersToInfer, typeContext,
isNonNullableByDefault: true,
isConst: node.isConst,
typeOperations: operations,
inferenceResultForTesting: dataForTesting?.typeInferenceResult,
treeNodeForTesting: node);
inferredTypes = typeSchemaEnvironment.choosePreliminaryTypes(
gatherer, typeParametersToInfer, null,
isNonNullableByDefault: true);
gatherer, typeParametersToInfer, null);
inferredKeyType = inferredTypes[0];
inferredValueType = inferredTypes[1];
} else {
@ -4715,19 +4710,16 @@ class InferenceVisitorImpl extends InferenceVisitorBase
TypeConstraintGatherer gatherer =
typeSchemaEnvironment.setupGenericTypeInference(
setType, typeParametersToInfer, typeContext,
isNonNullableByDefault: true,
isConst: node.isConst,
typeOperations: operations,
inferenceResultForTesting: dataForTesting?.typeInferenceResult,
treeNodeForTesting: node);
List<DartType> inferredTypesForSet = typeSchemaEnvironment
.choosePreliminaryTypes(gatherer, typeParametersToInfer, null,
isNonNullableByDefault: true);
.choosePreliminaryTypes(gatherer, typeParametersToInfer, null);
gatherer.constrainArguments(formalTypesForSet, actualTypesForSet,
treeNodeForTesting: node);
inferredTypesForSet = typeSchemaEnvironment.chooseFinalTypes(
gatherer, typeParametersToInfer, inferredTypesForSet,
isNonNullableByDefault: true);
gatherer, typeParametersToInfer, inferredTypesForSet);
DartType inferredTypeArgument = inferredTypesForSet[0];
instrumentation?.record(
uriForInstrumentation,
@ -4767,8 +4759,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
gatherer!.constrainArguments(formalTypes, actualTypes,
treeNodeForTesting: node);
inferredTypes = typeSchemaEnvironment.chooseFinalTypes(
gatherer, typeParametersToInfer, inferredTypes!,
isNonNullableByDefault: true);
gatherer, typeParametersToInfer, inferredTypes!);
if (dataForTesting != null) {
dataForTesting!.typeInferenceResult.inferredTypeArguments[node] =
inferredTypes;
@ -6160,8 +6151,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
if (isSpecialCasedBinaryOperator) {
rightContextType =
typeSchemaEnvironment.getContextTypeOfSpecialCasedBinaryOperator(
contextType, leftType, rightType,
isNonNullableByDefault: true);
contextType, leftType, rightType);
}
ExpressionInferenceResult rightResult =
@ -6172,8 +6162,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
if (isSpecialCasedBinaryOperator) {
binaryType = typeSchemaEnvironment.getTypeOfSpecialCasedBinaryOperator(
leftType, rightResult.inferredType,
isNonNullableByDefault: true);
leftType, rightResult.inferredType);
}
Expression binary;
@ -7945,14 +7934,12 @@ class InferenceVisitorImpl extends InferenceVisitorBase
if (inferenceNeeded) {
gatherer = typeSchemaEnvironment.setupGenericTypeInference(
setType, typeParametersToInfer, typeContext,
isNonNullableByDefault: true,
isConst: node.isConst,
typeOperations: operations,
inferenceResultForTesting: dataForTesting?.typeInferenceResult,
treeNodeForTesting: node);
inferredTypes = typeSchemaEnvironment.choosePreliminaryTypes(
gatherer, typeParametersToInfer, null,
isNonNullableByDefault: true);
gatherer, typeParametersToInfer, null);
inferredTypeArgument = inferredTypes[0];
} else {
inferredTypeArgument = node.typeArgument;
@ -7971,8 +7958,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
gatherer!.constrainArguments(formalTypes, actualTypes,
treeNodeForTesting: node);
inferredTypes = typeSchemaEnvironment.chooseFinalTypes(
gatherer, typeParametersToInfer, inferredTypes!,
isNonNullableByDefault: true);
gatherer, typeParametersToInfer, inferredTypes!);
if (dataForTesting != null) {
dataForTesting!.typeInferenceResult.inferredTypeArguments[node] =
inferredTypes;
@ -10226,8 +10212,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
node.minusType = replaceReturnType(
minusTarget.getFunctionType(this),
typeSchemaEnvironment.getTypeOfSpecialCasedBinaryOperator(
lengthType, coreTypes.intNonNullableRawType,
isNonNullableByDefault: true));
lengthType, coreTypes.intNonNullableRawType));
ObjectAccessTarget indexGetTarget = findInterfaceMember(
lookupType, indexGetName, node.fileOffset,
@ -10926,13 +10911,11 @@ class InferenceVisitorImpl extends InferenceVisitorBase
TypeConstraintGatherer gatherer =
typeSchemaEnvironment.setupGenericTypeInference(
declaredType, typeParametersToInfer, contextType,
isNonNullableByDefault: true,
typeOperations: operations,
inferenceResultForTesting: dataForTesting?.typeInferenceResult,
treeNodeForTesting: treeNodeForTesting);
return typeSchemaEnvironment.chooseFinalTypes(
gatherer, typeParametersToInfer, null,
isNonNullableByDefault: true);
gatherer, typeParametersToInfer, null);
}
@override

View file

@ -947,15 +947,13 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
new List<DartType>.filled(typeParameters.length, const UnknownType());
TypeConstraintGatherer gatherer = typeSchemaEnvironment
.setupGenericTypeInference(null, typeParameters, null,
isNonNullableByDefault: true,
typeOperations: cfeOperations,
inferenceResultForTesting: dataForTesting?.typeInferenceResult,
treeNodeForTesting: treeNodeForTesting);
gatherer.constrainArguments([onType], [receiverType],
treeNodeForTesting: treeNodeForTesting);
inferredTypes = typeSchemaEnvironment.chooseFinalTypes(
gatherer, typeParameters, inferredTypes,
isNonNullableByDefault: true);
gatherer, typeParameters, inferredTypes);
return inferredTypes;
}
@ -1391,7 +1389,7 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
// not spec'ed anywhere.
return const DynamicType();
} else {
return demoteTypeInLibrary(initializerType, isNonNullableByDefault: true);
return demoteTypeInLibrary(initializerType);
}
}
@ -1622,13 +1620,11 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
}
gatherer = typeSchemaEnvironment.setupGenericTypeInference(
calleeType.returnType, calleeTypeParameters, typeContext,
isNonNullableByDefault: true,
typeOperations: cfeOperations,
inferenceResultForTesting: dataForTesting?.typeInferenceResult,
treeNodeForTesting: arguments);
inferredTypes = typeSchemaEnvironment.choosePreliminaryTypes(
gatherer, calleeTypeParameters, null,
isNonNullableByDefault: true);
gatherer, calleeTypeParameters, null);
instantiator = new FunctionTypeInstantiator.fromIterables(
calleeTypeParameters, inferredTypes);
} else if (explicitTypeArguments != null &&
@ -1696,13 +1692,11 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
if (isSpecialCasedBinaryOperator) {
inferredFormalType =
typeSchemaEnvironment.getContextTypeOfSpecialCasedBinaryOperator(
typeContext, receiverType!, inferredFormalType,
isNonNullableByDefault: true);
typeContext, receiverType!, inferredFormalType);
} else if (isSpecialCasedTernaryOperator) {
inferredFormalType =
typeSchemaEnvironment.getContextTypeOfSpecialCasedTernaryOperator(
typeContext, receiverType!, inferredFormalType,
isNonNullableByDefault: true);
typeContext, receiverType!, inferredFormalType);
}
}
return visitor.inferExpression(argumentExpression, inferredFormalType);
@ -1801,8 +1795,7 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
.planReconciliationStages()) {
if (gatherer != null && !isFirstStage) {
inferredTypes = typeSchemaEnvironment.choosePreliminaryTypes(
gatherer, calleeTypeParameters, inferredTypes,
isNonNullableByDefault: true);
gatherer, calleeTypeParameters, inferredTypes);
instantiator = new FunctionTypeInstantiator.fromIterables(
calleeTypeParameters, inferredTypes);
}
@ -1863,8 +1856,7 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
calleeType = replaceReturnType(
calleeType,
typeSchemaEnvironment.getTypeOfSpecialCasedBinaryOperator(
receiverType!, actualTypes[0],
isNonNullableByDefault: true));
receiverType!, actualTypes[0]));
} else if (isSpecialCasedTernaryOperator) {
calleeType = replaceReturnType(
calleeType,
@ -1905,8 +1897,7 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
if (inferenceNeeded) {
inferredTypes = typeSchemaEnvironment.chooseFinalTypes(
gatherer!, calleeTypeParameters, inferredTypes!,
isNonNullableByDefault: true);
gatherer!, calleeTypeParameters, inferredTypes!);
assert(inferredTypes.every((type) => isKnown(type)),
"Unknown type(s) in inferred types: $inferredTypes.");
assert(inferredTypes.every((type) => !hasPromotedTypeVariable(type)),
@ -2114,8 +2105,7 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
}
instrumentation?.record(uriForInstrumentation, formal.fileOffset,
'type', new InstrumentationValueForType(inferredType));
formal.type =
demoteTypeInLibrary(inferredType, isNonNullableByDefault: true);
formal.type = demoteTypeInLibrary(inferredType);
if (dataForTesting != null) {
dataForTesting!.typeInferenceResult.inferredVariableTypes[formal] =
formal.type;
@ -3451,13 +3441,11 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
TypeConstraintGatherer gatherer =
typeSchemaEnvironment.setupGenericTypeInference(
instantiatedType, typeParameters, context,
isNonNullableByDefault: true,
typeOperations: cfeOperations,
inferenceResultForTesting: dataForTesting?.typeInferenceResult,
treeNodeForTesting: treeNodeForTesting);
inferredTypes = typeSchemaEnvironment.chooseFinalTypes(
gatherer, typeParameters, inferredTypes,
isNonNullableByDefault: true);
gatherer, typeParameters, inferredTypes);
FunctionTypeInstantiator instantiator =
new FunctionTypeInstantiator.fromIterables(
typeParameters, inferredTypes);

View file

@ -508,17 +508,15 @@ class InstanceAccessTarget extends ObjectAccessTarget {
@override
bool isSpecialCasedBinaryOperator(InferenceVisitorBase base) {
return member is Procedure &&
base.typeSchemaEnvironment.isSpecialCasesBinaryForReceiverType(
member as Procedure, receiverType,
isNonNullableByDefault: true);
base.typeSchemaEnvironment
.isSpecialCasedBinaryOperator(member as Procedure);
}
@override
bool isSpecialCasedTernaryOperator(InferenceVisitorBase base) {
return member is Procedure &&
base.typeSchemaEnvironment.isSpecialCasedTernaryOperator(
member as Procedure,
isNonNullableByDefault: true);
base.typeSchemaEnvironment
.isSpecialCasedTernaryOperator(member as Procedure);
}
@override

View file

@ -32,8 +32,6 @@ class TypeConstraintGatherer {
final List<StructuralParameter> _parametersToConstrain;
final bool _isNonNullableByDefault;
final OperationsCfe typeOperations;
final TypeSchemaEnvironment _environment;
@ -42,11 +40,9 @@ class TypeConstraintGatherer {
TypeConstraintGatherer(
this._environment, Iterable<StructuralParameter> typeParameters,
{required bool isNonNullableByDefault,
required OperationsCfe typeOperations,
{required OperationsCfe typeOperations,
required TypeInferenceResultForTesting? inferenceResultForTesting})
: typeOperations = typeOperations,
_isNonNullableByDefault = isNonNullableByDefault,
_parametersToConstrain =
new List<StructuralParameter>.of(typeParameters),
_inferenceResultForTesting = inferenceResultForTesting;
@ -76,8 +72,7 @@ class TypeConstraintGatherer {
}
/// Returns the set of type constraints that was gathered.
Map<StructuralParameter, MergedTypeConstraint> computeConstraints(
{required bool isNonNullableByDefault}) {
Map<StructuralParameter, MergedTypeConstraint> computeConstraints() {
Map<StructuralParameter, MergedTypeConstraint> result = {};
for (StructuralParameter parameter in _parametersToConstrain) {
result[parameter] = new MergedTypeConstraint(
@ -98,13 +93,8 @@ class TypeConstraintGatherer {
/// a subtype of [type] under any set of constraints.
bool tryConstrainLower(DartType type, DartType bound,
{required TreeNode? treeNodeForTesting}) {
if (_isNonNullableByDefault) {
return _tryNullabilityAwareSubtypeMatch(bound, type,
constrainSupertype: true, treeNodeForTesting: treeNodeForTesting);
} else {
return _tryNullabilityObliviousSubtypeMatch(bound, type,
treeNodeForTesting: treeNodeForTesting);
}
return _tryNullabilityAwareSubtypeMatch(bound, type,
constrainSupertype: true, treeNodeForTesting: treeNodeForTesting);
}
/// Tries to constrain type parameters in [type], so that [type] <: [bound].
@ -113,13 +103,8 @@ class TypeConstraintGatherer {
/// a subtype of [bound] under any set of constraints.
bool tryConstrainUpper(DartType type, DartType bound,
{required TreeNode? treeNodeForTesting}) {
if (_isNonNullableByDefault) {
return _tryNullabilityAwareSubtypeMatch(type, bound,
constrainSupertype: false, treeNodeForTesting: treeNodeForTesting);
} else {
return _tryNullabilityObliviousSubtypeMatch(type, bound,
treeNodeForTesting: treeNodeForTesting);
}
return _tryNullabilityAwareSubtypeMatch(type, bound,
constrainSupertype: false, treeNodeForTesting: treeNodeForTesting);
}
/// Tries to match [subtype] against [supertype].

View file

@ -26,21 +26,10 @@ class _HasPromotedTypeVariableVisitor extends FindTypeVisitor {
/// If [library] is non-nullable by default all legacy types have been replaced
/// with non-nullable types. Otherwise all non-legacy types have been replaced
/// with legacy types.
DartType demoteTypeInLibrary(DartType type,
{required bool isNonNullableByDefault}) {
if (isNonNullableByDefault) {
return type.accept1(
const _DemotionNullabilityNormalization(
demoteTypeVariables: true, forNonNullableByDefault: true),
Variance.covariant) ??
type;
} else {
return type.accept1(
const _DemotionNullabilityNormalization(
demoteTypeVariables: true, forNonNullableByDefault: false),
Variance.covariant) ??
type;
}
DartType demoteTypeInLibrary(DartType type) {
return type.accept1(
const _DemotionNullabilityNormalization(), Variance.covariant) ??
type;
}
/// Visitor that replaces all promoted type variables the type variable itself
@ -48,23 +37,12 @@ DartType demoteTypeInLibrary(DartType type,
///
/// The visitor returns `null` if the type wasn't changed.
class _DemotionNullabilityNormalization extends ReplacementVisitor {
final bool demoteTypeVariables;
final bool forNonNullableByDefault;
const _DemotionNullabilityNormalization(
{required this.demoteTypeVariables,
required this.forNonNullableByDefault});
const _DemotionNullabilityNormalization();
@override
Nullability? visitNullability(DartType node) {
if (forNonNullableByDefault) {
if (node.declaredNullability == Nullability.legacy) {
return Nullability.nonNullable;
}
} else {
if (node.declaredNullability != Nullability.legacy) {
return Nullability.legacy;
}
if (node.declaredNullability == Nullability.legacy) {
return Nullability.nonNullable;
}
return null;
}
@ -78,10 +56,7 @@ class _DemotionNullabilityNormalization extends ReplacementVisitor {
@override
DartType? visitIntersectionType(IntersectionType node, Variance variance) {
Nullability? newNullability = visitNullability(node);
if (demoteTypeVariables) {
return new TypeParameterType(
node.left.parameter, newNullability ?? node.left.nullability);
}
return createTypeParameterType(node.left, newNullability);
return new TypeParameterType(
node.left.parameter, newNullability ?? node.left.nullability);
}
}

View file

@ -86,104 +86,74 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
List<DartType> choosePreliminaryTypes(
TypeConstraintGatherer gatherer,
List<StructuralParameter> typeParametersToInfer,
List<DartType>? previouslyInferredTypes,
{required bool isNonNullableByDefault}) =>
List<DartType>? previouslyInferredTypes) =>
_chooseTypes(gatherer, typeParametersToInfer, previouslyInferredTypes,
isNonNullableByDefault: isNonNullableByDefault, preliminary: true);
@override
DartType getTypeOfSpecialCasedBinaryOperator(DartType type1, DartType type2,
{bool isNonNullableByDefault = false}) {
if (isNonNullableByDefault) {
return super.getTypeOfSpecialCasedBinaryOperator(type1, type2,
isNonNullableByDefault: isNonNullableByDefault);
} else {
// TODO(paulberry): this matches what is defined in the spec. It would be
// nice if we could change kernel to match the spec and not have to
// override.
if (type1 is InterfaceType && type1.classNode == coreTypes.intClass) {
if (type2 is InterfaceType && type2.classNode == coreTypes.intClass) {
return type2.withDeclaredNullability(type1.nullability);
}
if (type2 is InterfaceType &&
type2.classNode == coreTypes.doubleClass) {
return type2.withDeclaredNullability(type1.nullability);
}
}
return coreTypes.numRawType(type1.nullability);
}
}
preliminary: true);
DartType getContextTypeOfSpecialCasedBinaryOperator(
DartType contextType, DartType type1, DartType type2,
{bool isNonNullableByDefault = false}) {
if (isNonNullableByDefault) {
if (contextType is! NeverType &&
type1 is! NeverType &&
isSubtypeOf(type1, coreTypes.numNonNullableRawType,
DartType contextType, DartType type1, DartType type2) {
if (contextType is! NeverType &&
type1 is! NeverType &&
isSubtypeOf(type1, coreTypes.numNonNullableRawType,
SubtypeCheckMode.withNullabilities)) {
// If e is an expression of the form e1 + e2, e1 - e2, e1 * e2, e1 % e2
// or e1.remainder(e2), where C is the context type of e and T is the
// static type of e1, and where T is a non-Never subtype of num, then:
if (isSubtypeOf(coreTypes.intNonNullableRawType, contextType,
SubtypeCheckMode.withNullabilities) &&
!isSubtypeOf(coreTypes.numNonNullableRawType, contextType,
SubtypeCheckMode.withNullabilities) &&
isSubtypeOf(type1, coreTypes.intNonNullableRawType,
SubtypeCheckMode.withNullabilities)) {
// If e is an expression of the form e1 + e2, e1 - e2, e1 * e2, e1 % e2
// or e1.remainder(e2), where C is the context type of e and T is the
// static type of e1, and where T is a non-Never subtype of num, then:
if (isSubtypeOf(coreTypes.intNonNullableRawType, contextType,
SubtypeCheckMode.withNullabilities) &&
!isSubtypeOf(coreTypes.numNonNullableRawType, contextType,
SubtypeCheckMode.withNullabilities) &&
isSubtypeOf(type1, coreTypes.intNonNullableRawType,
SubtypeCheckMode.withNullabilities)) {
// If int <: C, not num <: C, and T <: int, then the context type of
// e2 is int.
return coreTypes.intNonNullableRawType;
} else if (isSubtypeOf(coreTypes.doubleNonNullableRawType, contextType,
SubtypeCheckMode.withNullabilities) &&
!isSubtypeOf(coreTypes.numNonNullableRawType, contextType,
SubtypeCheckMode.withNullabilities) &&
!isSubtypeOf(type1, coreTypes.doubleNonNullableRawType,
SubtypeCheckMode.withNullabilities)) {
// If double <: C, not num <: C, and not T <: double, then the context
// type of e2 is double.
return coreTypes.doubleNonNullableRawType;
} else {
// Otherwise, the context type of e2 is num.
return coreTypes.numNonNullableRawType;
}
// If int <: C, not num <: C, and T <: int, then the context type of
// e2 is int.
return coreTypes.intNonNullableRawType;
} else if (isSubtypeOf(coreTypes.doubleNonNullableRawType, contextType,
SubtypeCheckMode.withNullabilities) &&
!isSubtypeOf(coreTypes.numNonNullableRawType, contextType,
SubtypeCheckMode.withNullabilities) &&
!isSubtypeOf(type1, coreTypes.doubleNonNullableRawType,
SubtypeCheckMode.withNullabilities)) {
// If double <: C, not num <: C, and not T <: double, then the context
// type of e2 is double.
return coreTypes.doubleNonNullableRawType;
} else {
// Otherwise, the context type of e2 is num.
return coreTypes.numNonNullableRawType;
}
}
return type2;
}
DartType getContextTypeOfSpecialCasedTernaryOperator(
DartType contextType, DartType receiverType, DartType operandType,
{bool isNonNullableByDefault = false}) {
if (isNonNullableByDefault) {
if (receiverType is! NeverType &&
isSubtypeOf(receiverType, coreTypes.numNonNullableRawType,
DartType contextType, DartType receiverType, DartType operandType) {
if (receiverType is! NeverType &&
isSubtypeOf(receiverType, coreTypes.numNonNullableRawType,
SubtypeCheckMode.withNullabilities)) {
// If e is an expression of the form e1.clamp(e2, e3) where C is the
// context type of e and T is the static type of e1 where T is a
// non-Never subtype of num, then:
if (isSubtypeOf(coreTypes.intNonNullableRawType, contextType,
SubtypeCheckMode.withNullabilities) &&
!isSubtypeOf(coreTypes.numNonNullableRawType, contextType,
SubtypeCheckMode.withNullabilities) &&
isSubtypeOf(receiverType, coreTypes.intNonNullableRawType,
SubtypeCheckMode.withNullabilities)) {
// If e is an expression of the form e1.clamp(e2, e3) where C is the
// context type of e and T is the static type of e1 where T is a
// non-Never subtype of num, then:
if (isSubtypeOf(coreTypes.intNonNullableRawType, contextType,
SubtypeCheckMode.withNullabilities) &&
!isSubtypeOf(coreTypes.numNonNullableRawType, contextType,
SubtypeCheckMode.withNullabilities) &&
isSubtypeOf(receiverType, coreTypes.intNonNullableRawType,
SubtypeCheckMode.withNullabilities)) {
// If int <: C, not num <: C, and T <: int, then the context type of
// e2 and e3 is int.
return coreTypes.intNonNullableRawType;
} else if (isSubtypeOf(coreTypes.doubleNonNullableRawType, contextType,
SubtypeCheckMode.withNullabilities) &&
!isSubtypeOf(coreTypes.numNonNullableRawType, contextType,
SubtypeCheckMode.withNullabilities) &&
isSubtypeOf(receiverType, coreTypes.doubleNonNullableRawType,
SubtypeCheckMode.withNullabilities)) {
// If double <: C, not num <: C, and T <: double, then the context
// type of e2 and e3 is double.
return coreTypes.doubleNonNullableRawType;
} else {
// Otherwise the context type of e2 an e3 is num
return coreTypes.numNonNullableRawType;
}
// If int <: C, not num <: C, and T <: int, then the context type of
// e2 and e3 is int.
return coreTypes.intNonNullableRawType;
} else if (isSubtypeOf(coreTypes.doubleNonNullableRawType, contextType,
SubtypeCheckMode.withNullabilities) &&
!isSubtypeOf(coreTypes.numNonNullableRawType, contextType,
SubtypeCheckMode.withNullabilities) &&
isSubtypeOf(receiverType, coreTypes.doubleNonNullableRawType,
SubtypeCheckMode.withNullabilities)) {
// If double <: C, not num <: C, and T <: double, then the context
// type of e2 and e3 is double.
return coreTypes.doubleNonNullableRawType;
} else {
// Otherwise the context type of e2 an e3 is num
return coreTypes.numNonNullableRawType;
}
}
return operandType;
@ -221,8 +191,7 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
Map<StructuralParameter, MergedTypeConstraint> constraints,
List<StructuralParameter> typeParametersToInfer,
List<DartType>? previouslyInferredTypes,
{required bool isNonNullableByDefault,
bool preliminary = false,
{bool preliminary = false,
required OperationsCfe operations}) {
List<DartType> inferredTypes =
previouslyInferredTypes?.toList(growable: false) ??
@ -243,13 +212,11 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
if (preliminary) {
inferredTypes[i] = _inferTypeParameterFromContext(
previouslyInferredTypes?[i], constraint, extendsConstraint,
isNonNullableByDefault: isNonNullableByDefault,
isLegacyCovariant: typeParam.isLegacyCovariant,
operations: operations);
} else {
inferredTypes[i] = _inferTypeParameterFromAll(
previouslyInferredTypes?[i], constraint, extendsConstraint,
isNonNullableByDefault: isNonNullableByDefault,
isContravariant:
typeParam.variance == shared.Variance.contravariant,
isLegacyCovariant: typeParam.isLegacyCovariant,
@ -285,7 +252,7 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
}
List<DartType> instantiatedTypes = calculateBounds(
helperTypeParameters, coreTypes.objectClass,
isNonNullableByDefault: isNonNullableByDefault);
isNonNullableByDefault: true);
for (int i = 0; i < instantiatedTypes.length; ++i) {
if (inferredTypes[i] is UnknownType) {
inferredTypes[i] = instantiatedTypes[i];
@ -331,20 +298,8 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
/// This is a case of type-based overloading, which in Dart is only supported
/// by giving special treatment to certain arithmetic operators.
bool isSpecialCasesBinaryForReceiverType(
Procedure member, DartType receiverType,
{required bool isNonNullableByDefault}) {
if (!isNonNullableByDefault) {
// TODO(paulberry): this matches what is defined in the spec. It would be
// nice if we could change kernel to match the spec and not have to
// override.
if (member.name.text == 'remainder') return false;
if (!(receiverType is InterfaceType &&
identical(receiverType.classNode, coreTypes.intClass))) {
return false;
}
}
return isSpecialCasedBinaryOperator(member,
isNonNullableByDefault: isNonNullableByDefault);
Procedure member, DartType receiverType) {
return isSpecialCasedBinaryOperator(member);
}
@override
@ -363,8 +318,7 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
DartType? declaredReturnType,
List<StructuralParameter> typeParametersToInfer,
DartType? returnContextType,
{required bool isNonNullableByDefault,
bool isConst = false,
{bool isConst = false,
required OperationsCfe typeOperations,
required TypeInferenceResultForTesting? inferenceResultForTesting,
required TreeNode? treeNodeForTesting}) {
@ -376,23 +330,16 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
// are implied by this.
TypeConstraintGatherer gatherer = new TypeConstraintGatherer(
this, typeParametersToInfer,
isNonNullableByDefault: isNonNullableByDefault,
typeOperations: typeOperations,
inferenceResultForTesting: inferenceResultForTesting);
if (!isEmptyContext(returnContextType)) {
if (isConst) {
if (isNonNullableByDefault) {
returnContextType = new NullabilityAwareFreeTypeVariableEliminator(
bottomType: const NeverType.nonNullable(),
topType: objectNullableRawType,
topFunctionType: functionRawType(Nullability.nonNullable))
.eliminateToLeast(returnContextType!);
} else {
returnContextType =
new TypeVariableEliminator(const NullType(), objectLegacyRawType)
.substituteType(returnContextType!);
}
returnContextType = new NullabilityAwareFreeTypeVariableEliminator(
bottomType: const NeverType.nonNullable(),
topType: objectNullableRawType,
topFunctionType: functionRawType(Nullability.nonNullable))
.eliminateToLeast(returnContextType!);
}
gatherer.tryConstrainUpper(declaredReturnType!, returnContextType!,
treeNodeForTesting: treeNodeForTesting);
@ -467,10 +414,9 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
List<DartType> chooseFinalTypes(
TypeConstraintGatherer gatherer,
List<StructuralParameter> typeParametersToInfer,
List<DartType>? previouslyInferredTypes,
{required bool isNonNullableByDefault}) =>
List<DartType>? previouslyInferredTypes) =>
_chooseTypes(gatherer, typeParametersToInfer, previouslyInferredTypes,
isNonNullableByDefault: isNonNullableByDefault, preliminary: false);
preliminary: false);
/// Computes (or recomputes) a set of [inferredTypes] based on the constraints
/// that have been recorded so far.
@ -478,28 +424,23 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
TypeConstraintGatherer gatherer,
List<StructuralParameter> typeParametersToInfer,
List<DartType>? previouslyInferredTypes,
{required bool isNonNullableByDefault,
required bool preliminary}) {
{required bool preliminary}) {
List<DartType> inferredTypes = inferTypeFromConstraints(
gatherer.computeConstraints(
isNonNullableByDefault: isNonNullableByDefault),
gatherer.computeConstraints(),
typeParametersToInfer,
previouslyInferredTypes,
isNonNullableByDefault: isNonNullableByDefault,
preliminary: preliminary,
operations: gatherer.typeOperations);
for (int i = 0; i < inferredTypes.length; i++) {
inferredTypes[i] = demoteTypeInLibrary(inferredTypes[i],
isNonNullableByDefault: isNonNullableByDefault);
inferredTypes[i] = demoteTypeInLibrary(inferredTypes[i]);
}
return inferredTypes;
}
DartType _inferTypeParameterFromAll(DartType? typeFromPreviousInference,
MergedTypeConstraint constraint, DartType? extendsConstraint,
{required bool isNonNullableByDefault,
bool isContravariant = false,
{bool isContravariant = false,
bool isLegacyCovariant = true,
required OperationsCfe operations}) {
// See if we already fixed this type in a previous inference step.
@ -516,23 +457,14 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
constraint.mergeInTypeSchemaUpper(extendsConstraint, operations);
}
return solveTypeConstraint(
constraint,
isNonNullableByDefault
? coreTypes.objectNullableRawType
: const DynamicType(),
isNonNullableByDefault
? const NeverType.nonNullable()
: const NullType(),
grounded: true,
isContravariant: isContravariant);
return solveTypeConstraint(constraint, coreTypes.objectNullableRawType,
const NeverType.nonNullable(),
grounded: true, isContravariant: isContravariant);
}
DartType _inferTypeParameterFromContext(DartType? typeFromPreviousInference,
MergedTypeConstraint constraint, DartType? extendsConstraint,
{required bool isNonNullableByDefault,
bool isLegacyCovariant = true,
required OperationsCfe operations}) {
{bool isLegacyCovariant = true, required OperationsCfe operations}) {
// See if we already fixed this type in a previous inference step.
// If so, then we aren't allowed to change it unless [isLegacyCovariant] is
// false.
@ -542,14 +474,8 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
return typeFromPreviousInference;
}
DartType t = solveTypeConstraint(
constraint,
isNonNullableByDefault
? coreTypes.objectNullableRawType
: const DynamicType(),
isNonNullableByDefault
? const NeverType.nonNullable()
: const NullType());
DartType t = solveTypeConstraint(constraint,
coreTypes.objectNullableRawType, const NeverType.nonNullable());
if (!isKnown(t)) {
return t;
}
@ -564,14 +490,8 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
if (extendsConstraint != null) {
constraint = constraint.clone();
constraint.mergeInTypeSchemaUpper(extendsConstraint, operations);
return solveTypeConstraint(
constraint,
isNonNullableByDefault
? coreTypes.objectNullableRawType
: const DynamicType(),
isNonNullableByDefault
? const NeverType.nonNullable()
: const NullType());
return solveTypeConstraint(constraint, coreTypes.objectNullableRawType,
const NeverType.nonNullable());
}
return t;
}

View file

@ -396,7 +396,6 @@ class TypeConstraintGathererTest {
coreTypes, new ClassHierarchy(component, coreTypes));
var typeConstraintGatherer = new TypeConstraintGatherer(
typeSchemaEnvironment, typeParameterNodesToConstrain,
isNonNullableByDefault: true,
typeOperations: new OperationsCfe(typeSchemaEnvironment,
fieldNonPromotabilityInfo: new FieldNonPromotabilityInfo(
fieldNameInfo: {}, individualPropertyReasons: {}),
@ -405,8 +404,7 @@ class TypeConstraintGathererTest {
typeCacheLegacy: {}),
inferenceResultForTesting: null);
var constraints = tryConstrain(typeConstraintGatherer, a, b)
? typeConstraintGatherer.computeConstraints(
isNonNullableByDefault: true)
? typeConstraintGatherer.computeConstraints()
: null;
if (expectedConstraints == null) {
expect(constraints, isNull);

View file

@ -304,7 +304,6 @@ class TypeConstraintGathererTest {
coreTypes, new ClassHierarchy(component, coreTypes));
var typeConstraintGatherer = new TypeConstraintGatherer(
typeSchemaEnvironment, typeParameterNodesToConstrain,
isNonNullableByDefault: true,
typeOperations: new OperationsCfe(typeSchemaEnvironment,
fieldNonPromotabilityInfo: new FieldNonPromotabilityInfo(
fieldNameInfo: {}, individualPropertyReasons: {}),
@ -313,8 +312,7 @@ class TypeConstraintGathererTest {
typeCacheLegacy: {}),
inferenceResultForTesting: null);
var constraints = tryConstrain(typeConstraintGatherer, a, b)
? typeConstraintGatherer.computeConstraints(
isNonNullableByDefault: true)
? typeConstraintGatherer.computeConstraints()
: null;
if (expectedConstraints == null) {
expect(constraints, isNull);

View file

@ -174,7 +174,6 @@ abstract class TypeSchemaEnvironmentTestBase {
declaredReturnTypeNode,
typeParameterNodesToInfer,
returnContextTypeNode,
isNonNullableByDefault: true,
typeOperations: new OperationsCfe(typeSchemaEnvironment,
fieldNonPromotabilityInfo: new FieldNonPromotabilityInfo(
fieldNameInfo: {}, individualPropertyReasons: {}),
@ -185,14 +184,12 @@ abstract class TypeSchemaEnvironmentTestBase {
treeNodeForTesting: null);
if (formalTypeNodes == null) {
inferredTypeNodes = typeSchemaEnvironment.choosePreliminaryTypes(
gatherer, typeParameterNodesToInfer, inferredTypeNodes,
isNonNullableByDefault: true);
gatherer, typeParameterNodesToInfer, inferredTypeNodes);
} else {
gatherer.constrainArguments(formalTypeNodes, actualTypeNodes!,
treeNodeForTesting: null);
inferredTypeNodes = typeSchemaEnvironment.chooseFinalTypes(
gatherer, typeParameterNodesToInfer, inferredTypeNodes!,
isNonNullableByDefault: true);
gatherer, typeParameterNodesToInfer, inferredTypeNodes!);
}
assert(
@ -228,7 +225,6 @@ abstract class TypeSchemaEnvironmentTestBase {
{typeParameterNode: typeConstraint},
[typeParameterNode],
inferredTypeNodes,
isNonNullableByDefault: true,
preliminary: downwardsInferPhase,
operations: _operations);

View file

@ -0,0 +1,69 @@
library;
//
// Problems in library:
//
// pkg/front_end/testcases/general/invocations.dart:7:3: Error: Method not found: 'z'.
// z("Hello, World!");
// ^
//
// pkg/front_end/testcases/general/invocations.dart:8:3: Error: Undefined name 'z'.
// z.print("Hello, World!");
// ^
//
// pkg/front_end/testcases/general/invocations.dart:9:3: Error: Undefined name 'y'.
// y.z.print("Hello, World!");
// ^
//
// pkg/front_end/testcases/general/invocations.dart:10:3: Error: Undefined name 'x'.
// x.y.z.print("Hello, World!");
// ^
//
// pkg/front_end/testcases/general/invocations.dart:14:7: Error: Method not found: 'z'.
// z("Hello, World!") +
// ^
//
// pkg/front_end/testcases/general/invocations.dart:15:7: Error: Undefined name 'z'.
// z.print("Hello, World!") +
// ^
//
// pkg/front_end/testcases/general/invocations.dart:16:7: Error: Undefined name 'y'.
// y.z.print("Hello, World!") +
// ^
//
// pkg/front_end/testcases/general/invocations.dart:17:7: Error: Undefined name 'x'.
// x.y.z.print("Hello, World!");
// ^
//
// pkg/front_end/testcases/general/invocations.dart:13:7: Error: This expression has type 'void' and can't be used.
// print("Hello, World!") +
// ^
//
import self as self;
import "dart:core" as core;
static method main() → dynamic {
core::print("Hello, World!");
invalid-expression "pkg/front_end/testcases/general/invocations.dart:7:3: Error: Method not found: 'z'.
z(\"Hello, World!\");
^";
invalid-expression "pkg/front_end/testcases/general/invocations.dart:8:3: Error: Undefined name 'z'.
z.print(\"Hello, World!\");
^"{dynamic}.print("Hello, World!");
invalid-expression "pkg/front_end/testcases/general/invocations.dart:9:3: Error: Undefined name 'y'.
y.z.print(\"Hello, World!\");
^"{<invalid>}.z{dynamic}.print("Hello, World!");
invalid-expression "pkg/front_end/testcases/general/invocations.dart:10:3: Error: Undefined name 'x'.
x.y.z.print(\"Hello, World!\");
^"{<invalid>}.y{<invalid>}.z{dynamic}.print("Hello, World!");
1.{core::num::+}(invalid-expression "pkg/front_end/testcases/general/invocations.dart:13:7: Error: This expression has type 'void' and can't be used.
print(\"Hello, World!\") +
^" in core::print("Hello, World!")){(core::num) → core::num}.{core::num::+}(invalid-expression "pkg/front_end/testcases/general/invocations.dart:14:7: Error: Method not found: 'z'.
z(\"Hello, World!\") +
^"){(core::num) → core::double}.{core::double::+}(invalid-expression "pkg/front_end/testcases/general/invocations.dart:15:7: Error: Undefined name 'z'.
z.print(\"Hello, World!\") +
^"{dynamic}.print("Hello, World!") as{TypeError,ForDynamic} core::num){(core::num) → core::double}.{core::double::+}(invalid-expression "pkg/front_end/testcases/general/invocations.dart:16:7: Error: Undefined name 'y'.
y.z.print(\"Hello, World!\") +
^"{<invalid>}.z{dynamic}.print("Hello, World!") as{TypeError,ForDynamic} core::num){(core::num) → core::double}.{core::double::+}(invalid-expression "pkg/front_end/testcases/general/invocations.dart:17:7: Error: Undefined name 'x'.
x.y.z.print(\"Hello, World!\");
^"{<invalid>}.y{<invalid>}.z{dynamic}.print("Hello, World!") as{TypeError,ForDynamic} core::num){(core::num) → core::double};
}

View file

@ -41,7 +41,6 @@ general/infer_field_from_multiple2: TypeCheckError
general/infer_field_from_multiple: TypeCheckError
general/invalid_operator: TypeCheckError
general/invalid_operator_override: TypeCheckError
general/invocations: TypeCheckError
general/issue41210a: TypeCheckError
general/issue41210b/issue41210.no_link: TypeCheckError
general/issue41210b/issue41210: TypeCheckError
@ -66,7 +65,9 @@ inference/mixin_inference_outwards_4: TypeCheckError
inference/mixin_inference_unification_1: TypeCheckError
inference/mixin_inference_unification_2: TypeCheckError
late_lowering/covariant_late_field: TypeCheckError
late_lowering/definitely_unassigned: TypeCheckError
nnbd/covariant_late_field: TypeCheckError
nnbd/definitely_unassigned: TypeCheckError
nnbd/getter_vs_setter_type: TypeCheckError
nnbd/issue42603: TypeCheckError
no_such_method_forwarders/mixin_nsm: TypeCheckError

View file

@ -211,7 +211,7 @@ general/infer_field_from_multiple2: TypeCheckError
general/infer_field_from_multiple: TypeCheckError
general/invalid_operator: TypeCheckError
general/invalid_operator_override: TypeCheckError
general/invocations: TypeCheckError
general/invocations: RuntimeError
general/issue37776: RuntimeError
general/issue41210a: TypeCheckError
general/issue41210b/issue41210.no_link: TypeCheckError
@ -252,7 +252,9 @@ inference/mixin_inference_outwards_4: TypeCheckError
inference/mixin_inference_unification_1: TypeCheckError
inference/mixin_inference_unification_2: TypeCheckError
late_lowering/covariant_late_field: TypeCheckError
late_lowering/definitely_unassigned: TypeCheckError
nnbd/covariant_late_field: TypeCheckError
nnbd/definitely_unassigned: TypeCheckError
nnbd/getter_vs_setter_type: TypeCheckError
nnbd/issue42603: TypeCheckError
nnbd/no_support_for_old_null_aware_index_access_syntax: RuntimeError # Expected.

View file

@ -160,16 +160,12 @@ abstract class TypeEnvironment extends Types {
/// getUnionFreeType(int?) = int
/// getUnionFreeType(FutureOr<int>) = int
/// getUnionFreeType(FutureOr<int?>?) = int
DartType getUnionFreeType(DartType type,
{required bool isNonNullableByDefault}) {
DartType getUnionFreeType(DartType type) {
if (isNullableTypeConstructorApplication(type)) {
return getUnionFreeType(
computeTypeWithoutNullabilityMarker(type,
isNonNullableByDefault: isNonNullableByDefault),
isNonNullableByDefault: isNonNullableByDefault);
return getUnionFreeType(computeTypeWithoutNullabilityMarker(type,
isNonNullableByDefault: true));
} else if (type is FutureOrType) {
return getUnionFreeType(type.typeArgument,
isNonNullableByDefault: isNonNullableByDefault);
return getUnionFreeType(type.typeArgument);
} else {
return type;
}
@ -177,46 +173,30 @@ abstract class TypeEnvironment extends Types {
/// True if [member] is a binary operator whose return type is defined by
/// the both operand types.
bool isSpecialCasedBinaryOperator(Procedure member,
{bool isNonNullableByDefault = false}) {
if (isNonNullableByDefault) {
Class? class_ = member.enclosingClass;
// TODO(johnniwinther): Do we need to recognize backend implementation
// methods?
if (class_ == coreTypes.intClass ||
class_ == coreTypes.numClass ||
class_ == coreTypes.doubleClass) {
String name = member.name.text;
return name == '+' ||
name == '-' ||
name == '*' ||
name == 'remainder' ||
name == '%';
}
} else {
Class? class_ = member.enclosingClass;
if (class_ == coreTypes.intClass || class_ == coreTypes.numClass) {
String name = member.name.text;
return name == '+' ||
name == '-' ||
name == '*' ||
name == 'remainder' ||
name == '%';
}
bool isSpecialCasedBinaryOperator(Procedure member) {
Class? class_ = member.enclosingClass;
// TODO(johnniwinther): Do we need to recognize backend implementation
// methods?
if (class_ == coreTypes.intClass ||
class_ == coreTypes.numClass ||
class_ == coreTypes.doubleClass) {
String name = member.name.text;
return name == '+' ||
name == '-' ||
name == '*' ||
name == 'remainder' ||
name == '%';
}
return false;
}
/// True if [member] is a ternary operator whose return type is defined by
/// the least upper bound of the operand types.
bool isSpecialCasedTernaryOperator(Procedure member,
{bool isNonNullableByDefault = false}) {
if (isNonNullableByDefault) {
Class? class_ = member.enclosingClass;
if (class_ == coreTypes.intClass || class_ == coreTypes.numClass) {
String name = member.name.text;
return name == 'clamp';
}
bool isSpecialCasedTernaryOperator(Procedure member) {
Class? class_ = member.enclosingClass;
if (class_ == coreTypes.intClass || class_ == coreTypes.numClass) {
String name = member.name.text;
return name == 'clamp';
}
return false;
}
@ -224,64 +204,44 @@ abstract class TypeEnvironment extends Types {
/// Returns the static return type of a special cased binary operator
/// (see [isSpecialCasedBinaryOperator]) given the static type of the
/// operands.
DartType getTypeOfSpecialCasedBinaryOperator(DartType type1, DartType type2,
{bool isNonNullableByDefault = false}) {
if (isNonNullableByDefault) {
// Let e be an expression of one of the forms e1 + e2, e1 - e2, e1 * e2,
// e1 % e2 or e1.remainder(e2), where the static type of e1 is a non-Never
// type T and T <: num, and where the static type of e2 is S and S is
// assignable to num. Then:
if (type1 is! NeverType &&
isSubtypeOf(type1, coreTypes.numNonNullableRawType,
SubtypeCheckMode.withNullabilities) &&
type2 is DynamicType ||
isSubtypeOf(type2, coreTypes.numNonNullableRawType,
SubtypeCheckMode.withNullabilities)) {
if (isSubtypeOf(type1, coreTypes.doubleNonNullableRawType,
SubtypeCheckMode.withNullabilities)) {
// If T <: double then the static type of e is double. This includes S
// being dynamic or Never.
return coreTypes.doubleNonNullableRawType;
} else if (type2 is! NeverType &&
isSubtypeOf(type2, coreTypes.doubleNonNullableRawType,
SubtypeCheckMode.withNullabilities)) {
// If S <: double and not S <:Never, then the static type of e is
// double.
return coreTypes.doubleNonNullableRawType;
} else if (isSubtypeOf(type1, coreTypes.intNonNullableRawType,
DartType getTypeOfSpecialCasedBinaryOperator(DartType type1, DartType type2) {
// Let e be an expression of one of the forms e1 + e2, e1 - e2, e1 * e2,
// e1 % e2 or e1.remainder(e2), where the static type of e1 is a non-Never
// type T and T <: num, and where the static type of e2 is S and S is
// assignable to num. Then:
if (type1 is! NeverType &&
isSubtypeOf(type1, coreTypes.numNonNullableRawType,
SubtypeCheckMode.withNullabilities) &&
type2 is! NeverType &&
isSubtypeOf(type2, coreTypes.intNonNullableRawType,
SubtypeCheckMode.withNullabilities)) {
// If T <: int , S <: int and not S <: Never, then the static type of
// e is int.
return coreTypes.intNonNullableRawType;
} else if (type2 is! NeverType &&
isSubtypeOf(type2, type1, SubtypeCheckMode.withNullabilities)) {
// Otherwise the static type of e is num.
return coreTypes.numNonNullableRawType;
}
type2 is DynamicType ||
isSubtypeOf(type2, coreTypes.numNonNullableRawType,
SubtypeCheckMode.withNullabilities)) {
if (isSubtypeOf(type1, coreTypes.doubleNonNullableRawType,
SubtypeCheckMode.withNullabilities)) {
// If T <: double then the static type of e is double. This includes S
// being dynamic or Never.
return coreTypes.doubleNonNullableRawType;
} else if (type2 is! NeverType &&
isSubtypeOf(type2, coreTypes.doubleNonNullableRawType,
SubtypeCheckMode.withNullabilities)) {
// If S <: double and not S <:Never, then the static type of e is
// double.
return coreTypes.doubleNonNullableRawType;
} else if (isSubtypeOf(type1, coreTypes.intNonNullableRawType,
SubtypeCheckMode.withNullabilities) &&
type2 is! NeverType &&
isSubtypeOf(type2, coreTypes.intNonNullableRawType,
SubtypeCheckMode.withNullabilities)) {
// If T <: int , S <: int and not S <: Never, then the static type of
// e is int.
return coreTypes.intNonNullableRawType;
} else if (type2 is! NeverType &&
isSubtypeOf(type2, type1, SubtypeCheckMode.withNullabilities)) {
// Otherwise the static type of e is num.
return coreTypes.numNonNullableRawType;
}
// Otherwise the static type of e is num.
return coreTypes.numNonNullableRawType;
} else {
type1 = type1.nonTypeVariableBound;
type2 = type2.nonTypeVariableBound;
if (type1 == type2) return type1;
if (type1 is InterfaceType && type2 is InterfaceType) {
if (type1.classNode == type2.classNode) {
return type1;
}
if (type1.classNode == coreTypes.doubleClass ||
type2.classNode == coreTypes.doubleClass) {
return coreTypes.doubleRawType(type1.nullability);
}
}
return coreTypes.numRawType(type1.nullability);
}
// Otherwise the static type of e is num.
return coreTypes.numNonNullableRawType;
}
DartType getTypeOfSpecialCasedTernaryOperator(