blob: 92d8a1d7e34cdbd28efe405a774df16661584f20 [file] [edit]
// Copyright (c) 2026, 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.
// This test is based on the repro for
// https://github.com/dart-lang/sdk/issues/33298. It illustrates that the types
// that arise from a type coercion need to be accounted for in type inference.
//
// Specifically, these tests verify that, after type inference has finished
// visiting all the arguments of an invocation, made a preliminary assignment of
// types to type parameters, and then performed assignability checks on each of
// the arguments, if any of those assignability checks resulted in the insertion
// of a coercion, then the static type of the coerced expression is then used to
// generate additional type constraints.
//
// For example, in the invocation `List<String> list2 = ['a', 'b',
// 'c'].map(a).toList()` below, the assignability check to see if `a` is usable
// as an argument to `map` results in a coercion, causing `a` to be treated as
// `a.call`. After this coercion is generated, type inference needs to then use
// the static type of `a.call` to generate additional type constraints. This
// results in a constraint that the type argument to `map` must be a supertype
// of `String`, which in turn ensures that the type of `['a', 'b', 'c'].map(a)`
// is `Iterable<String>`. Without this extra constraint generation step, the
// type of `['a', 'b', 'c']` would be `Iterable<dynamic>`.
import 'package:expect/expect.dart';
class A {
String call(String s) => '$s$s';
}
class B<T> {
T call(T t) => t;
}
class C {
T call<T>(T t) => t;
}
main() {
A a = A();
List<String> list1 = ['a', 'b', 'c'].map(a.call).toList();
Expect.listEquals(['aa', 'bb', 'cc'], list1);
List<String> list2 = ['a', 'b', 'c'].map(a).toList();
Expect.listEquals(['aa', 'bb', 'cc'], list2);
B<String> b = B();
List<String> list3 = ['a', 'b', 'c'].map(b.call).toList();
Expect.listEquals(['a', 'b', 'c'], list3);
List<String> list4 = ['a', 'b', 'c'].map(b).toList();
Expect.listEquals(['a', 'b', 'c'], list4);
C c = C();
List<String> list5 = ['a', 'b', 'c'].map(c.call).toList();
Expect.listEquals(['a', 'b', 'c'], list5);
List<String> list6 = ['a', 'b', 'c'].map(c).toList();
Expect.listEquals(['a', 'b', 'c'], list6);
}