-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
detect extra region requirements in impls #37167
Conversation
trait_param_env, | ||
normalize_cause.clone()); | ||
|
||
tcx.infer_ctxt(None, Some(trait_param_env), Reveal::NotSpecializable).enter(|infcx| { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
indentation? the previous 20 or so lines should be de-indented because they are no longer within the infcx.
/// it easy to declare such methods on the builder. | ||
macro_rules! forward { | ||
// Forward pattern for &self -> &Self | ||
(pub fn $n:ident(&self, $($name:ident: $ty:ty),*) -> &Self) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: not sure a non-trivial macro is better than copy-paste here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seconded @arielb1 's comment... feels like it makes the code a little harder to read
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(i'm fine with the macro personally, but I can see that given the simplicity of these method bodies, this battle may not be worth fighting.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm. So I was going to remove the macro but hesitated for two reasons:
- I consider this a fairly trivial macro. =) But I can see that if you aren't familiar with macros you might not feel that way. And I was disappointed that I wound up requiring the three arms.
- The macro gives me an obvious place to put some documentation for why this forwarding is needed at all. Without the macro, I'd probably be inclined to just remove it, or else I have to just leave it dangling in the middle of the impl, where people are unlikely to see it.
Thoughts?
} | ||
|
||
impl EarlyLintMessage for String { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: merge this and the previous commit?
@@ -866,6 +866,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { | |||
err.note(&format!("required so that reference `{}` does not outlive its referent", | |||
ref_ty)); | |||
} | |||
ObligationCauseCode::ObjectTypeBound(object_ty, region) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test for this error message?
} | ||
} | ||
|
||
pub fn from_cause<F>(cause: &traits::ObligationCause<'tcx>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: from_obligation_cause? everything is some sort of a cause.
trait_item_span: Option<Span>, | ||
old_broken_mode: bool) { | ||
debug!("compare_impl_method(impl_trait_ref={:?})", | ||
impl_trait_ref); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2 duplicate calls to debug!?
I would also prefer the lines below this to be refactored out to 4 or so functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
heh, at first I was going to say that having two debug!
calls isn't a sin, but then I realized that @arielb1 is literally pointing out that the payload itself (impl_trait_ref
) is duplicated in both.
infcx.resolve_regions_and_report_errors(&free_regions, impl_m_body_id); | ||
} else { | ||
let fcx = FnCtxt::new(&inh, tcx.types.err, impl_m_body_id); | ||
fcx.regionck_item(impl_m_body_id, impl_m_span, &[]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This also calls relate_free_regions
from the impl. However, the liberated LBRs here come from the trait, so this is quite bogus, and even if it wasn't, you must avoid cases such as
trait Foo {
fn foo<'a, 'b>(x: &'a &'b u32, y: &'a &'b ());
}
impl Foo for () {
fn foo<'a, 'b>(x: &'b &'a u32, y: &'a &'b ());
}
Where the impl function's implied bounds tell you that 'a = 'b
, which bypasses the subtype check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ignore this - I misread regionck_item
. You might want to assume that the trait fn is WF, through.
The type-checking section LGTM modulo nits. I'll like @jonathandturner to look at the diagnostics section. |
@arielb1 Had a similar nit but that aside diagnostics looks good. |
Tidy is merciless
|
} | ||
|
||
impl<'a> A<'a> for B { | ||
fn foo<F>(&mut self, f: F) //~ ERROR parameter type `F` may not live long enough |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, does the error message here end up blaming the mismatch in lifetime bounds between the trait declaration and its implementation? I cannot tell from the portion of the diagnostic given here.
@@ -1,3 +1,4 @@ | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
delete this extraneous blank line
// `'a: 'b`. | ||
|
||
// Ignore `for<'a> T: 'a` -- we might in the future | ||
// consider this as evidence that `Foo: 'static`, but |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean "Foo" here, or "T: 'static" ?
// usually the changes we suggest would | ||
// actually have to be applied to the *trait* | ||
// method (and it's not clear that the trait | ||
// method is even under the user's control). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(and it's not clear that the trait method is even under the user's control)
can we not apply some heuristics here? For example, we could detect the scenario when the trait is defined in the same crate?
@@ -20,7 +20,7 @@ struct X { data: u32 } | |||
|
|||
impl Something for X { | |||
fn yay<T: Str>(_:Option<X>, thing: &[T]) { | |||
//~^ ERROR the requirement `T: Str` appears on the impl method | |||
//~^ ERROR E0276 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are all of these scenarios covered by the ui tests?
- If so, should we just delete these compile-fail tests?
- And if not, then I as a test reviewer personally prefer keeping the longer messages, as it gives me a better chance of divining what the original intent was from the test author.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(but I know that @nikomatsakis and i may simply fundamentally differ in our philosophies here.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I moved them to ui tests.
These changes look fine to me; r=me assuming you address the nits pointed out by @arielb1 |
☔ The latest upstream changes (presumably #37269) made this pull request unmergeable. Please resolve the merge conflicts. |
fb0ee77
to
39b3944
Compare
? |
@arielb1 wtf. That is very strange. Locally I also see a bunch of "parse-fail" test failures, which I assume is some kind of misconfiguration on my part. |
39b3944
to
82ab686
Compare
ping @nikomatsakis any idea what's going on with travis on this PR? |
☔ The latest upstream changes (presumably #37378) made this pull request unmergeable. Please resolve the merge conflicts. |
@pnkfelix not sure, but I think it must have to do with some of the changes I made to adjusting the error count. I've been meaning to figure this out -- hopefully I'll find some time today. |
@pnkfelix so I think I tracked down the problem -- or at least I tracked down a problem I see locally. Locally, some of the parse-fail tests are failing. We used to print this:
But we now print this:
Note that in both cases it ends with "error: aborting due to previous error" (i.e., the singular). I think what caused this difference is how I changed the mechanism to adjust the error count. Consider the diff for pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
self.emit(&sp.into(), msg, Error);
- self.bump_err_count();
self.panic_if_treat_err_as_bug();
} I changed it so that we bump the error count in the I think this also fixed a bug in the existing parser, which changes the output here. In particular, the pub fn emit(&self, msp: &MultiSpan, msg: &str, lvl: Level) {
if lvl == Warning && !self.can_emit_warnings {
return;
}
let mut db = DiagnosticBuilder::new(self, lvl, msg);
db.set_span(msp.clone());
db.emit();
if !self.continue_after_error.get() { // (** HERE **)
self.abort_if_errors();
}
} Now, in the old code, the error count had not been bumped at this point -- it got bumped after So I would argue that this is a bugfix (cc @nrc) in the case of the parse-fail tests. I'm not sure if this explains the other tests -- I'm going to patch the reference files locally and see what happens, maybe travis is running the tests in a funny order or something. |
Actually I'll add |
gets more comprehensive coverage in `ui`
The new handling fixed a latent bug in the parser error handling where it would only abort after the second error (when configured to stop after the first error). This is because the check for `error_count != 0` was occuring before the increment. Since the increment is tied to the `emit()` call now this no longer occurs.
The old parse code kept going even though it wasn't supposed to, leading to an E0045 ("feature not allowed on beta") printout
cdb7195
to
4501e5a
Compare
This now builds locally -- or did before rebase. Let's see what travis has to say. |
@bors r=pnkfelix |
📌 Commit 4501e5a has been approved by |
⌛ Testing commit 4501e5a with merge 0717508... |
💔 Test failed - auto-win-msvc-64-opt |
@bors: retry On Wed, Nov 2, 2016 at 2:29 PM, bors [email protected] wrote:
|
⌛ Testing commit 4501e5a with merge 9dfaf1e... |
💔 Test failed - auto-win-gnu-32-opt-rustbuild |
@bors: retry |
⌛ Testing commit 4501e5a with merge 135b76e... |
💔 Test failed - auto-mac-64-opt-rustbuild |
@bors: retry |
⌛ Testing commit 4501e5a with merge ccfc38f... |
detect extra region requirements in impls The current "compare method" check fails to check for the "region obligations" that accrue in the fulfillment context. This branch switches that code to create a `FnCtxt` so that it can invoke the regionck code. Previous crater runs (I haven't done one with the latest tip) have found some small number of affected crates, so I went ahead and introduced a warning cycle. I will kick off a crater run with this branch shortly. This is a [breaking-change] because previously unsound code was accepted. The crater runs also revealed some cases where legitimate code was no longer type-checking, so the branch contains one additional (but orthogonal) change. It improves the elaborator so that we elaborate region requirements more thoroughly. In particular, if we know that `&'a T: 'b`, we now deduce that `T: 'b` and `'a: 'b`. I invested a certain amount of effort in getting a good error message. The error message looks like this: ``` error[E0276]: impl has stricter requirements than trait --> traits-elaborate-projection-region.rs:33:5 | 21 | fn foo() where T: 'a; | --------------------- definition of `foo` from trait ... 33 | fn foo() where U: 'a { } | ^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `U: 'a` | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #18937 <#18937> note: lint level defined here --> traits-elaborate-projection-region.rs:12:9 | 12 | #![deny(extra_requirement_in_impl)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ ``` Obviously the warning only prints if this is a _new_ error (that resulted from the bugfix). But all existing errors that fit this description are updated to follow the general template. In order to get the lint to preserve the span-labels and the error code, I separate out the core `Diagnostic` type (which encapsulates the error code, message, span, and children) from the `DiagnosticBuilder` (which layers on a `Handler` that can be used to report errors). I also extended `add_lint` with an alternative `add_lint_diagnostic` that takes in a full diagnostic (cc @jonathandturner for those changes). This doesn't feel ideal but feels like it's moving in the right direction =). r? @pnkfelix cc @arielb1 Fixes #18937
The current "compare method" check fails to check for the "region obligations" that accrue in the fulfillment context. This branch switches that code to create a
FnCtxt
so that it can invoke the regionck code. Previous crater runs (I haven't done one with the latest tip) have found some small number of affected crates, so I went ahead and introduced a warning cycle. I will kick off a crater run with this branch shortly.This is a [breaking-change] because previously unsound code was accepted. The crater runs also revealed some cases where legitimate code was no longer type-checking, so the branch contains one additional (but orthogonal) change. It improves the elaborator so that we elaborate region requirements more thoroughly. In particular, if we know that
&'a T: 'b
, we now deduce thatT: 'b
and'a: 'b
.I invested a certain amount of effort in getting a good error message. The error message looks like this:
Obviously the warning only prints if this is a new error (that resulted from the bugfix). But all existing errors that fit this description are updated to follow the general template. In order to get the lint to preserve the span-labels and the error code, I separate out the core
Diagnostic
type (which encapsulates the error code, message, span, and children) from theDiagnosticBuilder
(which layers on aHandler
that can be used to report errors). I also extendedadd_lint
with an alternativeadd_lint_diagnostic
that takes in a full diagnostic (cc @jonathandturner for those changes). This doesn't feel ideal but feels like it's moving in the right direction =).r? @pnkfelix
cc @arielb1
Fixes #18937