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 alias infrastructure #45047

Merged
merged 11 commits into from
Dec 14, 2017
Merged

trait alias infrastructure #45047

merged 11 commits into from
Dec 14, 2017

Conversation

durka
Copy link
Contributor

@durka durka commented Oct 5, 2017

This will be an implementation of trait aliases (RFC 1733, #41517).

Progress so far:

Postponed:

I need some pointers on where to start with that last one. The test currently does this:

error[E0283]: type annotations required: cannot resolve `_: CD`
  --> src/test/run-pass/trait-alias.rs:34:16
   |
34 |     let both = foo();
   |                ^^^
   |
   = note: required by `foo`

@rust-highfive
Copy link
Collaborator

r? @eddyb

(rust_highfive has picked a reviewer for you, use r? to override)

@@ -391,6 +391,9 @@ impl<'a> Resolver<'a> {
self.define(parent, ident, TypeNS, (module, vis, sp, expansion));
self.current_module = module;
}
ItemKind::TraitAlias(..) => {
// TODO: do we need to do anything here?
Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, the same thing as in ItemKind::Ty (only with Def::TraitAlias).

Copy link
Contributor

Choose a reason for hiding this comment

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

You'll also have to add a new variant to PathSource for contexts permitting trait alias paths (they are slightly different than contexts permitting trait paths.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Why would the contexts be different? Because impl Alias {} won't be allowed?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes.
So you'll automatically get "expected a trait, found a trait alias" errors on impl Alias {}.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This already happens with no modifications to PathSource.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh but maybe this is needed to check for impl Alias for Struct {}?

} else {
self.expect(&token::Eq)?;
let bounds = self.parse_ty_param_bounds()?;
self.expect(&token::Semi)?;
Copy link
Contributor

Choose a reason for hiding this comment

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

where clauses?

/// Trait alias
///
/// E.g. `trait Foo = Bar + Quux;`
TraitAlias(Generics, TyParamBounds),
Copy link
Contributor

Choose a reason for hiding this comment

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

I need to reread the RFC, but IIRC there should be two sets of predicates - one for the alias itself (LHS) and one for the alias substitution result.
I.e.

trait Alias<T: Clone> = where T: Default;

=>

trait Alias<T> whereLHS T: Clone = whereRHS T: Default;

(But maybe they are equivalent?)

Copy link
Contributor

Choose a reason for hiding this comment

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

I mean Alias<NoClone> is an immediate error, but Alias<CloneNoDefault> is a valid always-false predicate.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think they are equivalent - both are added as predicates.

Copy link
Contributor

Choose a reason for hiding this comment

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

This should be related to #21903 somehow.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The RFC only mentions whereRHS.

Copy link
Contributor

Choose a reason for hiding this comment

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

@durka
Could you prohibit bounds on trait alias' generic parameters in ast_validation for now?

trait TraitAlias<T: Bound /* <-- error, this one represents "whereLHS" */>

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sounds good.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added an error for this and also trait Alias<T = ()>. cfail

@petrochenkov
Copy link
Contributor

@durka

I need some pointers on where to start with that last one.

TLDR is "look how instantiate_poly_trait_ref and friends (in predicates_of) turn hir:: bounds and where clauses into ty::Predicates and do the same thing".

@bors
Copy link
Contributor

bors commented Oct 5, 2017

☔ The latest upstream changes (presumably #45046) made this pull request unmergeable. Please resolve the merge conflicts.

@eddyb
Copy link
Member

eddyb commented Oct 5, 2017

r? @petrochenkov

@rust-highfive rust-highfive assigned petrochenkov and unassigned eddyb Oct 5, 2017
@shepmaster shepmaster added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Oct 6, 2017
@durka
Copy link
Contributor Author

durka commented Oct 14, 2017

I'm in way over my head here.

I stopped explicit_predicates_of from adding a Self: TheAlias bound when evaluating TheAlias directly. But that doesn't work when evaluating something using the alias, like fn foo<T: TheAlias>(...) { ... }, because astconv simply constructs the predicates itself without consulting collect. So I added a hack to Bounds::predicates that scans for aliases and calls super_predicates_of to eliminate them. It seems really fishy, but it only gets me to another error, shown here with logs:

DEBUG:rustc_typeck::check::wfcheck: check_item_well_formed(it.id=73, it.name=foo)
DEBUG:rustc::traits::fulfill: select(obligation-forest-size=0)
DEBUG:rustc::traits::fulfill: select: starting another iteration
DEBUG:rustc::traits::fulfill: select: outcome=Outcome { completed: [], errors: [], stalled: true }
DEBUG:rustc::traits::fulfill: select(0 predicates remaining, 0 errors) done
DEBUG:rustc_typeck::check: normalize_associated_types_in(value=Binder(([]; variadic: false)->(T, T)))
DEBUG:rustc_typeck::check: normalize_associated_types_in: result=Binder(([]; variadic: false)->(T, T)) predicates=[]
DEBUG:rustc_typeck::check: normalize_associated_types_in(value=InstantiatedPredicates([Binder(TraitPredicate(<T as std::marker::Sized>)), Binder(TraitPredicate(<Self as std::clone::Clone>)), Binder(TraitPredicate(<Self as std::default::Default>))]))
DEBUG:rustc_typeck::check: normalize_associated_types_in: result=InstantiatedPredicates([Binder(TraitPredicate(<T as std::marker::Sized>)), Binder(TraitPredicate(<Self as std::clone::Clone>)), Binder(TraitPredicate(<Self as std::default::Default>))]) predicates=[]
DEBUG:rustc_typeck::check::wfcheck: check_item_fn: predicates=InstantiatedPredicates([Binder(TraitPredicate(<T as std::marker::Sized>)), Binder(TraitPredicate(<Self as std::clone::Clone>)), Binder(TraitPredicate(<Self as std::default::Default>))])
DEBUG:rustc_typeck::check::wfcheck: check_item_fn_or_method: 1
DEBUG:rustc_typeck::check: normalize_associated_types_in(value=Binder(([]; variadic: false)->(T, T)))
DEBUG:rustc_typeck::check: normalize_associated_types_in: result=Binder(([]; variadic: false)->(T, T)) predicates=[]
DEBUG:rustc_typeck::check::wfcheck: check_item_fn_or_method: 2
DEBUG:rustc_typeck::check::wfcheck: check_item_fn_or_method: 3
DEBUG:rustc_typeck::check::wfcheck: check_item_fn_or_method: 4
DEBUG:rustc_typeck::check::wfcheck: check_item_fn_or_method: 5
DEBUG:rustc_typeck::check: register_predicate(Obligation(predicate=WF((T, T)),depth=0))
DEBUG:rustc::traits::fulfill: register_predicate_obligation(obligation=Obligation(predicate=WF((T, T)),depth=0))
DEBUG:rustc_typeck::check::wfcheck: check_item_fn_or_method: 6
DEBUG:rustc_typeck::check::wfcheck: check_item_fn_or_method: 7
DEBUG:rustc_typeck::check: register_predicate(Obligation(predicate=Binder(TraitPredicate(<T as std::marker::Sized>)),depth=0))
DEBUG:rustc::traits::fulfill: register_predicate_obligation(obligation=Obligation(predicate=Binder(TraitPredicate(<T as std::marker::Sized>)),depth=0))
DEBUG:rustc_typeck::check: register_predicate(Obligation(predicate=WF(T),depth=0))
DEBUG:rustc::traits::fulfill: register_predicate_obligation(obligation=Obligation(predicate=WF(T),depth=0))
DEBUG:rustc_typeck::check: register_predicate(Obligation(predicate=Binder(TraitPredicate(<Self as std::marker::Sized>)),depth=0))
DEBUG:rustc::traits::fulfill: register_predicate_obligation(obligation=Obligation(predicate=Binder(TraitPredicate(<Self as std::marker::Sized>)),depth=0))
DEBUG:rustc_typeck::check: register_predicate(Obligation(predicate=Binder(TraitPredicate(<Self as std::clone::Clone>)),depth=0))
DEBUG:rustc::traits::fulfill: register_predicate_obligation(obligation=Obligation(predicate=Binder(TraitPredicate(<Self as std::clone::Clone>)),depth=0))
DEBUG:rustc_typeck::check: register_predicate(Obligation(predicate=WF(Self),depth=0))
DEBUG:rustc::traits::fulfill: register_predicate_obligation(obligation=Obligation(predicate=WF(Self),depth=0))
DEBUG:rustc_typeck::check: register_predicate(Obligation(predicate=Binder(TraitPredicate(<Self as std::marker::Sized>)),depth=0))
DEBUG:rustc::traits::fulfill: register_predicate_obligation(obligation=Obligation(predicate=Binder(TraitPredicate(<Self as std::marker::Sized>)),depth=0))
DEBUG:rustc_typeck::check: register_predicate(Obligation(predicate=Binder(TraitPredicate(<Self as std::default::Default>)),depth=0))
DEBUG:rustc::traits::fulfill: register_predicate_obligation(obligation=Obligation(predicate=Binder(TraitPredicate(<Self as std::default::Default>)),depth=0))
DEBUG:rustc_typeck::check: register_predicate(Obligation(predicate=WF(Self),depth=0))
DEBUG:rustc::traits::fulfill: register_predicate_obligation(obligation=Obligation(predicate=WF(Self),depth=0))
DEBUG:rustc_typeck::check::wfcheck: check_item_fn_or_method: 8
DEBUG:rustc_typeck::check: select_all_obligations_or_error
DEBUG:rustc::traits::fulfill: select(obligation-forest-size=7)
DEBUG:rustc::traits::fulfill: select: starting another iteration
DEBUG:rustc::traits::fulfill: selecting trait `Binder(TraitPredicate(<T as std::marker::Sized>))` at depth 0 yielded Ok(None)
DEBUG:rustc::traits::fulfill: process_predicate: pending obligation Obligation(predicate=Binder(TraitPredicate(<T as std::marker::Sized>)),depth=0) now stalled on []
DEBUG:rustc::traits::fulfill: selecting trait `Binder(TraitPredicate(<Self as std::marker::Sized>))` at depth 0 yielded Ok(None)
DEBUG:rustc::traits::fulfill: process_predicate: pending obligation Obligation(predicate=Binder(TraitPredicate(<Self as std::marker::Sized>)),depth=0) now stalled on []
DEBUG:rustc::traits::fulfill: selecting trait `Binder(TraitPredicate(<Self as std::clone::Clone>))` at depth 0 yielded Ok(Some)
DEBUG:rustc::traits::fulfill: selecting trait `Binder(TraitPredicate(<Self as std::default::Default>))` at depth 0 yielded Ok(Some)
DEBUG:rustc::traits::fulfill: select: outcome=Outcome { completed: [PendingPredicateObligation { obligation: Obligation(predicate=Binder(TraitPredicate(<Self as std::default::Default>)),depth=0), stalled_on: [] }, PendingPredicateObligation { obligation: Obligation(predicate=WF(Self),depth=0), stalled_on: [] }, PendingPredicateObligation { obligation: Obligation(predicate=Binder(TraitPredicate(<Self as std::clone::Clone>)),depth=0), stalled_on: [] }, PendingPredicateObligation { obligation: Obligation(predicate=WF(T),depth=0), stalled_on: [] }], errors: [], stalled: false }
DEBUG:rustc::traits::fulfill: select: starting another iteration
DEBUG:rustc::traits::fulfill: selecting trait `Binder(TraitPredicate(<T as std::marker::Sized>))` at depth 0 yielded Ok(None)
DEBUG:rustc::traits::fulfill: process_predicate: pending obligation Obligation(predicate=Binder(TraitPredicate(<T as std::marker::Sized>)),depth=0) now stalled on []
DEBUG:rustc::traits::fulfill: selecting trait `Binder(TraitPredicate(<Self as std::marker::Sized>))` at depth 0 yielded Ok(None)
DEBUG:rustc::traits::fulfill: process_predicate: pending obligation Obligation(predicate=Binder(TraitPredicate(<Self as std::marker::Sized>)),depth=0) now stalled on []
DEBUG:rustc::traits::fulfill: select: outcome=Outcome { completed: [], errors: [], stalled: true }
DEBUG:rustc::traits::fulfill: select(3 predicates remaining, 0 errors) done
DEBUG:rustc::traits::fulfill: select(obligation-forest-size=3)
DEBUG:rustc::traits::fulfill: select: starting another iteration
DEBUG:rustc::traits::fulfill: selecting trait `Binder(TraitPredicate(<T as std::marker::Sized>))` at depth 0 yielded Ok(None)
DEBUG:rustc::traits::fulfill: process_predicate: pending obligation Obligation(predicate=Binder(TraitPredicate(<T as std::marker::Sized>)),depth=0) now stalled on []
DEBUG:rustc::traits::fulfill: selecting trait `Binder(TraitPredicate(<Self as std::marker::Sized>))` at depth 0 yielded Ok(None)
DEBUG:rustc::traits::fulfill: process_predicate: pending obligation Obligation(predicate=Binder(TraitPredicate(<Self as std::marker::Sized>)),depth=0) now stalled on []
DEBUG:rustc::traits::fulfill: select: outcome=Outcome { completed: [], errors: [], stalled: true }
DEBUG:rustc::traits::fulfill: select(3 predicates remaining, 0 errors) done
DEBUG:rustc::traits::fulfill: select(obligation-forest-size=3)
DEBUG:rustc::traits::fulfill: select: starting another iteration
DEBUG:rustc::traits::fulfill: selecting trait `Binder(TraitPredicate(<T as std::marker::Sized>))` at depth 0 yielded Ok(None)
DEBUG:rustc::traits::fulfill: process_predicate: pending obligation Obligation(predicate=Binder(TraitPredicate(<T as std::marker::Sized>)),depth=0) now stalled on []
DEBUG:rustc::traits::fulfill: selecting trait `Binder(TraitPredicate(<Self as std::marker::Sized>))` at depth 0 yielded Ok(None)
DEBUG:rustc::traits::fulfill: process_predicate: pending obligation Obligation(predicate=Binder(TraitPredicate(<Self as std::marker::Sized>)),depth=0) now stalled on []
DEBUG:rustc::traits::fulfill: select: outcome=Outcome { completed: [], errors: [], stalled: true }
DEBUG:rustc::traits::fulfill: select(3 predicates remaining, 0 errors) done
error[E0282]: type annotations needed
  --> src/test/run-pass/trait-alias.rs:27:1
   |
27 | / fn foo<T: CD>() -> (T, T) {
28 | |     let one = T::default();
29 | |     let two = one.clone();
30 | |     (one, two)
31 | | }
   | |_^ cannot infer type for `T`

I can't see where the error is coming from, since trait selection keeps saying no errors and the log looks similar to successful fulfillments, to my eye. Where should I look next?

Copy link
Contributor

@nikomatsakis nikomatsakis left a comment

Choose a reason for hiding this comment

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

OK, did a quick read through, here are two off-the-cuff comments.

self.print_name(item.name)?;
self.print_generics(generics)?;
let mut real_bounds = Vec::with_capacity(bounds.len());
// FIXME(durka) this seems to be some quite outdated syntax
Copy link
Contributor

Choose a reason for hiding this comment

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

yeah, you used to have to say trait Foo for ?Sized, but now that's the default (and you have to write trait Foo: Sized)

Copy link
Contributor

Choose a reason for hiding this comment

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

I would assume that TraitBoundModifier::Maybe in this context is illegal, right? i.e., trait Foo = ?Sized is kind of nonsense.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed.

@@ -1446,7 +1447,15 @@ impl<'a, 'gcx, 'tcx> Bounds<'tcx> {
}

for bound_trait_ref in &self.trait_bounds {
vec.push(bound_trait_ref.to_predicate());
if let Some(node_id) = tcx.hir.as_local_node_id(bound_trait_ref.def_id()) {
if let hir::ItemTraitAlias(..) = tcx.hir.expect_item(node_id).node {
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm. This doesn't seem like the right place to be doing these sorts of tests. By the time we get to ty::TraitRef, aliases should already be expanded, I think -- or, alternatively, we should do the expansion during trait resolution. The latter seems better and more like the strategy we want long term (not sure if that's the direction you've been going, still reading into the PR). Either way, this bit of code should't have to change.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed (see below).

@@ -668,7 +668,7 @@ fn adt_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
/// Ensures that the super-predicates of the trait with def-id
/// trait_def_id are converted and stored. This also ensures that
/// the transitive super-predicates are converted;
fn super_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
pub fn super_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this public now? It's a provider so I think it should not have to be, we should be using the query instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's public because I needed it in the hack that I added to astconv, which you correctly pointed out just above is the wrong place 😛

@nikomatsakis
Copy link
Contributor

Question:

Is the overall strategy here to treat a "trait alias" trait Foo = Bar as its own kind of trait, but:

  • it has 'supertraits' Bar, hence we elaborate T: Foo into T: Bar?
  • to prove that T: Foo is true, we must prove that T: Bar is true?

If so, I approve. =) This is how I had hoped to do it, though for some reason I thought we might need to do some kind of "syntactic expansion" first. But now I don't see a reason we have to go through that step.

if items.is_some() {
// Add in a predicate that `Self:Trait` (where `Trait` is the
// current trait). This is needed for builtin bounds.
predicates.push(trait_ref.to_poly_trait_ref().to_predicate());
Copy link
Contributor

Choose a reason for hiding this comment

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

I feel like we should be able to treat traits and trait aliases the same here if we set things up right (i.e., either both or neither would get this extra predicate). But it's not a big deal I don't think.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, this is the part that works if you say "what are the preds of TraitAlias" (i.e. it adds only the super predicates and not TraitAlias itself) but falls over if you ask "what are the preds of <some item that refers to TraitAlias>", which may indicate it's too early or late to be distinguishing traits from aliases.

@nikomatsakis
Copy link
Contributor

nikomatsakis commented Oct 16, 2017

@durka

But that doesn't work when evaluating something using the alias, like fn foo<T: TheAlias>(...) { ... }, because astconv simply constructs the predicates itself without consulting collect.

I think that this comment is exactly your problem here, though it's possible I misunderstand. I think that hunk should basically be reverted. Instead, we want to extend the select logic to understand trait aliases.

There are ways I can see to do this. One way would be that, in HIR lowering, we would basically generate a synthetic impl like impl<..., T> TraitAlias for T. Effectively something like trait Foo = Bar would be desugared to something like this. This is kind of slick but will require some effort to get the error messages nice, of course.

Some questions though:

  • Can trait aliases be used with object types? I believe so, and that seems to imply we have to be careful about how we are handling supertraits here, since that influences object safety and in particular what methods can be invoked.
  • I think what we probably want is a third category:
    • Right now, we have superpredicates (which are basically Self: Foo where-clauses) and predicates.
    • Superpredicates are used to construct trait objects and also used in elaboration.
    • I suspect we want to separate those two roles, so that trait aliases can have one set of superpredicates that are used for trait objects, and another that are used for elaboration (which includes all where-clauses on the trait alias).

The other way would be to extend trait selection to treat "trait aliases" as a kind of native concept. This isn't too much work, we probably have to add a new vtable variant like TraitAlias:

pub enum Vtable<'tcx, N> {
    ...
    VtableAlias(VtableAliasData),
    ...
}

pub struct VtableAliasData<N> {
    pub alias_def_id: DefId,
    pub substs: &'tcx Substs<'tcx>,
    pub nested: Vec<N>,
}

and then extend this logic here to add an "alias candidate" for aliases and things. This promises to be straightforward but a lot of boilerplate.

Personally, I'm inclined to go with the "lower at HIR construction time" route myself.

What do you all think? Am I overlooking something here or does this all make sense. =)

@durka
Copy link
Contributor Author

durka commented Oct 16, 2017

What you asked about was indeed my plan, and I figured I would get to the trait object subtleties once I got everything to stop ICEing all the time 😛.

About the HIR desugaring: hmm, but I claimed that sugar was accurate early in the RFC thread, I was corrected. The reasons I was wrong were that (1) it wouldn't allow you to impl a trait alias (which we decided not to allow in the end, but could be relitigated in the future), and (2) it means that let x: Box<AliasOfBar> = Box::new(foo) as Box<Bar>; would not work. So these sort of seem to argue for doing the expansion deeper in the compiler.

@nikomatsakis
Copy link
Contributor

@durka

The reasons I was wrong were

Also the supertraits point that I raised earlier =)

it wouldn't allow you to impl a trait alias

While true, I think this isn't quite a blocker. In particular, if we do decide to permit that, I feel like it would mostly mean that we want to adjust the desugaring further -- i.e., maybe we desugar that impl by unrolling the trait alias one step (in fact, that's what I would probably expect us to do), but leaving the "magic, implicit" impl for the alias in place.

(Really, I want to rework trait selection so that everything winds up getting lowered internally to simpler primitives anyway, which would kind of render this discussion semi-moot, but we're not there yet.)

it means that let x: Box<AliasOfBar> = Box::new(foo) as Box<Bar>; would not work.

This is an interesting point, but I think orthogonal from the question of whether to desugar into a "synthetic HIR impl" vs customizing trait selection. It might argue for another approach entirely, though I suspect it can be made to work.

Basically, the problem here is that Box<dyn AliasOfBar> would be lowered to a trait object whose trait def-id is the alias, and we don't (right now) permit much in the way of interconversion between dyn types. Note that I'm adopting the dyn syntax to make the "trait used in type" vs "trait used as logical predicate" distinction more evident, since it is crucial here. Basically, either adding the impl or hacking resolve solves the "trait used as logical predicate" problem (I believe), but neither solves the "trait used in type" scenario.

I think we can correct this in two ways:

  • When creating a trait object type, we "dereference" trait aliases -- i.e., dyn AliasOfBar, in the compiler, would be unrolled into dyn Bar. Now the mismatch goes away (but the user's error messages will show dyn Bar instead of dyn AliasOfBar).
  • We could hack up trait object unification so that unifying dyn T and dyn U succeeds if T is an alias for U or vice versa. This sounds like a pain in the neck.

I favor the first idea. =)

@durka
Copy link
Contributor Author

durka commented Oct 17, 2017

First idea sounds good to me! Type errors already see through type aliases, so the error message doesn't seem like a blocker to me. But, does it present a problem with more complex aliases? For example, Box<dyn Clone + Default where for<'a> Self: Foo<'a>> doesn't quite parse :)

@durka
Copy link
Contributor Author

durka commented Oct 17, 2017

@nikomatsakis So, basically I should revert most of my changes to collect and astconv and focus on select instead? Can you give some more specific pointers?

@nikomatsakis
Copy link
Contributor

@durka

For example, Box<dyn Clone + Default where for<'a> Self: Foo<'a>> doesn't quite parse :)

First off, I would say it's a good idea to produce a first PR that basically just makes it an error to use trait aliases in an object type.

In any case, I imagine that after we expand the trait alias we'll have to examine the traits and make sure that they fit what our current set of object types can support.

You can already type things (e.g., dyn (Display + Debug)) that are not legal object types at the moment.

@petrochenkov
Copy link
Contributor

petrochenkov commented Oct 17, 2017

I've read the previous messages, but I still don't understand why trait aliases can't be expanded in astconv/collect in the same exact way like type aliases are expanded (doesn't matter where, in trait objects or not in trait objects).

@durka
Copy link
Contributor Author

durka commented Oct 17, 2017

Where are type aliases expanded?

@petrochenkov
Copy link
Contributor

@durka

Where are type aliases expanded?

fn def_to_ty/fn ast_path_to_ty

@carols10cents
Copy link
Member

Triage ping to keep this on your radar @durka!

@durka
Copy link
Contributor Author

durka commented Oct 30, 2017 via email

@nikomatsakis
Copy link
Contributor

@petrochenkov

I've read the previous messages, but I still don't understand why trait aliases can't be expanded in astconv/collect in the same exact way like type aliases are expanded (doesn't matter where, in trait objects or not in trait objects).

They could, but I'd prefer to avoid that if we can. For one thing, it does not offer an easy path to handling where clauses. I actually hope to refactor so that type aliases are also expanded in the trait system eventually, as a kind of poor man's associated type.

@nikomatsakis nikomatsakis self-assigned this Nov 7, 2017
@nikomatsakis
Copy link
Contributor

@durka how's it going? Still have time to work on this?

@durka
Copy link
Contributor Author

durka commented Nov 10, 2017 via email

@kennytm
Copy link
Member

kennytm commented Dec 14, 2017

@durka Yeah clippy is an unrelated error. You may ignore it for now.

@durka
Copy link
Contributor Author

durka commented Dec 14, 2017

@bors r=petrochenkov

@bors
Copy link
Contributor

bors commented Dec 14, 2017

📌 Commit 834674f has been approved by petrochenkov

@kennytm kennytm added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Dec 14, 2017
@bors
Copy link
Contributor

bors commented Dec 14, 2017

⌛ Testing commit 834674f with merge 0077d12...

bors added a commit that referenced this pull request Dec 14, 2017
trait alias infrastructure

This will be an implementation of trait aliases (RFC 1733, #41517).

Progress so far:

- [x] Feature gate
- [x] Add to parser
  - [x] `where` clauses
    - [x] prohibit LHS type parameter bounds via AST validation #45047 (comment)
- [x] Add to AST and HIR
  - [x] make a separate PathSource for trait alias contexts #45047 (comment)
- [x] Stub out enough of typeck and resolve to just barely not ICE

Postponed:

- [ ] Actually implement the alias part
- [ ] #21903
- [ ] #24010

I need some pointers on where to start with that last one. The test currently does this:

```
error[E0283]: type annotations required: cannot resolve `_: CD`
  --> src/test/run-pass/trait-alias.rs:34:16
   |
34 |     let both = foo();
   |                ^^^
   |
   = note: required by `foo`
```
@bors
Copy link
Contributor

bors commented Dec 14, 2017

☀️ Test successful - status-appveyor, status-travis
Approved by: petrochenkov
Pushing 0077d12 to master...

@bors bors merged commit 834674f into rust-lang:master Dec 14, 2017
@varkor varkor mentioned this pull request Feb 21, 2018
13 tasks
bors added a commit that referenced this pull request Nov 2, 2018
Implement trait aliases (RFC 1733)

Extends groundwork done in #45047, and fully implements rust-lang/rfcs#1733.

CC @durka @nikomatsakis
bors added a commit that referenced this pull request Nov 3, 2018
Implement trait aliases (RFC 1733)

Extends groundwork done in #45047, and fully implements rust-lang/rfcs#1733.

CC @durka @nikomatsakis
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Dec 6, 2022
Remove outdated syntax from trait alias pretty printing

Given the following program:
```rust
#![feature(trait_alias)]
trait A = ?Sized;

fn main() {}
```
Old output of `rustc +nightly ./t.rs -Zunpretty=normal`:
```rust
#![feature(trait_alias)]
trait A for ? Sized ;

fn main() {}
```
New output of `rustc +a ./t.rs -Zunpretty=normal`:
```rust
#![feature(trait_alias)]
trait A = ?Sized;

fn main() {}
```

cc `@durka` (you've written the `FIXME` in rust-lang#45047, see rust-lang#45047 (comment))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants