dart-sdk/tests/language/static_type_helper.dart
Paul Berry 7dda27b543 inference-update-3: use unpromoted type as context for local variable assignments.
This change implements one of the features of experimental feature
`inference-update-3`: with the experimental feature enabled,
assignments to local variables use the declared (or inferred) type of
the local variable as the context for evaluating the RHS of the
assignment, regardless of whether the local variable is promoted. With
the experimental feature disabled, assignments to local variables
continue to use the promoted type of the local variable as the context
for evaluating the RHS of the assignment.

This eliminates one of the scenarios in which the context type of an
assignment is "aspirational" (i.e., not required to be met in order to
prevent a compile time error). Once all aspirational context types
have been removed from the language, we will be able to re-work
coercions to be based on context type, which fixes a number of
usability footguns in the language. See
https://github.com/dart-lang/language/issues/3471 for details.

Bug: https://github.com/dart-lang/language/issues/3471
Change-Id: Ic07ac1810b641a9208c168846cd5fd912088d62b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/338802
Reviewed-by: Bob Nystrom <rnystrom@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
2023-12-07 23:30:06 +00:00

91 lines
2.9 KiB
Dart

// Copyright (c) 2020, 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.
/// Helper to create [Type] values.
Type typeOf<T>() => T;
/// Ensures a context type of [T] for the operand.
Object? context<T>(T x) => x;
/// Captures the context type of the call and returns the same type.
///
/// Can be used to check the context type as:
/// ```dart
/// int x = contextType(1 /* valid value */)..expectStaticType<Exactly<int>>;
/// ```
T contextType<T>(Object? result) => result as T;
extension StaticType<T> on T {
/// Check the static type.
///
/// Use as follows (assuming `e` has static type `num`):
/// ```dart
/// e.expectStaticType<Exactly<num>>() // No context type.
/// e.expectStaticType<SubtypeOf<Object>>() // No context type.
/// e.expectStaticType<SupertypeOf<int>>() // No context type.
/// ```
/// or
/// ```dart
/// e..expectStaticType<Exactly<num>>() // Preserve context type.
/// e..expectStaticType<SubtypeOf<Object>>() // Preserve context type.
/// e..expectStaticType<SupertypeOf<int>>() // Preserve context type.
/// ```
/// This will be a *compile-time error* if the static type is not
/// as required by the constraints type (the one passed to [Exactly],
/// [SubtypeOf] or [SupertypeOf].)
T expectStaticType<R extends Exactly<T>>() {
return this;
}
/// Invokes [callback] with the static type of `this`.
///
/// Allows any operation on the type.
T captureStaticType(void Function<X>() callback) {
callback<T>();
return this;
}
}
/// Invokes [callback] with the static type of [value].
///
/// Similar to [StaticType.captureStaticType], but works
/// for types like `void` and `dynamic` which do not allow
/// extension methods.
void captureStaticType<T>(T value, void Function<X>(X value) callback) {
callback<T>(value);
}
/// Use with [StaticType.expectStaticType] to expect precisely the type [T].
///
/// Example use:
/// ```dart
/// "abc".expectStaticType<Exactly<String>>();
/// ```
typedef Exactly<T> = T Function(T);
/// Use with [StaticType.expectStaticType] to expect a subtype of [T].
///
/// Example use:
/// ```dart
/// num x = 1;
/// x.expectStaticType<SubtypeOf<Object>>();
/// ```
typedef SubtypeOf<T> = Never Function(T);
/// Use with [StaticType.expectStaticType] to expect a supertype of [T].
///
/// Example use:
/// ```dart
/// num x = 1;
/// x.expectStaticType<SupertypeOf<int>>();
/// ```
typedef SupertypeOf<T> = T Function(Object?);
/// Checks that an expression is assignable to [T1], [T2] and [Object].
///
/// This ensures that the static type of the expression is either dynamic,
/// Never, or a type assignable to both [T1] and [T2], and if those are
/// unrelated, it must be an intersection type.
void checkIntersectionType<T1, T2>(T1 v1, T2 v2, Object v3) {}