Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trait aliases make it possible to sidestep various syntactic trait bound checks #135342

Open
fmease opened this issue Jan 10, 2025 · 1 comment
Open
Labels
C-bug Category: This is a bug. F-trait_alias `#![feature(trait_alias)]` requires-nightly This issue requires a nightly compiler in some way. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-types Relevant to the types team, which will review and decide on the PR/issue.

Comments

@fmease
Copy link
Member

fmease commented Jan 10, 2025

Similar to how type aliases allow you to circumvent some syntactic/syntax-driven1 checks made by AST lowering (#132212), you can utilize trait aliases to bypass certain restrictions applying to trait bounds.

#![feature(trait_alias)]

trait SuperMaybeNeg: ?Sized {} // 🔴 REJECTED: `?Trait` is not permitted in supertraits
trait SuperMaybePos: MaybeSized {} // 🟢 Workaround: ACCEPTED

type DynMaybeNeg = dyn std::io::Write + ?Sized; // 🔴 REJECTED: `?Trait` is not permitted in trait object types
type DynMaybePos = dyn std::io::Write + MaybeSized; // 🟢 Workaround: ACCEPTED

fn noop_maybe_neg() where i32: ?Sized {} // 🔴 REJECTED: `?Trait` bounds are only permitted at the point where a type parameter is declared
fn noop_maybe_pos() where i32: MaybeSized {} // 🟢 Workaround: ACCEPTED


trait MaybeSized = ?Sized;
#![feature(trait_alias, const_trait_impl)]

const fn incompat_modifs_neg<T: const ?Trait>() {} // 🔴 REJECTED: const` trait not allowed with `?` trait polarity modifier
const fn incompat_modifs_pos<T: ?ConstTrait>() {} // 🟢 Workaround: ACCEPTED


trait ConstTrait = const Trait; // alternatively, `async Fn()` under feat `async_trait_bounds`
#[const_trait] trait Trait {}
#![feature(trait_alias)]

type DupeAssocNeg = dyn std::ops::Deref<Target = String, Target = i32>; // 🔴 REJECTED: the value of the associated type `Target` in trait `Deref` is already specified
type DupeAssocPos = dyn AssocFixed<Target = i32>; // 🟢 Workaround: ACCEPTED
//^ This bypasses a HIR ty lowering check, not an AST validation one.

type DynAtbNeg = dyn std::ops::Deref<Target: Copy>; // 🔴 REJECTED: associated type bounds are not allowed in `dyn` types
type DynAtbPosIsh<T> = dyn AssocBounded<Target = T>; // 🟢 Workaround-ish: ACCEPTED


trait AssocFixed = std::ops::Deref<Target = String>;
trait AssocBounded = std::ops::Deref<Target: Copy>;
#![feature(trait_alias, return_type_notation)]

struct DynRtnNeg(dyn Trait<method(..): Copy>); // 🔴 REJECTED: associated type bounds are not allowed in `dyn` types
                                               //              return type notation is not allowed to use type equality
struct DynRtnPos(dyn Rtn); // 🟢 Workaround: ACCEPTED

trait Trait { fn method(&self) -> impl Sized where Self: Sized; }
trait Rtn = Trait<method(..): Copy>;

This either calls into question the very existence of these restrictions or it demonstrates that all of these checks ought to run "later" (i.e., after trait alias expansion).

Footnotes

  1. I.e., checks on the AST or HIR without any sort of prior substitution/expansion/normalization/...

@fmease fmease added C-bug Category: This is a bug. F-trait_alias `#![feature(trait_alias)]` requires-nightly This issue requires a nightly compiler in some way. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team, which will review and decide on the PR/issue. labels Jan 10, 2025
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Jan 10, 2025
@fmease fmease added T-types Relevant to the types team, which will review and decide on the PR/issue. and removed needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. T-lang Relevant to the language team, which will review and decide on the PR/issue. labels Jan 10, 2025
@fmease fmease changed the title Trait aliases make it possible to sidestep several syntactic trait bound checks Trait aliases make it possible to sidestep various syntactic trait bound checks Jan 10, 2025
@compiler-errors
Copy link
Member

I'm not totally convinced all of these are bugs. For the first one, That MaybeSized one just seems like it needs to exist since we want to have a placeholder for "no trait bounds" -- think impl ?Sized for opaques.

For the second one, maybe we should just make ?Trait a hard error for trait aliases? Or else, I think if we envision trait X = Y as trait X: Y {} + impl X for T where T: Y {}, it's not exactly the same as writing ?const.

Third one seems like a disagreement about what we consider to be WF when it comes to dyn trait aliases. This will remain a bug until we stop doing that sketchy eager trait alias expansion behavior in dyn.

Same thing with the fourth one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug. F-trait_alias `#![feature(trait_alias)]` requires-nightly This issue requires a nightly compiler in some way. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-types Relevant to the types team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

3 participants