makepad/libs/relax/compiler/tests/method_probe_ambiguity.rs
Admin b22a714840 makepad run: the Rust JIT (libs/relax) and makepad-remote
The JIT that runs makepad apps from source: lexer, front end, type checker,
lazy borrow checker (Gandalf; `--check-first` opts in), codegen, session and
warm/cold caches keyed by compiler stamp, provided crates bound late,
startup images, live patching. User-facing name is `makepad run` (binary
`makepad`, MAKEPAD_RUN_* env, ~/.makepad-run); libs/relax stays the internal
library name. `makepad check` reports rustc-style diagnostics with rustc
error codes and checks a whole workspace (`--workspace`). Runs on macOS,
Linux, Windows and Android. makepad-remote: one tool schema for apps and the
WM (app/1): grabs, captures, traces, frame profiles and tweaks.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-13 12:26:21 +02:00

147 lines
4.5 KiB
Rust

use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
fn noop_raw() -> RawWaker {
fn clone(_: *const ()) -> RawWaker { noop_raw() }
fn noop(_: *const ()) {}
static VT: RawWakerVTable = RawWakerVTable::new(clone, noop, noop, noop);
RawWaker::new(std::ptr::null(), &VT)
}
fn block_on<F: Future>(mut future: F) -> F::Output {
let waker = unsafe { Waker::from_raw(noop_raw()) };
let mut cx = Context::from_waker(&waker);
let mut future = unsafe { Pin::new_unchecked(&mut future) };
loop {
if let Poll::Ready(value) = future.as_mut().poll(&mut cx) { return value; }
}
}
#[test]
fn integer_collect() {
let v: Vec<_> = (0..16).map(|i| i * 2).collect();
assert_eq!(v.len(), 16);
assert_eq!(v[15], 30);
}
async fn collect_async() {
let v: Vec<_> = (0..16).map(|i| i * 2).collect();
assert_eq!(v.len(), 16);
assert_eq!(v[15], 30);
}
#[test]
fn async_integer_collect() { block_on(collect_async()); }
struct PreparedBox<T>(std::marker::PhantomData<T>);
impl<T> PreparedBox<T> {
fn new() -> Self { Self(std::marker::PhantomData) }
fn initialize(self, value: T) -> Box<T> { Box::new(value) }
}
struct RetirementBatch<P> { items: [Option<P>; 64] }
struct TaskHandle<T>(Option<T>);
impl<T> TaskHandle<T> {
fn try_take(&mut self) -> Option<Result<T, ()>> { self.0.take().map(Ok) }
}
struct TaskSlot;
impl TaskSlot {
fn submit_internal_named<R: Send + 'static, F: FnOnce() -> R + Send + 'static>(
self, _name: &str, task: F,
) -> TaskHandle<R> {
TaskHandle(Some(task()))
}
}
struct RetirementBatches<P: Send + 'static> {
available: Vec<Box<RetirementBatch<P>>>,
preparing: Option<TaskHandle<Vec<Box<RetirementBatch<P>>>>>,
initialized: bool,
}
impl<P: Send + 'static> RetirementBatches<P> {
// The task field supplies collect's expected type through the outer closure, as in
// draw_list.rs's retirement poll. The integer range and inner closure stay unannotated.
// rustc_hir_typeck/src/method/probe.rs:2205 and
// rustc_type_ir/src/relate/solver_relating.rs:198 (@8d1a764) preserve pending obligations.
async fn poll(&mut self) -> bool {
if let Some(result) = self.preparing.as_mut().and_then(TaskHandle::try_take) {
self.preparing = None;
if let Ok(available) = result {
self.available = available;
self.initialized = true;
}
}
if !self.initialized {
if self.preparing.is_none() {
self.preparing = Some(TaskSlot.submit_internal_named("retirement batch storage", || {
(0..16)
.map(|_| {
PreparedBox::new().initialize(RetirementBatch {
items: std::array::from_fn(|_| None),
})
})
.collect()
}));
}
return false;
}
true
}
}
#[test]
fn generic_async_poll_collect_from_enclosing_closure() {
let mut batches = RetirementBatches::<u32> {
available: Vec::new(), preparing: None, initialized: false,
};
assert!(!block_on(batches.poll()));
assert!(block_on(batches.poll()));
assert_eq!(batches.available.len(), 16);
for batch in &batches.available {
assert_eq!(batch.items.len(), 64);
for item in &batch.items { assert!(item.is_none()); }
}
}
struct FloatRange<T> { next: T, end: T }
impl Iterator for FloatRange<f32> {
type Item = f32;
fn next(&mut self) -> Option<f32> {
if self.next >= self.end { return None; }
let value = self.next;
self.next += 1.0;
Some(value)
}
}
impl Iterator for FloatRange<f64> {
type Item = f64;
fn next(&mut self) -> Option<f64> {
if self.next >= self.end { return None; }
let value = self.next;
self.next += 1.0;
Some(value)
}
}
#[test]
fn float_collect() {
let v: Vec<_> = FloatRange { next: 0.0, end: 4.0 }.map(|i| i * 2.0).collect();
assert_eq!(v.len(), 4);
assert_eq!(v[3], 6.0);
}
trait Value { fn value(&self) -> u32 { 7 } }
struct Deferred<T>(Option<T>);
impl Value for Deferred<bool> {}
impl Value for Deferred<char> {}
#[test]
fn general_inference_collects_candidate_before_arguments_resolve() {
let mut value = Deferred(None);
assert_eq!(value.value(), 7);
value.0 = Some(true);
assert_eq!(value.value(), 7);
}