blob: 0b0adb793de154d0016ca9d6699128511fc633ae [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/static_type.dart';
import 'package:_fe_analyzer_shared/src/exhaustiveness/subtract.dart';
import 'package:test/test.dart';
void main() {
test('sealed', () {
// (A)
// /|\
// B C(D)
// / \
// E F
var a = StaticType('A', isSealed: true);
var b = StaticType('B', inherits: [a]);
var c = StaticType('C', inherits: [a]);
var d = StaticType('D', isSealed: true, inherits: [a]);
var e = StaticType('E', inherits: [d]);
var f = StaticType('F', inherits: [d]);
expectExpand(a, a, 'A');
expectExpand(a, b, 'B|C|D');
expectExpand(a, c, 'B|C|D');
expectExpand(a, d, 'B|C|D');
expectExpand(a, e, 'B|C|E|F');
expectExpand(a, f, 'B|C|E|F');
expectExpand(d, a, 'D');
expectExpand(d, b, 'D');
expectExpand(d, c, 'D');
expectExpand(d, d, 'D');
expectExpand(d, e, 'E|F');
expectExpand(d, f, 'E|F');
});
test('unsealed', () {
// A
// /|\
// B C D
// / \
// E F
var a = StaticType('A');
var b = StaticType('B', inherits: [a]);
var c = StaticType('C', inherits: [a]);
var d = StaticType('D', inherits: [a]);
var e = StaticType('E', inherits: [d]);
var f = StaticType('F', inherits: [d]);
expectExpand(a, a, 'A');
expectExpand(a, b, 'A');
expectExpand(a, c, 'A');
expectExpand(a, d, 'A');
expectExpand(a, e, 'A');
expectExpand(a, f, 'A');
expectExpand(d, a, 'D');
expectExpand(d, b, 'D');
expectExpand(d, c, 'D');
expectExpand(d, d, 'D');
expectExpand(d, e, 'D');
expectExpand(d, f, 'D');
});
test('unsealed in middle', () {
// (A)
// / \
// B C
// / \
// D (E)
// / \
// F G
var a = StaticType('A', isSealed: true);
var b = StaticType('B', inherits: [a]);
var c = StaticType('C', inherits: [a]);
var d = StaticType('D', inherits: [c]);
var e = StaticType('E', isSealed: true, inherits: [c]);
var f = StaticType('F', inherits: [e]);
var g = StaticType('G', inherits: [e]);
expectExpand(a, a, 'A');
expectExpand(a, b, 'B|C');
expectExpand(a, c, 'B|C');
expectExpand(a, d, 'B|C');
expectExpand(a, e, 'B|C');
expectExpand(a, f, 'B|C');
expectExpand(c, a, 'C');
expectExpand(c, b, 'C');
expectExpand(c, c, 'C');
expectExpand(c, d, 'C');
expectExpand(c, e, 'C');
expectExpand(c, f, 'C');
expectExpand(e, a, 'E');
expectExpand(e, b, 'E');
expectExpand(e, c, 'E');
expectExpand(e, e, 'E');
expectExpand(e, f, 'F|G');
expectExpand(e, g, 'F|G');
});
test('transitive sealed family', () {
// (A)
// / \
// (B) (C)
// / | | \
// D E F G
// \ /
// H
var a = StaticType('A', isSealed: true);
var b = StaticType('B', isSealed: true, inherits: [a]);
var c = StaticType('C', isSealed: true, inherits: [a]);
var d = StaticType('D', inherits: [b]);
var e = StaticType('E', inherits: [b]);
var f = StaticType('F', inherits: [c]);
var g = StaticType('G', inherits: [c]);
var h = StaticType('H', inherits: [e, f]);
expectExpand(a, a, 'A');
expectExpand(a, b, 'B|C');
expectExpand(a, c, 'B|C');
expectExpand(a, d, 'D|E|C');
expectExpand(a, e, 'D|E|C');
expectExpand(a, f, 'B|F|G');
expectExpand(a, g, 'B|F|G');
expectExpand(a, h, 'D|E|F|G');
expectExpand(b, a, 'B');
expectExpand(b, b, 'B');
expectExpand(b, c, 'B');
expectExpand(b, d, 'D|E');
expectExpand(b, e, 'D|E');
expectExpand(b, f, 'B');
expectExpand(b, h, 'D|E');
expectExpand(d, a, 'D');
expectExpand(d, b, 'D');
expectExpand(d, c, 'D');
expectExpand(d, d, 'D');
expectExpand(d, e, 'D');
expectExpand(d, f, 'D');
expectExpand(e, a, 'E');
expectExpand(e, b, 'E');
expectExpand(e, c, 'E');
expectExpand(e, d, 'E');
expectExpand(e, e, 'E');
expectExpand(e, f, 'E');
expectExpand(e, h, 'E');
expectExpand(h, a, 'H');
expectExpand(h, b, 'H');
expectExpand(h, d, 'H');
expectExpand(h, e, 'H');
expectExpand(h, h, 'H');
});
test('sealed with multiple paths', () {
// (A)
// / \
// (B) C
// / \ /
// D E
var a = StaticType('A', isSealed: true);
var b = StaticType('B', isSealed: true, inherits: [a]);
var c = StaticType('C', inherits: [a]);
var d = StaticType('D', inherits: [b]);
var e = StaticType('E', inherits: [b, c]);
expectExpand(a, a, 'A');
expectExpand(a, b, 'B|C');
expectExpand(a, c, 'B|C');
expectExpand(a, d, 'D|E|C');
expectExpand(a, e, 'D|E|C');
expectExpand(b, a, 'B');
expectExpand(b, b, 'B');
expectExpand(b, c, 'B');
expectExpand(b, d, 'D|E');
expectExpand(b, e, 'D|E');
expectExpand(c, a, 'C');
expectExpand(c, b, 'C');
expectExpand(c, c, 'C');
expectExpand(c, d, 'C');
expectExpand(c, e, 'C');
expectExpand(d, a, 'D');
expectExpand(d, b, 'D');
expectExpand(d, c, 'D');
expectExpand(d, d, 'D');
expectExpand(d, e, 'D');
expectExpand(e, a, 'E');
expectExpand(e, b, 'E');
expectExpand(e, c, 'E');
expectExpand(e, d, 'E');
expectExpand(e, e, 'E');
});
test('nullable', () {
// (A)
// / \
// B C
// / \
// D E
var a = StaticType('A', isSealed: true);
var b = StaticType('B', inherits: [a]);
var c = StaticType('C', inherits: [a]);
var d = StaticType('D', inherits: [c]);
expectExpand(a.nullable, a, 'A|Null');
expectExpand(a, a.nullable, 'A');
expectExpand(a.nullable, a.nullable, 'A|Null');
// Sealed subtype.
expectExpand(a.nullable, b, 'B|C|Null');
expectExpand(a, b.nullable, 'B|C');
expectExpand(a.nullable, b.nullable, 'B|C|Null');
// Unsealed subtype.
expectExpand(c.nullable, d, 'C|Null');
expectExpand(c, d.nullable, 'C');
expectExpand(c.nullable, d.nullable, 'C|Null');
});
}
void expectExpand(StaticType left, StaticType right, String expected) {
expect(expandType(left, right).join('|'), expected);
}