Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upTreatment of regions in trait matching is perhaps too simplistic #21974
Comments
nikomatsakis
added
the
A-lifetimes
label
Feb 5, 2015
nikomatsakis
self-assigned this
Feb 5, 2015
This comment has been minimized.
This comment has been minimized.
|
Note that this problem only really arises with where-clauses, since in the case of impls all lifetimes (other than 'static) are variables bound in the impl itself. |
This comment has been minimized.
This comment has been minimized.
|
After some discussion with @aturon I feel a bit better here. It's true that the current code is not handling this scenario correctly, in a couple of ways, but there is a plausible way forward (described below). Moreover, for the short short term, I think I can make progress in my implied bounds experiments by filtering the predicates we add to the environment a bit. The obvious way forward is to overhaul region inference so that rather than simply infallibly collecting constraints as it goes, it actually evaluates the constraints that it has at hand to decide whether adding a new constraint will create an insolvable graph or not. I have to do some investigation into the best algorithms here but this kind of "live updated" dataflow graph seems like something that has certainly been explored over time, so I'm sure there's a really nifty algorithmic solution that will be tons of fun to implement. The other change that is needed is to modify the trait checker, which currently has a rule that says "If I see two matches from where clauses, drop one of them". This rule can probably be dropped completely given #21968, but if not, it can at least be made more sensitive. This would imply that the calls above would yield ambiguous results until the inference graph is complete enough to select just one of the where clauses. |
This comment has been minimized.
This comment has been minimized.
|
Note that this is not obviously 100% backwards compat, but I think it probably falls under the realm of "bug fix". |
This comment has been minimized.
This comment has been minimized.
|
In particular, if we do it right, we're just detecting (earlier) guaranteed errors that will occur later. But we should probably modify the trait checker so that the example above at least yields ambiguity now. I will experiment with that. |
nikomatsakis
added a commit
to nikomatsakis/rust
that referenced
this issue
Feb 5, 2015
nikomatsakis
added a commit
to nikomatsakis/rust
that referenced
this issue
Feb 6, 2015
nikomatsakis
added a commit
to nikomatsakis/rust
that referenced
this issue
Feb 6, 2015
edwardw
referenced this issue
Feb 8, 2015
Closed
Trait implementation accepts wrong lifetime in method signature with associated type #22077
edwardw
referenced this issue
Feb 21, 2015
Closed
Inference failure with for-loop and associated type that contains lifetimes #22066
nikomatsakis
referenced this issue
Feb 23, 2015
Closed
can't store static references in a Unique indirectly #22655
arielb1
referenced this issue
Apr 15, 2015
Closed
"coherence failed to report ambiguity" ICE Involving Lifetimes #24424
This comment has been minimized.
This comment has been minimized.
|
Here are some weird things I've noticed. This doesn't compile, the compiler is too picky: use std::ops::Add;
fn plus<T>(a: &T, b: &T) -> T where
for <'a> &'a T: Add<&'a T, Output=T>,
{
a + b // error: cannot infer an appropriate lifetime for automatic coercion due to conflicting requirements
}
fn main() {}Solution: Either annotate a and b params with the same lifetime, or do the following fn plus<T>(a: &T, b: &T) -> T where
for <'a, 'b> &'a T: Add<&'b T, Output=T>,
{
a + b
}But we can add nonsense bounds to existential clauses too fn plus<'c, T>(a: &'c T, b: &'c T) -> T where
for <'a: 'c> &'a T: Add<&'a T, Output=T>,
{
let s = a + b;
&s + &s
}Only Add for lifetimes longer than |
This comment has been minimized.
This comment has been minimized.
|
The problem with your first program is that trait matching does not do subtyping - it does work if you reborrow: use std::ops::Add;
fn plus<T>(a: &T, b: &T) -> T where
for <'a> &'a T: Add<&'a T, Output=T>,
{
&*a + &*b
}
fn main() {
println!("1+1={}", plus(&1,&1));
}You last program works as you wrote it – http://is.gd/SUyb2X. |
This comment has been minimized.
This comment has been minimized.
|
Neither of these examples are relevant to this issue anyway. |
This comment has been minimized.
This comment has been minimized.
|
@arielb1 Thanks for the clarification! The last program had the |
nikomatsakis
referenced this issue
Aug 14, 2015
Open
False ambiguity due to overlap between higher-ranked and other where clause #27834
arielb1
referenced this issue
Aug 27, 2015
Open
Type inference problem with lifetimes and assoiated types #28046
arielb1
referenced this issue
Sep 14, 2015
Closed
ICE: assertion failed: leak_check(infcx, &skol_map, snapshot).is_ok() #22872
This comment has been minimized.
This comment has been minimized.
|
Triage: this issue is kind of vague, and has a lot going on. Given this comment and that the original example still does not compile, it seems like this is something that might be doable, but it's not clear that we will/should. |
Zoxc
referenced this issue
Mar 10, 2017
Merged
fix #40294 obligation cause.body_id is not always a NodeExpr #40404
dtolnay
referenced this issue
May 4, 2017
Open
Inference disrupted by trait bound that is redundant with a HRTB #41617
Mark-Simulacrum
added
the
C-enhancement
label
Jul 22, 2017
Zoxc
referenced this issue
Sep 25, 2017
Open
Rust thinks std::marker::Sized differ from std::marker::Sized #44835
This comment has been minimized.
This comment has been minimized.
|
Apparently this causes problems when adding new implicit type parameter bounds and implicit trait supertraits (like use std::fmt::Debug;
trait DescriptiveSpec<'r> {}
impl<'r, T> DescriptiveSpec<'r> for &'r T {}
fn from_spec<'r, T: DescriptiveSpec<'r>>(spec: &'r T) {}
fn matching_contains<'s, T: 's, I>(a: &mut &'s I) where &'s I: Debug {
from_spec(a);
}
fn main() {} |
nikomatsakis commentedFeb 5, 2015
Not sure why I didn't see this coming. Until now, the treatment of regions in trait matching has intentionally ignored lifetimes (in the sense of, it did not consider lifetime constraints when deciding what impl to apply -- once an impl is selected, the constraints that appear on it naturally are enforced). The reason for this is that lifetime inference is a second pass that uses a much more flexible constraint-graph solving algorithm, in contrast to the bulk of type inference which uses something much closer to unification. A side-effect of this is that you cannot easily get a "yes or no" answer to the question "does
'x : 'yhold?" One must see wait until all the constraints have been gathered to know.However, this leads to problems when you have multiple predicates in the environment that reference lifetimes. This is easy to see in the following example, but one does not need where clauses to get into this situation:
this winds up failing to compile because it can't really distinguish the two predicates here, since they are identical but for the specific lifetimes involved. This doesn't arise much in practice because it's unusual to have two requirements like that, usually you either have a more universal requirement (e.g.,
for<'a> &'a T : Foo), or just one particular lifetime you are interested in. I observed this problem however when experimenting with implied bounds, because it is common for multiple indistinguishable bounds of this kind to be generated as part of that proposal.I'm not really sure how best to solve this at the moment.