blob: 639a704e479b66545e506a040c4d0ede7e2ddfe9 [file] [log] [blame]
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:_fe_analyzer_shared/src/exhaustiveness/intersect.dart';
import 'package:_fe_analyzer_shared/src/exhaustiveness/space.dart';
import 'package:_fe_analyzer_shared/src/exhaustiveness/static_type.dart';
import 'package:test/test.dart';
import 'env.dart';
import 'utils.dart';
void main() {
// (A)
// / \
// B C
var env = TestEnvironment();
var a = env.createClass('A', isSealed: true);
var b = env.createClass('B', inherits: [a]);
var c = env.createClass('C', inherits: [a]);
var x = 'x';
var y = 'y';
var z = 'z';
var w = 'w';
Space A({StaticType? x, StaticType? y, StaticType? z}) => ty(
a, {if (x != null) 'x': x, if (y != null) 'y': y, if (z != null) 'z': z});
Space B({StaticType? x, StaticType? y, StaticType? z}) => ty(
b, {if (x != null) 'x': x, if (y != null) 'y': y, if (z != null) 'z': z});
Space C({StaticType? x, StaticType? y, StaticType? z}) => ty(
c, {if (x != null) 'x': x, if (y != null) 'y': y, if (z != null) 'z': z});
test('records', () {
var r = env.createRecordType({x: a, y: a, z: a, w: a});
expectIntersect(
ty(r, {x: a, y: a}), ty(r, {x: a, y: a}), ty(r, {x: a, y: a}));
expectIntersect(ty(r, {x: a, y: a}), ty(r, {x: a}), ty(r, {x: a, y: a}));
expectIntersect(ty(r, {w: a, x: a}), ty(r, {y: a, z: a}),
ty(r, {w: a, x: a, y: a, z: a}));
expectIntersect(ty(r, {w: a, x: a, y: a}), ty(r, {x: a, y: a, z: a}),
ty(r, {w: a, x: a, y: a, z: a}));
});
test('types', () {
// Note: More comprehensive tests under intersect_types_test.dart.
expectIntersect(a, a, a);
expectIntersect(a, b, b);
expectIntersect(a, c, c);
expectIntersect(b, c, '∅');
expectIntersect(
StaticType.nullableObject, StaticType.nullType, StaticType.nullType);
expectIntersect(StaticType.nonNullableObject, StaticType.nullType, '∅');
expectIntersect(StaticType.neverType, StaticType.nullType, '∅');
expectIntersect(StaticType.nonNullableObject, StaticType.nullableObject,
StaticType.nonNullableObject);
});
test('field types', () {
var r = env.createRecordType({x: a, y: a});
expectIntersect(
ty(r, {x: a, y: b}), ty(r, {x: b, y: a}), ty(r, {x: b, y: b}));
expectIntersect(ty(r, {x: b}), ty(r, {x: c}), '∅');
});
test('types and fields', () {
expectIntersect(A(x: a), A(x: a), A(x: a));
expectIntersect(A(x: a), A(x: b), A(x: b));
expectIntersect(A(x: b), A(x: c), '∅');
expectIntersect(A(x: a), B(x: a), B(x: a));
expectIntersect(A(x: a), B(x: b), B(x: b));
expectIntersect(A(x: b), B(x: c), '∅');
expectIntersect(B(x: a), A(x: a), B(x: a));
expectIntersect(B(x: a), A(x: b), B(x: b));
expectIntersect(B(x: b), A(x: c), '∅');
expectIntersect(B(x: a), B(x: a), B(x: a));
expectIntersect(B(x: a), B(x: b), B(x: b));
expectIntersect(B(x: b), B(x: c), '∅');
expectIntersect(B(x: a), C(x: a), '∅');
expectIntersect(B(x: a), C(x: b), '∅');
expectIntersect(B(x: b), C(x: c), '∅');
});
}
void expectIntersect(Object left, Object right, Object expected) {
var leftSpace = parseSpace(left);
var rightSpace = parseSpace(right);
var expectedText = parseSpace(expected).toString();
// Intersection is symmetric so try both directions.
expect(intersect(leftSpace, rightSpace).toString(), expectedText);
expect(intersect(rightSpace, leftSpace).toString(), expectedText);
}