Skip to content

Negative trait bounds#561

Open
ozgunozerk wants to merge 3 commits intomainfrom
negative-trait-bounds
Open

Negative trait bounds#561
ozgunozerk wants to merge 3 commits intomainfrom
negative-trait-bounds

Conversation

@ozgunozerk
Copy link
Collaborator

@ozgunozerk ozgunozerk commented Feb 2, 2026

Fixes #560

PR Checklist

  • Tests
  • Documentation

P.S. strongly suggest to run cargo clean on your workspace after this merges, because we are switching toolchain. This will prevent non-sense weird error messages. Speaking from experience :')

Summary by CodeRabbit

  • Documentation

    • Revised architecture documentation to reflect override-based extension mechanism with compile-time constraint enforcement.
  • New Features

    • Added allowlist trait methods: allowed(), allow_user(), and disallow_user() for managing permitted accounts.
  • Refactor

    • Simplified trait inheritance requirements for token extensions.
    • Established mutual exclusivity between conflicting extension implementations (allowlist/blocklist, enumerable/consecutive).

@ozgunozerk ozgunozerk requested a review from brozorec February 2, 2026 08:29
@ozgunozerk ozgunozerk self-assigned this Feb 2, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 2, 2026

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

  • 🔍 Trigger a full review

Walkthrough

The PR switches the Rust toolchain to nightly and restructures trait-based extension design by removing associated ContractType constraints from multiple traits. Negative trait implementations are introduced to enforce mutual exclusivity between incompatible extensions, replacing the previous combinatorial workaround approach. FungibleAllowList gains new public methods for allowlist operations.

Changes

Cohort / File(s) Summary
Toolchain Configuration
rust-toolchain.toml, .github/workflows/generic.yml, packages/tokens/src/lib.rs
Updated Rust toolchain from stable to nightly; enabled negative_impls feature gate at crate root; adjusted cargo fmt invocation in CI workflow to use standard wrapper.
Architecture Documentation
Architecture.md
Rewrote Trait-Based Design section to emphasize Overrides mechanism and ContractOverrides over detailed constraint enforcement; introduced explicit negative trait impl examples (e.g., impl<T: NonFungibleEnumerable> !NonFungibleConsecutive for T {}) for mutual exclusivity enforcement.
Fungible Extensions
packages/tokens/src/fungible/extensions/allowlist/mod.rs, blocklist/mod.rs, mod.rs
Removed ContractType associated type constraints from FungibleAllowList and FungibleBlockList traits; added public methods to FungibleAllowList (allowed, allow_user, disallow_user); introduced negative impl to enforce mutual exclusivity between allowlist and blocklist.
Non-Fungible Extensions
packages/tokens/src/non_fungible/extensions/consecutive/mod.rs, enumerable/mod.rs, mod.rs
Removed ContractType constraints from NonFungibleConsecutive and NonFungibleEnumerable traits; added default forwarding implementations to NonFungibleEnumerable (total_supply, get_owner_token_id, get_token_id); introduced negative impl to enforce mutual exclusivity between enumerable and consecutive.
Core Trait Updates
packages/tokens/src/vault/mod.rs, rwa/mod.rs
Removed ContractType associated type constraints from FungibleVault and RWAToken traits; updated method implementations to call Vault:: directly instead of Self::ContractType::.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 Hark! The nightly channel gleams so bright,
With negative impls enforcing mutual might,
No more combinatorial dance we play,
Trait bounds reign supreme—hooray, hooray!
Extensions clash? They simply cannot be,
Compile-time wisdom sets us free!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The PR title 'Negative trait bounds' clearly and directly summarizes the main change: switching to nightly Rust's negative trait bounds feature to enforce mutual exclusivity between extensions.
Description check ✅ Passed The PR description references the linked issue (#560), marks both Tests and Documentation as complete, and provides helpful context about workspace cleanup. All required template sections are addressed.
Linked Issues check ✅ Passed The PR successfully implements the core objective from issue #560: replacing associated-type workarounds with nightly negative trait bounds for enforcing mutual exclusivity [#560]. Toolchain switched to nightly, negative impls added to prevent incompatible trait combinations, and trait bounds relaxed across multiple extension traits.
Out of Scope Changes check ✅ Passed All changes directly support the core objective of issue #560: switching to negative trait bounds. The Architecture.md update, toolchain.toml change, rust-toolchain.toml update, and generic.yml adjustments are all necessary to enable and implement the nightly feature.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch negative-trait-bounds

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link

codecov bot commented Feb 2, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 96.08%. Comparing base (26f939c) to head (b3c2058).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #561   +/-   ##
=======================================
  Coverage   96.08%   96.08%           
=======================================
  Files          54       54           
  Lines        5215     5215           
=======================================
  Hits         5011     5011           
  Misses        204      204           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@Architecture.md`:
- Line 36: Update the sentence in Architecture.md to hyphenate the compound
adjective: change the phrase "polymorphism like behavior" to "polymorphism-like
behavior" so the line reads "...we achieve polymorphism-like behavior through
**associated types** and **trait bounds**."
🧹 Nitpick comments (2)
.github/workflows/generic.yml (1)

49-51: Mirror the pinned nightly here once you select it.

When you pin nightly in rust-toolchain.toml, update this toolchain: value to the same date to prevent local/CI mismatches.

rust-toolchain.toml (1)

2-2: Pin nightly to a tested date for reproducibility and stable CI builds.

The codebase uses #![feature(negative_impls)], which requires the nightly channel. Since unpinned nightly can introduce unexpected compiler changes, specify a concrete nightly version (e.g., channel = "nightly-2026-02-01") to ensure consistent builds across environments.

@brozorec
Copy link
Collaborator

brozorec commented Feb 2, 2026

great work, this is very elegant but have a couple of concerns.

Using this feature requires the nightly toolchain, but I don't think this is a common practice in the ecosystem. I tested with stellar contract init and with scaffold-stellar as I guess the two most used boostrapers and both use stable. Let say, a dev starts with one of those and then they want to use our lib, they will bump into issues prompting them to change the toolchain. But looking from the perspective of an existing project, that will be a dealbreaker imo.

@ozgunozerk
Copy link
Collaborator Author

ozgunozerk commented Feb 2, 2026

they will bump into issues prompting them to change the toolchain. But looking from the perspective of an existing project, that will be a dealbreaker imo.

Why should it?

Nightly is compatible with stable. The deal breaker would be reverse scenario, where stellar_sdk uses nightly features, and we force our users to use the stable version.

Notice that soroban_sdk does not require us to use nightly, it is based on stable, yet we can compile everything completely fine by using nightly.

I don't see a problem tbh

@ozgunozerk
Copy link
Collaborator Author

On top of that, cargo automatically handles the change behind the scenes. Having some projects using nightly, and some using stable, at the same time, is not that uncommon in rust. The end developers may not even notice cargo is using nightly in the background

@brozorec
Copy link
Collaborator

brozorec commented Feb 2, 2026

the error I get:

error[E0554]: `#![feature]` may not be used on the stable release channel
  --> ~/stellar-contracts/packages/tokens/src/lib.rs:15:1
   |
15 | #![feature(negative_impls)]
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^

For more information about this error, try `rustc --explain E0554`.
error: could not compile `stellar-tokens` (lib) due to 1 previous error

@ozgunozerk
Copy link
Collaborator Author

that's weird. Because I didn't put any command on my workflow to change the toolchain. I just updated the toolchain file in the repo, and voila!

Let's go to slack for discussing this further

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.

🏗️ [Core Feature]: use nightly feature for mutual exclusivity

2 participants

Comments