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

Ensure the types of methods are well-formed #28669

Merged
merged 3 commits into from
Oct 3, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/librustc/middle/ty/structural_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,9 @@ impl<'tcx, A: Lift<'tcx>, B: Lift<'tcx>> Lift<'tcx> for (A, B) {
impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for [T] {
type Lifted = Vec<T::Lifted>;
fn lift_to_tcx(&self, tcx: &ty::ctxt<'tcx>) -> Option<Self::Lifted> {
let mut result = Vec::with_capacity(self.len());
// type annotation needed to inform `projection_must_outlive`
let mut result : Vec<<T as Lift<'tcx>>::Lifted>
= Vec::with_capacity(self.len());
for x in self {
if let Some(value) = tcx.lift(x) {
result.push(value);
Expand Down
22 changes: 14 additions & 8 deletions src/librustc_typeck/check/method/confirm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,22 +103,23 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
// Unify the (adjusted) self type with what the method expects.
self.unify_receivers(self_ty, method_self_ty);

// Add any trait/regions obligations specified on the method's type parameters.
self.add_obligations(&pick, &all_substs, &method_predicates);

// Create the final `MethodCallee`.
// Create the method type
let method_ty = pick.item.as_opt_method().unwrap();
let fty = self.tcx().mk_fn(None, self.tcx().mk_bare_fn(ty::BareFnTy {
sig: ty::Binder(method_sig),
unsafety: method_ty.fty.unsafety,
abi: method_ty.fty.abi.clone(),
}));

// Add any trait/regions obligations specified on the method's type parameters.
self.add_obligations(fty, &all_substs, &method_predicates);

// Create the final `MethodCallee`.
let callee = ty::MethodCallee {
def_id: pick.item.def_id(),
ty: fty,
substs: self.tcx().mk_substs(all_substs)
};

// If this is an `&mut self` method, bias the receiver
// expression towards mutability (this will switch
// e.g. `Deref` to `DerefMut` in overloaded derefs and so on).
Expand Down Expand Up @@ -422,11 +423,11 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
}

fn add_obligations(&mut self,
pick: &probe::Pick<'tcx>,
fty: Ty<'tcx>,
all_substs: &subst::Substs<'tcx>,
method_predicates: &ty::InstantiatedPredicates<'tcx>) {
debug!("add_obligations: pick={:?} all_substs={:?} method_predicates={:?}",
pick,
debug!("add_obligations: fty={:?} all_substs={:?} method_predicates={:?}",
fty,
all_substs,
method_predicates);

Expand All @@ -439,6 +440,11 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
self.fcx.add_wf_bounds(
all_substs,
self.call_expr);

// the function type must also be well-formed (this is not
// implied by the substs being well-formed because of inherent
// impls and late-bound regions - see issue #28609).
self.fcx.register_wf_obligation(fty, self.span, traits::MiscObligation);
}

///////////////////////////////////////////////////////////////////////////
Expand Down
3 changes: 3 additions & 0 deletions src/librustc_typeck/check/method/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,9 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
traits::ObligationCause::misc(span, fcx.body_id),
&method_bounds);

// Also register an obligation for the method type being well-formed.
fcx.register_wf_obligation(fty, span, traits::MiscObligation);

// FIXME(#18653) -- Try to resolve obligations, giving us more
// typing information, which can sometimes be needed to avoid
// pathological region inference failures.
Expand Down
3 changes: 2 additions & 1 deletion src/libstd/thread/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,8 @@ impl Builder {
let my_thread = Thread::new(name);
let their_thread = my_thread.clone();

let my_packet = Arc::new(UnsafeCell::new(None));
let my_packet : Arc<UnsafeCell<Option<Result<T>>>>
= Arc::new(UnsafeCell::new(None));
let their_packet = my_packet.clone();

let main = move || {
Expand Down
1 change: 1 addition & 0 deletions src/test/compile-fail/issue-18959.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ fn foo(b: &Bar) {
b.foo(&0)
//~^ ERROR the trait `Foo` is not implemented for the type `Bar`
//~| ERROR E0038
//~| WARNING E0038
}

fn main() {
Expand Down
1 change: 1 addition & 0 deletions src/test/compile-fail/object-safety-issue-22040.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ struct SExpr<'x> {
impl<'x> PartialEq for SExpr<'x> {
fn eq(&self, other:&SExpr<'x>) -> bool {
println!("L1: {} L2: {}", self.elements.len(), other.elements.len());

let result = self.elements.len() == other.elements.len();

println!("Got compare {}", result);
Expand Down
1 change: 1 addition & 0 deletions src/test/compile-fail/trait-test-2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ fn main() {
//~^ ERROR E0038
//~| ERROR E0038
//~| ERROR E0277
//~| WARNING E0038
}
33 changes: 33 additions & 0 deletions src/test/compile-fail/wf-method-late-bound-regions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// 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.

// A method's receiver must be well-formed, even if it has late-bound regions.
// Because of this, a method's substs being well-formed does not imply that
// the method's implied bounds are met.

struct Foo<'b>(Option<&'b ()>);

trait Bar<'b> {
fn xmute<'a>(&'a self, u: &'b u32) -> &'a u32;
}

impl<'b> Bar<'b> for Foo<'b> {
fn xmute<'a>(&'a self, u: &'b u32) -> &'a u32 { u }
}

fn main() {
let f = Foo(None);
let f2 = f;
let dangling = {
let pointer = Box::new(42);
f2.xmute(&pointer) //~ ERROR `pointer` does not live long enough
};
println!("{}", dangling);
}
84 changes: 84 additions & 0 deletions src/test/compile-fail/wf-misc-methods-issue-28609.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// 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.

// check that misc. method calls are well-formed

use std::marker::PhantomData;
use std::ops::{Deref, Shl};

#[derive(Copy, Clone)]
struct S<'a, 'b: 'a> {
marker: PhantomData<&'a &'b ()>,
bomb: Option<&'b u32>
}

type S2<'a> = S<'a, 'a>;

impl<'a, 'b> S<'a, 'b> {
fn transmute_inherent(&self, a: &'b u32) -> &'a u32 {
a
}
}

fn return_dangling_pointer_inherent(s: S2) -> &u32 {
let s = s;
s.transmute_inherent(&mut 42) //~ ERROR does not live long enough
}

impl<'a, 'b> Deref for S<'a, 'b> {
type Target = &'a u32;
fn deref(&self) -> &&'a u32 {
self.bomb.as_ref().unwrap()
}
}

fn return_dangling_pointer_coerce(s: S2) -> &u32 {
let four = 4;
let mut s = s;
s.bomb = Some(&four); //~ ERROR does not live long enough
&s
}

fn return_dangling_pointer_unary_op(s: S2) -> &u32 {
let four = 4;
let mut s = s;
s.bomb = Some(&four); //~ ERROR does not live long enough
&*s
}

impl<'a, 'b> Shl<&'b u32> for S<'a, 'b> {
type Output = &'a u32;
fn shl(self, t: &'b u32) -> &'a u32 { t }
}

fn return_dangling_pointer_binary_op(s: S2) -> &u32 {
let s = s;
s << &mut 3 //~ ERROR does not live long enough
}

fn return_dangling_pointer_method(s: S2) -> &u32 {
let s = s;
s.shl(&mut 3) //~ ERROR does not live long enough
}

fn return_dangling_pointer_ufcs(s: S2) -> &u32 {
let s = s;
S2::shl(s, &mut 3) //~ ERROR does not live long enough
}

fn main() {
let s = S { marker: PhantomData, bomb: None };
let _inherent_dp = return_dangling_pointer_inherent(s);
let _coerce_dp = return_dangling_pointer_coerce(s);
let _unary_dp = return_dangling_pointer_unary_op(s);
let _binary_dp = return_dangling_pointer_binary_op(s);
let _method_dp = return_dangling_pointer_method(s);
let _ufcs_dp = return_dangling_pointer_ufcs(s);
}
64 changes: 64 additions & 0 deletions src/test/compile-fail/wf-static-method.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// 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.

// check that static methods don't get to assume their trait-ref
// is well-formed.
// FIXME(#27579): this is just a bug. However, our checking with
// static inherent methods isn't quite working - need to
// fix that before removing the check.

trait Foo<'a, 'b, T>: Sized {
fn make_me() -> Self { loop {} }
fn static_evil(u: &'b u32) -> &'a u32;
}

struct Evil<'a, 'b: 'a>(Option<&'a &'b ()>);

impl<'a, 'b> Foo<'a, 'b, Evil<'a, 'b>> for () {
fn make_me() -> Self { }
fn static_evil(u: &'b u32) -> &'a u32 {
u //~ ERROR cannot infer an appropriate lifetime
}
}

struct IndirectEvil<'a, 'b: 'a>(Option<&'a &'b ()>);

impl<'a, 'b> Foo<'a, 'b, ()> for IndirectEvil<'a, 'b> {
fn make_me() -> Self { IndirectEvil(None) }
fn static_evil(u: &'b u32) -> &'a u32 {
let me = Self::make_me(); //~ ERROR lifetime bound not satisfied
loop {} // (`me` could be used for the lifetime transmute).
}
}

impl<'a, 'b> Evil<'a, 'b> {
fn inherent_evil(u: &'b u32) -> &'a u32 {
u //~ ERROR cannot infer an appropriate lifetime
}
}

// while static methods don't get to *assume* this, we still
// *check* that they hold.

fn evil<'a, 'b>(b: &'b u32) -> &'a u32 {
<()>::static_evil(b) //~ ERROR cannot infer an appropriate lifetime
}

fn indirect_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
<IndirectEvil>::static_evil(b)
//~^ ERROR cannot infer an appropriate lifetime
}

fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
<Evil>::inherent_evil(b) // bug? shouldn't this be an error
}


fn main() {}