Skip to content

refactor: ⚡ Switch to thumb-mode to reduce code size - #2

Open
ion098 wants to merge 73 commits into
vexide:armv7a-vex-v5from
ion098:armv7a-vex-v5
Open

ion098 wants to merge 73 commits into
vexide:armv7a-vex-v5from
ion098:armv7a-vex-v5

Conversation

@ion098

@ion098 ion098 commented Jan 17, 2025

Copy link
Copy Markdown

No description provided.

max-niederman and others added 30 commits January 5, 2025 16:45
tropicaaal and others added 22 commits January 5, 2025 16:46
This isn't necessarily fixing anything on the V5 in particular (exit requests are handled by CPU0, which then interrupt CPU1 after), but it's certainly more correct and may be required for other single-core VEXos targets if support is added in the future.
0.23.0 most notably removes uses of `#[no_mangle]` from symbols in `vex-sdk` to avoid conflicts with other versions of the crate.

Symbols were originally `#[no_mangle]` for the purposes of compiling to a C static library, but this never ended up being useful and would be actively harmful to include in `libstd`.
The Cortex-A9 only has 16 double-precision registers (`d0`-`d15`), so this is the correct VFP instructionset to use.
This release of `vex-sdk` notably removes any (previously misguided) usage of `#[no_mangle]` which would be unsuitable to have in `libstd`.
@tropicaaal
tropicaaal force-pushed the armv7a-vex-v5 branch 2 times, most recently from f2e6bb2 to d0d1fd9 Compare January 25, 2025 09:17
tropicaaal pushed a commit that referenced this pull request Sep 3, 2025
…=jieyouxu

Rehome 30 `tests/ui/issues/` tests to other subdirectories under `tests/ui/` [#1 of Batch #2]

Part of rust-lang#133895

Methodology:

1. Refer to the previously written `tests/ui/SUMMARY.md`
2. Find an appropriate category for the test, using the original issue thread and the test contents.
3. Add the issue URL at the bottom (not at the top, as that would mess up stderr line numbers)
4. Rename the tests to make their purpose clearer

Inspired by the methodology that `@Kivooeo` was using.

r? `@jieyouxu`
tropicaaal pushed a commit that referenced this pull request Sep 3, 2025
…=jieyouxu

Rehome 30 `tests/ui/issues/` tests to other subdirectories under `tests/ui/` [#2 of Batch #2]

Part of rust-lang#133895

Methodology:

1. Refer to the previously written `tests/ui/SUMMARY.md`
2. Find an appropriate category for the test, using the original issue thread and the test contents.
3. Add the issue URL at the bottom (not at the top, as that would mess up stderr line numbers)
4. Rename the tests to make their purpose clearer

Inspired by the methodology that `@Kivooeo` was using.

r? `@jieyouxu`
tropicaaal pushed a commit that referenced this pull request Sep 20, 2025
…r=jieyouxu

Rehome 30 `tests/ui/issues/` tests to other subdirectories under `tests/ui/` [rust-lang#3 of Batch #2]

Part of rust-lang#133895

Methodology:

1. Refer to the previously written `tests/ui/SUMMARY.md`
2. Find an appropriate category for the test, using the original issue thread and the test contents.
3. Add the issue URL at the bottom (not at the top, as that would mess up stderr line numbers)
4. Rename the tests to make their purpose clearer

Inspired by the methodology that `@Kivooeo` was using.

r? `@jieyouxu`
lewisfm pushed a commit that referenced this pull request Oct 29, 2025
…r=jieyouxu

Rehome 30 `tests/ui/issues/` tests to other subdirectories under `tests/ui/` [rust-lang#4 of Batch #2]

Part of rust-lang#133895

Methodology:

1. Refer to the previously written `tests/ui/SUMMARY.md`
2. Find an appropriate category for the test, using the original issue thread and the test contents.
3. Add the issue URL at the bottom (not at the top, as that would mess up stderr line numbers)
4. Rename the tests to make their purpose clearer

Inspired by the methodology that `@Kivooeo` was using.

r? `@jieyouxu`
lewisfm pushed a commit that referenced this pull request Oct 29, 2025
…r=jieyouxu

Rehome 26 `tests/ui/issues/` tests to other subdirectories under `tests/ui/` [rust-lang#5 of Batch #2]

Part of rust-lang#133895

Methodology:

1. Refer to the previously written `tests/ui/SUMMARY.md`
2. Find an appropriate category for the test, using the original issue thread and the test contents.
3. Add the issue URL at the bottom (not at the top, as that would mess up stderr line numbers)
4. Rename the tests to make their purpose clearer

Inspired by the methodology that Kivooeo was using.

r? ```@jieyouxu```
lewisfm pushed a commit that referenced this pull request Sep 17, 2026
…ods, r=petrochenkov

delegation: supporting inherent impls

This PR adds support for delegation to inherent impl functions on the delegation side.

Support for inherent impls in delegation consists of two problems: we need to resolve inherent function through `ProbeContext` routine and then we need to generate delegation function knowing the `DefId` of the signature function. The first problem is a fundamental problem given current compiler architecture, and it is not solved in this PR. To imitate working resolution for tests we adopt simple resolution by name only in inherent impls (not trait impls, which would work if we implement fair resolution through `ProbeContext`). A `resolve_type_relative_delegations` query was created which tries to resolve unresolved delegations after resolve stage. In future, when we will be able to fairly resolve delegations through `ProbeContext` contents of this query can be changed and all other logic implemented in this pull request will work.

## Free to inherent impl

Unlike free to trait delegation where we generated explicit `Self` param, here we just use default parameter.

```rust
struct X<'a, T, const B: bool>(...);
impl<'a, T, const B: bool> X<'a, T, B> {
  fn foo<'b, U, const X: usize>(&self) { ... }
}

reuse X::<'static, (), false>::foo as foo1;
reuse X::<'static, (), false,>::foo::<'static, (), 123> as foo3;

//Desugaring:
#[attr = Inline(Hint)]
fn foo1<'b, U, const X: _>(self: _) -> _ where
    'b:'b { X<'static, (), false>::foo::<'b, U, X>(self) }

#[attr = Inline(Hint)]
fn foo3(self: _) -> _ { X<'static, (), false>::foo::<'static, (), 123>(self) }
```

## Trait to inherent impl

In trait to inherent impl delegation we replace the type of self parameter from impl's type to `Self` generic param (if the signature function is a method).

```rust
trait Trait {
    reuse X::<'static, (), false>::foo as foo1;
    reuse X::<'static, (), false,>::foo::<'static, (), true> as foo3;
}

// Desugaring:
trait Trait {
    #[attr = Inline(Hint)]
    fn foo1<'b, U, const X: _>(self: _) -> _ where
        'b:'b { X<'static, (), false>::foo::<'b, U, X>(self) }

    #[attr = Inline(Hint)]
    fn foo3(self: _)
        -> _ { X<'static, (), false>::foo::<'static, (), 123>(self) }
}
```

Note that we didn't specified target expression, so we would get errors like:
```rust
error[E0308]: mismatched types
  --> $DIR/xd.rs:10:14
   |
LL | trait Trait {
   | ----------- found this type parameter
LL |     reuse X::foo;
   |              ^^^
   |              |
   |              expected `&X<'_, T, B>`, found `&Self`
   |              arguments to this function are incorrect
   |
   = note: expected reference `&X<'_, T, B>`
              found reference `&Self`
```

## Trait impl to inherent impl

Here the resolution should look signature in trait as in other cases where we delegate from trait impl. We generate function whose signature matches the resolved function in trait. We propagate only child generics if they are not specified.

```rust
trait Trait {
    fn foo<A, B, C>(&self) { }
    fn foo1<T, U, V>(&self) { }
    fn foo2<'a, T, U, V>(&self) where 'a:'a { }
    fn foo3(&self) { }
}

impl Trait for X {
    reuse X::<'static, (), false>::foo as foo1;
    reuse X::<'static, (), false,>::foo::<'static, (), 123> as foo3;
}

// Desugaring:
impl Trait for X<'_> {
    #[attr = Inline(Hint)]
    fn foo1<T, U, V>(self: _)
        -> _ { X<'static, (), false>::foo::<T, U, V>(self) }

    #[attr = Inline(Hint)]
    fn foo3(self: _)
        -> _ { X<'static, (), false>::foo::<'static, (), 123>(self) }
}
```

## Inherent impl to inherent impl

In inherent impl to inherent impl delegation we replace signature self type with delegation parent self type in case of methods.
```rust
trait Trait {
    fn foo<A, B, C>(&self) { }
    fn foo1<T, U, V>(&self) { }
    fn foo2<'a, T, U, V>(&self) where 'a:'a { }
    fn foo3(&self) { }
}

struct Y;

impl Trait for Y {
    reuse X::<'static, (), false>::foo as foo1;
    reuse X::<'static, (), false,>::foo::<'static, (), 123> as foo3;
}

impl Trait for Y {
    #[attr = Inline(Hint)]
    fn foo1<T, U, V>(self: _)
        -> _ { X<'static, (), false>::foo::<T, U, V>(self) }

    #[attr = Inline(Hint)]
    fn foo3(self: _)
        -> _ { X<'static, (), false>::foo::<'static, (), 123>(self) }
}
```

We did not specify target expression so we would get errors like:
```rust
error[E0308]: mismatched types
  --> $DIR/xd.rs:12:14
   |
LL |     reuse X::foo;
   |              ^^^
   |              |
   |              expected `&X<'_, T, B>`, found `Y`
   |              arguments to this function are incorrect
   |
   = note: expected reference `&X<'_, T, B>`
                 found struct `Y`
```

## Generics

After some experiments I think that we should force user to always specify generics for parent segment of delegation to inherent impls. Consider the following example and imagine that we can use fair resolution through `ProbeContext`:

```rust
trait M1 {}
trait M2 {}

struct S1;
struct S2;

impl M1 for S1 {}
impl M2 for S2 {}

struct X<T, U>(T, U);

impl<T: M1> X<T, ()> {
    fn foo() {}
}

impl<T: M2> X<T, usize> {
    fn foo() {}
}

reuse X::foo;
```

How to resolve `X::foo`? If we generate parent generics (`fn foo<T, U>() { X::<T, U>::foo() }`) which clauses should we inherit? It is impossible to determine which function to reuse, and despite the fact that there may be some cases where it is possible, I don't think that we should write heuristics for that. So always specifying parent generics seems to be a good option. Also I think we should ban infers in parent segment too.

One implementation aspect of how we map generic args for signature and predicates inheritance, as we inherit predicates not from the ADT declaration but from the impl block we need to take generic args from this impl, not from the declaration. So indices of generic args are taken from the impl block and then they are used in mapping and future instantiation:

```rust
struct S<'a, A, const C: usize> {
    xd: &'a [A; C],
}

// index of A = 3
// index of C = 4
impl<'a, 'b, 'c, A, const C: usize> S<A, C> {
    fn foo_self<'d: 'd, 'e, T, const B: bool>(self) {}
}

trait Trait<'a, AA, BB> where Self: Sized {
    reuse S::<(), ()>::foo_self;
    // Args: [Self/#0, 'a/#1, AA/#2, BB/rust-lang#3, '{region error}, 'd/rust-lang#4, (), {const error}, T/rust-lang#5, B/rust-lang#6]
    // Mapping: {0: 0, 7: 9, 5: 5, 3: 6, 6: 8, 4: 7}, A (index 3) is mapped into index 6 (`()`), C (index 4) mapped into index 7 (const error)
}
```

## Other concerns

### Glob and list delegations

List delegations are supported, glob delegations are not supported:

```rust
struct X;

impl X {
    fn foo(&self) {}
    fn foo2(&self) {}
}

struct Y;

impl Y {
    reuse X::{foo, foo2} { X }
}

impl Y {
    reuse X::*;
    //~^ ERROR: expected trait, found struct `X`
}
```

### Self type adjustments and target expression deletion

Adjustments for receiver are applied, adjustments for other parameters whose types contain `Self` are not applied as `Self` acts as a type alias to the struct, not a generic param which will can get replaced. The deletion of target expression should work as before.

```rust
enum X {
   ...
}

impl X {
    fn static_f() {}
    fn by_value(self) {}
    fn by_ref(&self) {}
    fn by_mut_ref(&mut self) {}
}

struct Y;

impl Y {
    fn get_x(&self) -> X { X }
    reuse X::{static_f, by_value, by_ref, by_mut_ref} { self.get_x() }
}

impl Y {
    fn get_x(&self) -> X { X }

    #[attr = Inline(Hint)]
    fn static_f() -> _ { X::static_f() }

    #[attr = Inline(Hint)]
    fn by_value(self: _) -> _ { X::by_value(self.get_x()) }

    #[attr = Inline(Hint)]
    fn by_ref(self: _) -> _ { X::by_ref(self.get_x()) }

    #[attr = Inline(Hint)]
    fn by_mut_ref(self: _) -> _ { X::by_mut_ref(self.get_x()) }
}

fn main() {
    let y = Y;
    y.by_ref();
    y.by_mut_ref();
    //~^ ERROR: cannot borrow `y` as mutable, as it is not declared as mutable
    y.by_value();

    let y = &Y;
    y.by_value();
    //~^ ERROR: cannot move out of `*y` which is behind a shared reference
    y.by_ref();
    y.by_mut_ref();
    //~^ ERROR: cannot borrow `*y` as mutable, as it is behind a `&` reference

    let y = &mut Y;
    y.by_value();
    //~^ ERROR: cannot move out of `*y` which is behind a mutable reference
    y.by_ref();
    y.by_mut_ref();
}
```

### Recursive delegations

Works as before, we just check the resolution chain and we do not care whether it came from resolution at resolve stage or from resolution of type relative delegations.

r? @petrochenkov
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants