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

Implement associated constants #23606

Merged
merged 8 commits into from
Apr 27, 2015
Merged

Conversation

quantheory
Copy link
Contributor

Closes #17841.

The majority of the work should be done, e.g. trait and inherent impls, different forms of UFCS syntax, defaults, and cross-crate usage. It's probably enough to replace the constants in f32, i8, and so on, or close to good enough.

There is still some significant functionality missing from this commit:

  • Associated consts can't be used in match patterns at all. This is simply because I haven't updated the relevant bits in the parser or resolve, but it's probably not hard to get working.
  • Since you can't select an impl for trait-associated consts until partway through type-checking, there are some problems with code that assumes that you can check constants earlier. Associated consts that are not in inherent impls cause ICEs if you try to use them in array sizes or match ranges. For similar reasons, check_static_recursion doesn't check them properly, so the stack goes ka-blooey if you use an associated constant that's recursively defined. That's a bit trickier to solve; I'm not entirely sure what the best approach is yet.
  • Dealing with consts associated with type parameters will raise some new issues (e.g. if you have a T: Int type parameter and want to use <T>::ZERO). See Update RFC 195 to account for RFC 246. rfcs#865.
  • Unused associated consts don't seem to trigger the dead_code lint when they should. Probably easy to fix.

Also, this is the first time I've been spelunking in rustc to such a large extent, so I've probably done some silly things in a couple of places.

@rust-highfive
Copy link
Collaborator

r? @pcwalton

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

@eddyb
Copy link
Member

eddyb commented Mar 22, 2015

🎉 This is great!
I'll be looking over the changes, but I'd rather have someone more knowledgeable (e.g. @nikomatsakis) with the latest advances in type-checking do the actual review.

ref_id: ast::NodeId)
-> Option<&'tcx Expr>
{
let rcvr_substs = ty::node_id_item_substs(tcx, ref_id).substs;
Copy link
Member

Choose a reason for hiding this comment

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

So you're expecting substitutions to be there, which means this can't be used earlier...
But this is an ExprPath, isn't it? Which means that at least the <T as Trait>::CONST case could be handled here, if an astconv interface were provided.

That reminds me, I meant to check if it's possible to move const_eval and everything depending on it to rustc_typeck and integrate it properly.
Maybe this can all be done in a follow-up PR after the groundwork has been laid.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point; I'm not really sure. The traits code is probably the main bit that I don't understand as well as I should here, so here (and even more so in rustc_typeck::check::compare_method) there may be a couple of details that are just superstitiously copied.

One thing that concerns me is that maybe we could have a path like <<T>::U as Trait>::CONST or <[T; <U>::N] as Trait>::CONST (or the nested UFCS could be in the trait, too). The former is disallowed right now because <T>::U can't be used to refer to an associated type; I don't know if that ever will be allowed in the future. The latter is of course one of the things I don't have working yet, but it seems like it could be done.

As for moving const_eval to rustc_typeck, probably the main obstacle there is that rustc_trans uses it. It's kind of awkward because middle::const_eval and trans::consts kind of duplicate some of each others' logic, but the former is more broadly used. But I think that const_eval is doing some things wrong that are done right in trans::consts. E.g. in const_eval all floats are treated as f64, and compare_const_vals treats them as totally ordered.

@quantheory
Copy link
Contributor Author

r? @nikomatsakis

@nikomatsakis
Copy link
Contributor

Exciting. I'll take a look. I agree that the interplay of constants, type-checking, and traits is subtle-- it's going to wind up (I think) as a kind of best-effort thing in the end, though I'd like to see add some amount of reasoning for treating constants more "generically" and deferring the actual evaluation until trans when types are known. This is probably related to some refactoring I've been doing for doing better normalization, but anyway.

@quantheory
Copy link
Contributor Author

@nikomatsakis

[...] I'd like to see add some amount of reasoning for treating constants more "generically" and deferring the actual evaluation until trans when types are known. This is probably related to some refactoring I've been doing for doing better normalization, but anyway.

I don't quite understand what you're saying. Certainly I'm interested in interaction between constants and types (note that I proposed rust-lang/rfcs#884, which is necessary, though far from sufficient, for some concrete applications I have in mind). Are you saying that you have a justification for deferring evaluation until trans, or that you want to know would I say about this? (I do think that such a change needs to happen, at least in some cases, but it's not directly relevant to this PR, I believe.)

@huonw
Copy link
Member

huonw commented Mar 24, 2015

though I'd like to see add some amount of reasoning for treating constants more "generically" and deferring the actual evaluation until trans when types are known

It seems this may lead to old-transmute like errors, where some constant evaluation that is only known in trans is invalid (e.g. depending how we handle it, overflow).

@bors
Copy link
Contributor

bors commented Mar 24, 2015

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

@quantheory
Copy link
Contributor Author

I have gotten match patterns working, though using associated consts in range patterns causes the same ICE as array sizes. (Actually, if we deferred checking that the lower bound is below the upper bound until check_match, I think that that would solve the issue, but some things need to get moved around for array sizes anyway, so I'm not sure if it's worth it.)

I will try to rebase today.

@quantheory quantheory force-pushed the associated_const branch 2 times, most recently from c6ca1b8 to e43afbc Compare March 25, 2015 17:24
@nikomatsakis
Copy link
Contributor

Are you saying that you have a justification for deferring evaluation until trans, or that you want to know would I say about this? (I do think that such a change needs to happen, at least in some cases, but it's not directly relevant to this PR, I believe.)

I wasn't really saying either of those things. Well, I do have justifications for potentially deferring evaluation until monomorphization -- e.g., type-checking [i32; X::LEN] -- but I wasn't suggesting it was relevant to this PR.

Anyway, sorry for the delay. I intend to review today (actually, yesterday, but a lot of stuff came up and I wound up away from my computer for much of the day).

@nikomatsakis
Copy link
Contributor

It seems this may lead to old-transmute like errors, where some constant evaluation that is only known in trans is invalid (e.g. depending how we handle it, overflow).

I was assuming type-checking would be more conservative than trans, not less.

@nikomatsakis
Copy link
Contributor

@quantheory

So I've been reading through and so far I'm enjoying what I read -- but one comment. We definitely want a feature-gate on this work before it can land! Can you add a feature-gate for defining a trait with an associated constant? (I think that's probably sufficient; we could add a feature-gate for referencing such a constant as well, but so long as we don't export any public interfaces that define them, that shouldn't be necessary.)

@quantheory
Copy link
Contributor Author

@nikomatsakis

Done! The feature gate covers both traits and impls, since you can define an inherent associated const.

@quantheory
Copy link
Contributor Author

Hmm, I fixed the last error to get a full make check working again, but it looks like Travis CI hit a glitch. 😞

@bors
Copy link
Contributor

bors commented Mar 28, 2015

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

@quantheory
Copy link
Contributor Author

Rebased. Hmm, is there a way to restart the Travis CI build?

@bors
Copy link
Contributor

bors commented Mar 30, 2015

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

@nikomatsakis
Copy link
Contributor

@quantheory cool, thanks. I read through most of the PR and didn't have any major comments, it all seemed quite nice. But then I got distracted again by the beta deadline and in particular researching and implementing rust-lang/rfcs#1023. Argh. I will look it over again today -- but now that there is a feature-gate, I feel pretty good about landing this before I understand every bit. We can improve over time.

@quantheory
Copy link
Contributor Author

@nikomatsakis OK, cool. Just rebased!

@nikomatsakis
Copy link
Contributor

OK, so I was doing some experimentation. I found that the following example ICEs:

// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(associated_consts)]

use std::marker::MarkerTrait;

trait Foo: MarkerTrait {
    const ID: i32;
}

trait Bar: MarkerTrait {
    const ID: i32;
}

impl Foo for i32 {
    const ID: i32 = 1;
}

impl Bar for i32 {
    const ID: i32 = 3;
}

const X: i32 = <i32>::ID;

fn main() {
    assert_eq!(1, X);
}

the problem is not super deep, it's just that the "ambiguity reporting" code assumes methods.

@nikomatsakis
Copy link
Contributor

So I'm basically ready to r+. I'm just wondering whether it makes sense to hold this till after the beta branch is cut this evening.

@nikomatsakis
Copy link
Contributor

(Basically, I'm inclined to wait because it seems like landing this patch can only create merge conflicts and other uncertainty, and the feature is feature-gated anyhow. Landing all the critical PRs before the branch deadline is always challenging anyway.)

@bors
Copy link
Contributor

bors commented Apr 1, 2015

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

@quantheory quantheory force-pushed the associated_const branch 2 times, most recently from d38d43f to 2cd6cd6 Compare April 17, 2015 06:36
@bors
Copy link
Contributor

bors commented Apr 22, 2015

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

@quantheory
Copy link
Contributor Author

@nikomatsakis bump

@cristicbz
Copy link
Contributor

@quantheory try #rust-internals IRC?

@nikomatsakis
Copy link
Contributor

@bors r+ p=1 4c0ac6d

Giving p=1 due to the fact that this has been hanging around. Thanks @quantheory for your persistence.

@bors
Copy link
Contributor

bors commented Apr 27, 2015

📌 Commit 4c0ac6d has been approved by nikomatsakis

bors added a commit that referenced this pull request Apr 27, 2015
Closes #17841.

The majority of the work should be done, e.g. trait and inherent impls, different forms of UFCS syntax, defaults, and cross-crate usage. It's probably enough to replace the constants in `f32`, `i8`, and so on, or close to good enough.

There is still some significant functionality missing from this commit:

 - ~~Associated consts can't be used in match patterns at all. This is simply because I haven't updated the relevant bits in the parser or `resolve`, but it's *probably* not hard to get working.~~
 - Since you can't select an impl for trait-associated consts until partway through type-checking, there are some problems with code that assumes that you can check constants earlier. Associated consts that are not in inherent impls cause ICEs if you try to use them in array sizes or match ranges. For similar reasons, `check_static_recursion` doesn't check them properly, so the stack goes ka-blooey if you use an associated constant that's recursively defined. That's a bit trickier to solve; I'm not entirely sure what the best approach is yet.
 - Dealing with consts associated with type parameters will raise some new issues (e.g. if you have a `T: Int` type parameter and want to use `<T>::ZERO`). See rust-lang/rfcs#865.
 - ~~Unused associated consts don't seem to trigger the `dead_code` lint when they should. Probably easy to fix.~~

Also, this is the first time I've been spelunking in rustc to such a large extent, so I've probably done some silly things in a couple of places.
@bors
Copy link
Contributor

bors commented Apr 27, 2015

⌛ Testing commit 4c0ac6d with merge 857ef6e...

@quantheory
Copy link
Contributor Author

🎉

@petrochenkov
Copy link
Contributor

Congrats.
Now it's time to empty the "primitive" modules!

@kvark
Copy link
Contributor

kvark commented May 6, 2015

Thanks @quantheory, this is a huge boon for us!

@burdges
Copy link

burdges commented Oct 12, 2016

Anyone considered replacing mem::size_of::<T>() with an associated constant, maybe part of the Sized trait or maybe not?

@mitchmindtree
Copy link
Contributor

@burdges I think this is one of the examples given in the original RFC

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.

subtask of RFC 195: Implement associated constants