Skip to content

Commit 4a16b56

Browse files
author
Ariel Ben-Yehuda
committed
fix remaining bugs
1 parent c998057 commit 4a16b56

File tree

6 files changed

+125
-59
lines changed

6 files changed

+125
-59
lines changed

src/librustc/middle/traits/mod.rs

+44-38
Original file line numberDiff line numberDiff line change
@@ -340,47 +340,53 @@ pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
340340
ty,
341341
bound);
342342

343-
if !ty.has_infer_types() && !ty.has_closure_types() {
344-
let cause = ObligationCause::misc(span, ast::DUMMY_NODE_ID);
345-
let obligation =
346-
util::predicate_for_builtin_bound(infcx.tcx, cause, bound, 0, ty);
347-
let obligation = match obligation {
348-
Ok(o) => o,
349-
Err(..) => return false
350-
};
351-
let result = SelectionContext::new(infcx)
352-
.evaluate_obligation_conservatively(&obligation);
353-
debug!("type_known_to_meet_builtin_bound: ty={:?} bound={:?} => {:?}",
354-
ty, bound, result);
355-
return result;
356-
}
357-
358-
let mut fulfill_cx = FulfillmentContext::new(false);
359-
360-
// We can use a dummy node-id here because we won't pay any mind
361-
// to region obligations that arise (there shouldn't really be any
362-
// anyhow).
363343
let cause = ObligationCause::misc(span, ast::DUMMY_NODE_ID);
344+
let obligation =
345+
util::predicate_for_builtin_bound(infcx.tcx, cause, bound, 0, ty);
346+
let obligation = match obligation {
347+
Ok(o) => o,
348+
Err(..) => return false
349+
};
350+
let result = SelectionContext::new(infcx)
351+
.evaluate_obligation_conservatively(&obligation);
352+
debug!("type_known_to_meet_builtin_bound: ty={:?} bound={:?} => {:?}",
353+
ty, bound, result);
354+
355+
if result && (ty.has_infer_types() || ty.has_closure_types()) {
356+
// Because of inference "guessing", selection can sometimes claim
357+
// to succeed while the success requires a guess. To ensure
358+
// this function's result remains infallible, we must confirm
359+
// that guess. While imperfect, I believe this is sound.
360+
361+
let mut fulfill_cx = FulfillmentContext::new(false);
362+
363+
// We can use a dummy node-id here because we won't pay any mind
364+
// to region obligations that arise (there shouldn't really be any
365+
// anyhow).
366+
let cause = ObligationCause::misc(span, ast::DUMMY_NODE_ID);
364367

365-
fulfill_cx.register_builtin_bound(infcx, ty, bound, cause);
366-
367-
// Note: we only assume something is `Copy` if we can
368-
// *definitively* show that it implements `Copy`. Otherwise,
369-
// assume it is move; linear is always ok.
370-
match fulfill_cx.select_all_or_error(infcx) {
371-
Ok(()) => {
372-
debug!("type_known_to_meet_builtin_bound: ty={:?} bound={:?} success",
373-
ty,
374-
bound);
375-
true
376-
}
377-
Err(e) => {
378-
debug!("type_known_to_meet_builtin_bound: ty={:?} bound={:?} errors={:?}",
379-
ty,
380-
bound,
381-
e);
382-
false
368+
fulfill_cx.register_builtin_bound(infcx, ty, bound, cause);
369+
370+
// Note: we only assume something is `Copy` if we can
371+
// *definitively* show that it implements `Copy`. Otherwise,
372+
// assume it is move; linear is always ok.
373+
match fulfill_cx.select_all_or_error(infcx) {
374+
Ok(()) => {
375+
debug!("type_known_to_meet_builtin_bound: ty={:?} bound={:?} success",
376+
ty,
377+
bound);
378+
true
379+
}
380+
Err(e) => {
381+
debug!("type_known_to_meet_builtin_bound: ty={:?} bound={:?} errors={:?}",
382+
ty,
383+
bound,
384+
e);
385+
false
386+
}
383387
}
388+
} else {
389+
result
384390
}
385391
}
386392

src/librustc/middle/traits/select.rs

+30-11
Original file line numberDiff line numberDiff line change
@@ -2851,18 +2851,37 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
28512851
-> Vec<PredicateObligation<'tcx>>
28522852
{
28532853
debug!("impl_or_trait_obligations(def_id={:?})", def_id);
2854+
let tcx = self.tcx();
28542855

2855-
let predicates = self.tcx().lookup_predicates(def_id);
2856-
let predicates = predicates.instantiate(self.tcx(), substs);
2857-
let predicates = normalize_with_depth(self, cause.clone(), recursion_depth, &predicates);
2858-
let predicates = self.infcx().plug_leaks(skol_map, snapshot, &predicates);
2859-
2860-
let mut obligations = predicates.obligations;
2861-
obligations.append(
2862-
&mut util::predicates_for_generics(cause,
2863-
recursion_depth,
2864-
&predicates.value));
2865-
obligations
2856+
// To allow for one-pass evaluation of the nested obligation,
2857+
// each predicate must be preceded by the obligations required
2858+
// to normalize it.
2859+
// for example, if we have:
2860+
// impl<U: Iterator, V: Iterator<Item=U>> Foo for V where U::Item: Copy
2861+
// the impl will have the following predicates:
2862+
// <V as Iterator>::Item = U,
2863+
// U: Iterator, U: Sized,
2864+
// V: Iterator, V: Sized,
2865+
// <U as Iterator>::Item: Copy
2866+
// When we substitute, say, `V => IntoIter<u32>, U => $0`, the last
2867+
// obligation will normalize to `<$0 as Iterator>::Item = $1` and
2868+
// `$1: Copy`, so we must ensure the obligations are emitted in
2869+
// that order.
2870+
let predicates = tcx
2871+
.lookup_predicates(def_id)
2872+
.predicates.iter()
2873+
.flat_map(|predicate| {
2874+
let predicate =
2875+
normalize_with_depth(self, cause.clone(), recursion_depth,
2876+
&predicate.subst(tcx, substs));
2877+
predicate.obligations.into_iter().chain(
2878+
Some(Obligation {
2879+
cause: cause.clone(),
2880+
recursion_depth: recursion_depth,
2881+
predicate: predicate.value
2882+
}))
2883+
}).collect();
2884+
self.infcx().plug_leaks(skol_map, snapshot, &predicates)
28662885
}
28672886

28682887
#[allow(unused_comparisons)]

src/test/compile-fail/cast-rfc0401.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ fn main()
3737
let f: f32 = 1.2;
3838
let v = 0 as *const u8;
3939
let fat_v : *const [u8] = unsafe { &*(0 as *const [u8; 1])};
40+
let fat_sv : *const [i8] = unsafe { &*(0 as *const [i8; 1])};
4041
let foo: &Foo = &f;
4142

4243
let _ = v as &u8; //~ ERROR non-scalar
@@ -94,7 +95,7 @@ fn main()
9495
let _ = main as *mut str; //~ ERROR casting
9596
let _ = &f as *mut f32; //~ ERROR casting
9697
let _ = &f as *const f64; //~ ERROR casting
97-
let _ = fat_v as usize;
98+
let _ = fat_sv as usize;
9899
//~^ ERROR casting
99100
//~^^ HELP through a thin pointer first
100101

@@ -106,7 +107,7 @@ fn main()
106107
let _ = main.f as *const u32; //~ ERROR attempted access of field
107108

108109
let cf: *const Foo = &0;
109-
let _ = cf as *const [u8];
110+
let _ = cf as *const [u16];
110111
//~^ ERROR casting
111112
//~^^ NOTE vtable kinds
112113
let _ = cf as *const Bar;

src/test/compile-fail/infinite-instantiation.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
//~^^^^^^^^^^ ERROR overflow
1211
//
1312
// We get an error message at the top of file (dummy span).
1413
// This is not helpful, but also kind of annoying to prevent,
@@ -32,6 +31,7 @@ impl<T:Clone> ToOpt for Option<T> {
3231
}
3332

3433
fn function<T:ToOpt + Clone>(counter: usize, t: T) {
34+
//~^ ERROR reached the recursion limit during monomorphization
3535
if counter > 0 {
3636
function(counter - 1, t.to_option());
3737
// FIXME(#4287) Error message should be here. It should be

src/test/compile-fail/recursion.rs

+1-7
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,6 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
//~^^^^^^^^^^ ERROR overflow
12-
//
13-
// We get an error message at the top of file (dummy span).
14-
// This is not helpful, but also kind of annoying to prevent,
15-
// so for now just live with it.
16-
1711
enum Nil {NilValue}
1812
struct Cons<T> {head:isize, tail:T}
1913
trait Dot {fn dot(&self, other:Self) -> isize;}
@@ -26,7 +20,7 @@ impl<T:Dot> Dot for Cons<T> {
2620
}
2721
}
2822
fn test<T:Dot> (n:isize, i:isize, first:T, second:T) ->isize {
29-
match n { 0 => {first.dot(second)}
23+
match n { 0 => {first.dot(second)} //~ ERROR overflow
3024
// FIXME(#4287) Error message should be here. It should be
3125
// a type error to instantiate `test` at a type other than T.
3226
_ => {test (n-1, i+1, Cons {head:2*i+1, tail:first}, Cons{head:i*i, tail:second})}
+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// "guessing" in trait selection can affect `copy_or_move`. Check that this
12+
// is correctly handled. I am not sure what is the "correct" behaviour,
13+
// but we should at least not ICE.
14+
15+
use std::mem;
16+
17+
struct U([u8; 1337]);
18+
19+
struct S<'a,T:'a>(&'a T);
20+
impl<'a, T> Clone for S<'a, T> { fn clone(&self) -> Self { S(self.0) } }
21+
/// This impl triggers inference "guessing" - S<_>: Copy => _ = U
22+
impl<'a> Copy for S<'a, Option<U>> {}
23+
24+
fn assert_impls_fn<R,T: Fn()->R>(_: &T){}
25+
26+
fn main() {
27+
let n = None;
28+
let e = S(&n);
29+
let f = || {
30+
// S being copy is critical for this to work
31+
drop(e);
32+
mem::size_of_val(e.0)
33+
};
34+
assert_impls_fn(&f);
35+
assert_eq!(f(), 1337+1);
36+
37+
assert_eq!((|| {
38+
// S being Copy is not critical here, but
39+
// we check it anyway.
40+
let n = None;
41+
let e = S(&n);
42+
let ret = mem::size_of_val(e.0);
43+
drop(e);
44+
ret
45+
})(), 1337+1);
46+
}

0 commit comments

Comments
 (0)