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

RFC: Simplify rules on when traits can be used as objects #5086

Closed
nikomatsakis opened this issue Feb 22, 2013 · 1 comment
Closed

RFC: Simplify rules on when traits can be used as objects #5086

nikomatsakis opened this issue Feb 22, 2013 · 1 comment
Labels
A-traits Area: Trait system A-typesystem Area: The type system

Comments

@nikomatsakis
Copy link
Contributor

The current rules for when traits can be used as object types are a bit complex and hard to explain and understand. I propose the following:

  • A trait is said to be "object-compatible" if it meets the following requirements:
    • No method uses the Self type more than once, including the receiver and return type positions.
    • No use of by-value Self
  • For every object type @T, &T, or ~T, the trait T must be an object-compatible trait
  • No "static" functions (see extension below)

I am not sure what's the best place to report errors. We can enforce this in various possible ways:

  1. Report an error for every object type with an incompatible trait T.
  2. Report an error whenever an object is created with an incompatible trait T.
  3. Report an error when a method is called on an incompatible trait T.

Enforcing the rule at point (1) may result in a lot of errors but is probably the clearest thing. No matter what, I think we should definitely enforce the rule at point (2). It guarantees that no instances of illegal traits actually exist at runtime. We'll have to be careful around point (3) anyhow because users may try to call illegal methods; I think right now we ICE (see #5085).

Justifications

Why these rules? We need to prevent objects from being used in scenarios like this:

trait Eq {
    fn eq(&self, b: &Self) -> bool;
}

since we can't enforce this rule if we don't know what the Self type is.

Note that it's not enough to say "don't call eq()" because of generic code:

fn foo<A: Eq>(a: &A, b: &A) -> bool { a.eq(b) }

Unless we're careful, one could call foo() on an instance of @Eq since @Eq implements Eq.

What we do today

Today we do not permit eq() to be called and we say that if a trait is non-object-like, then @Eq does not implement Eq, thus preventing a generic method like foo() from being invoked. This is maximally flexible and sound but (I think) overly complex and hard to explain.

Possible Extensions

We could in principle allow return types of Self and "auto-box" them. This is an extension.

In some cases, we could also allow static functions, but we would need (a) auto-boxing for return values and (b) auto-unboxing on call. We then have to make sure that Self does not appear in a by-value position or as part of another type, like here:

trait Foo {
  fn foo(v: &Self) { ... } // OK, we can "auto-unwrap" in monomorphization
  fn foo(v: Self) { ... } // Not so good
  fn foo(v: Option<Self>) { ... } // Uh-oh
}
@nikomatsakis
Copy link
Contributor Author

Closing in favor of #5087

bors added a commit to rust-lang-ci/rust that referenced this issue May 2, 2020
don't fire `empty_loop` in `no_std` crates

closes rust-lang#3746.
changelog: move no_std detection to utils, don't fire empty_loop in no_std crates
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-traits Area: Trait system A-typesystem Area: The type system
Projects
None yet
Development

No branches or pull requests

1 participant