blob: 1fdea0d6c53b8b645efc55be4339530619665d6e [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.
/// @assertion Given a type schema K and a record expression E of the general
/// form (e1, ..., en, d1 : e{n+1}, ..., dm : e{n+m}) inference proceeds as
/// follows.
///
/// If K is a record type schema of the form
/// (K1, ..., Kn, {d1 : K{n+1}, ...., dm : K{n+m}}) then:
///
/// - Each ei is inferred with context type schema Ki to have type Si
/// - Let Ri be the greatest closure of Ki
/// - If Si is a subtype of Ri then let Ti be Si
/// - Otherwise, if Si is dynamic, then we insert an implicit cast on ei to
/// Ri, and let Ti be Ri
/// - Otherwise, if Si is coercible to Ri (via some sequence of call method
/// tearoff or implicit generic instantiation coercions), then we insert the
/// appropriate implicit coercion(s) on ei. Let Ti be the type of the
/// resulting coerced value (which must be a subtype of Ri, possibly proper).
/// - Otherwise, it is a static error.
/// - The type of E is (T1, ..., Tn, {d1 : T{n+1}, ...., dm : T{n+m}})
/// If K is any other type schema:
///
/// - Each ei is inferred with context type schema _ to have type Ti
/// - The type of E is (T1, ..., Tn, {d1 : T{n+1}, ...., dm : T{n+m}})
///
/// @description Checks an implicit downcast for records
/// @author sgrekhov22@gmail.com
import "../../Utils/expect.dart";
import "../../Utils/static_type_helper.dart";
({List<int> list, Map<String, int> map, Set<String> set}) foo() =>
(list: [], map: {}, set: {}) ..expectStaticType<Exactly<
({List<int> list, Map<String, int> map, Set<String> set})>>();
void bar((List<int>, Map<String, int>, Set<String>) r) {
Expect.throws(() {(r.$1 as dynamic).add("");});
Expect.throws(() {(r.$2 as dynamic)[""] = "";});
Expect.throws(() {(r.$2 as dynamic)[42] = 42;});
Expect.throws(() {(r.$3 as dynamic).add(42);});
}
main() {
(List<int>, Map<String, int>, {Set<String> set}) r = ([], {}, set: {})
..expectStaticType<Exactly<
(List<int>, Map<String, int>, {Set<String> set})>>();
Expect.throws(() {(r.$1 as dynamic).add("");});
Expect.throws(() {(r.$2 as dynamic)[""] = "";});
Expect.throws(() {(r.$2 as dynamic)[42] = 42;});
Expect.throws(() {(r.set as dynamic).add(42);});
Expect.throws(() {(foo().list as dynamic).add("");});
Expect.throws(() {(foo().map as dynamic)[""] = "";});
Expect.throws(() {(foo().map as dynamic)[42] = 42;});
Expect.throws(() {(foo().set as dynamic).add(42);});
bar(([], {}, {})
..expectStaticType<Exactly<(List<int>, Map<String, int>, Set<String>)>>());
}