Skip to content

Treat builtin bounds like all other kinds of trait matches. #18749

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

Merged
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
20 changes: 17 additions & 3 deletions src/librustc/middle/traits/fulfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
use middle::mem_categorization::Typer;
use middle::ty;
use middle::typeck::infer::InferCtxt;
use std::collections::HashSet;
use std::rc::Rc;
use util::ppaux::Repr;

use super::CodeAmbiguity;
Expand All @@ -30,6 +32,13 @@ use super::select::SelectionContext;
/// method `select_all_or_error` can be used to report any remaining
/// ambiguous cases as errors.
pub struct FulfillmentContext<'tcx> {
// a simple cache that aims to cache *exact duplicate obligations*
// and avoid adding them twice. This serves a different purpose
// than the `SelectionCache`: it avoids duplicate errors and
// permits recursive obligations, which are often generated from
// traits like `Send` et al.
duplicate_set: HashSet<Rc<ty::TraitRef<'tcx>>>,

// A list of all obligations that have been registered with this
// fulfillment context.
trait_obligations: Vec<Obligation<'tcx>>,
Expand All @@ -43,6 +52,7 @@ pub struct FulfillmentContext<'tcx> {
impl<'tcx> FulfillmentContext<'tcx> {
pub fn new() -> FulfillmentContext<'tcx> {
FulfillmentContext {
duplicate_set: HashSet::new(),
trait_obligations: Vec::new(),
attempted_mark: 0,
}
Expand All @@ -52,9 +62,13 @@ impl<'tcx> FulfillmentContext<'tcx> {
tcx: &ty::ctxt<'tcx>,
obligation: Obligation<'tcx>)
{
debug!("register_obligation({})", obligation.repr(tcx));
assert!(!obligation.trait_ref.has_escaping_regions());
self.trait_obligations.push(obligation);
if self.duplicate_set.insert(obligation.trait_ref.clone()) {
debug!("register_obligation({})", obligation.repr(tcx));
assert!(!obligation.trait_ref.has_escaping_regions());
self.trait_obligations.push(obligation);
} else {
debug!("register_obligation({}) -- already seen, skip", obligation.repr(tcx));
}
}

pub fn select_all_or_error<'a>(&mut self,
Expand Down
34 changes: 12 additions & 22 deletions src/librustc/middle/traits/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ pub enum MethodMatchedData {
/// candidate is one that might match or might not, depending on how
/// type variables wind up being resolved. This only occurs during inference.
///
/// For selection to suceed, there must be exactly one non-ambiguous
/// For selection to succeed, there must be exactly one non-ambiguous
/// candidate. Usually, it is not possible to have more than one
/// definitive candidate, due to the coherence rules. However, there is
/// one case where it could occur: if there is a blanket impl for a
Expand Down Expand Up @@ -1149,24 +1149,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
candidates: &mut CandidateSet<'tcx>)
-> Result<(),SelectionError<'tcx>>
{
// FIXME -- To be more like a normal impl, we should just
// ignore the nested cases here, and instead generate nested
// obligations in `confirm_candidate`. However, this doesn't
// work because we require handling the recursive cases to
// avoid infinite cycles (that is, with recursive types,
// sometimes `Foo : Copy` only holds if `Foo : Copy`).

match self.builtin_bound(bound, stack.obligation.self_ty()) {
Ok(If(nested)) => {
debug!("builtin_bound: bound={} nested={}",
bound.repr(self.tcx()),
nested.repr(self.tcx()));
let data = self.vtable_builtin_data(stack.obligation, bound, nested);
match self.winnow_selection(Some(stack), VtableBuiltin(data)) {
EvaluatedToOk => { Ok(candidates.vec.push(BuiltinCandidate(bound))) }
EvaluatedToAmbig => { Ok(candidates.ambiguous = true) }
EvaluatedToErr => { Err(Unimplemented) }
}
Ok(If(_)) => {
debug!("builtin_bound: bound={}",
bound.repr(self.tcx()));
candidates.vec.push(BuiltinCandidate(bound));
Ok(())
}
Ok(ParameterBuiltin) => { Ok(()) }
Ok(AmbiguousBuiltin) => { Ok(candidates.ambiguous = true) }
Expand Down Expand Up @@ -1539,8 +1527,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
candidate.repr(self.tcx()));

match candidate {
// FIXME -- see assemble_builtin_bound_candidates()
BuiltinCandidate(_) |
BuiltinCandidate(builtin_bound) => {
Ok(VtableBuiltin(
try!(self.confirm_builtin_candidate(obligation, builtin_bound))))
}

ErrorCandidate => {
Ok(VtableBuiltin(VtableBuiltinData { nested: VecPerParamSpace::empty() }))
}
Expand Down Expand Up @@ -1590,8 +1581,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {

match try!(self.builtin_bound(bound, obligation.self_ty())) {
If(nested) => Ok(self.vtable_builtin_data(obligation, bound, nested)),
AmbiguousBuiltin |
ParameterBuiltin => {
AmbiguousBuiltin | ParameterBuiltin => {
self.tcx().sess.span_bug(
obligation.cause.span,
format!("builtin bound for {} was ambig",
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_trans/trans/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -965,7 +965,7 @@ pub fn trans_external_path<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,

pub fn invoke<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
llfn: ValueRef,
llargs: Vec<ValueRef> ,
llargs: &[ValueRef],
fn_ty: Ty<'tcx>,
call_info: Option<NodeInfo>,
// FIXME(15064) is_lang_item is a horrible hack, please remove it
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_trans/trans/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -808,7 +808,7 @@ pub fn trans_call_inner<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
// Invoke the actual rust fn and update bcx/llresult.
let (llret, b) = base::invoke(bcx,
llfn,
llargs,
llargs[],
callee_ty,
call_info,
dest.is_none());
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_trans/trans/glue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
let dtor_ty = ty::mk_ctor_fn(bcx.tcx(),
&[get_drop_glue_type(bcx.ccx(), t)],
ty::mk_nil(bcx.tcx()));
let (_, variant_cx) = invoke(variant_cx, dtor_addr, args, dtor_ty, None, false);
let (_, variant_cx) = invoke(variant_cx, dtor_addr, args[], dtor_ty, None, false);

variant_cx.fcx.pop_and_trans_custom_cleanup_scope(variant_cx, field_scope);
variant_cx
Expand Down
15 changes: 15 additions & 0 deletions src/test/compile-fail/comm-not-freeze-receiver.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright 2013 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.

fn test<T: Sync>() {}

fn main() {
test::<Receiver<int>>(); //~ ERROR: `core::kinds::Sync` is not implemented
}
4 changes: 1 addition & 3 deletions src/test/compile-fail/comm-not-freeze.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,5 @@
fn test<T: Sync>() {}

fn main() {
test::<Sender<int>>(); //~ ERROR: `core::kinds::Sync` is not implemented
test::<Receiver<int>>(); //~ ERROR: `core::kinds::Sync` is not implemented
test::<Sender<int>>(); //~ ERROR: `core::kinds::Sync` is not implemented
test::<Sender<int>>(); //~ ERROR: `core::kinds::Sync` is not implemented
}
10 changes: 8 additions & 2 deletions src/test/compile-fail/dst-object-from-unsized-type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,24 @@
trait Foo for Sized? {}
impl Foo for str {}

fn test<Sized? T: Foo>(t: &T) {
fn test1<Sized? T: Foo>(t: &T) {
let u: &Foo = t;
//~^ ERROR `core::kinds::Sized` is not implemented for the type `T`
}

fn test2<Sized? T: Foo>(t: &T) {
let v: &Foo = t as &Foo;
//~^ ERROR `core::kinds::Sized` is not implemented for the type `T`
}

fn main() {
fn test3() {
let _: &[&Foo] = &["hi"];
//~^ ERROR `core::kinds::Sized` is not implemented for the type `str`
}

fn test4() {
let _: &Foo = "hi" as &Foo;
//~^ ERROR `core::kinds::Sized` is not implemented for the type `str`
}

fn main() { }
1 change: 0 additions & 1 deletion src/test/compile-fail/issue-5883.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ fn new_struct(r: A+'static)
-> Struct { //~^ ERROR the trait `core::kinds::Sized` is not implemented
//~^ ERROR the trait `core::kinds::Sized` is not implemented
Struct { r: r }
//~^ ERROR the trait `core::kinds::Sized` is not implemented
}

trait Curve {}
Expand Down
2 changes: 1 addition & 1 deletion src/test/compile-fail/issue-7013.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,5 @@ struct A {

fn main() {
let a = A {v: box B{v: None} as Box<Foo+Send>};
//~^ ERROR the trait `core::kinds::Send` is not implemented for the type `B`
//~^ ERROR the trait `core::kinds::Send` is not implemented
}
4 changes: 2 additions & 2 deletions src/test/compile-fail/issue-8727.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// error-pattern:reached the recursion limit during monomorphization

// Verify the compiler fails with an error on infinite function
// recursions.


struct Data(Box<Option<Data>>);

fn generic<T>( _ : Vec<(Data,T)> ) {
//~^ ERROR reached the recursion limit during monomorphization
let rec : Vec<(Data,(bool,T))> = Vec::new();
generic( rec );
}
Expand Down
2 changes: 1 addition & 1 deletion src/test/compile-fail/kindck-copy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ struct MyStruct {
}

struct MyNoncopyStruct {
x: Box<int>,
x: Box<char>,
}

fn test<'a,T,U:Copy>(_: &'a int) {
Expand Down
2 changes: 1 addition & 1 deletion src/test/compile-fail/kindck-destructor-owned.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ struct Foo {
}

impl Drop for Foo {
//~^ ERROR the trait `core::kinds::Send` is not implemented for the type `Foo`
//~^ ERROR the trait `core::kinds::Send` is not implemented
//~^^ NOTE cannot implement a destructor on a structure or enumeration that does not satisfy Send
fn drop(&mut self) {
}
Expand Down
10 changes: 10 additions & 0 deletions src/test/compile-fail/kindck-impl-type-params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ fn f<T>(val: T) {
let a = &t as &Gettable<T>;
//~^ ERROR the trait `core::kinds::Send` is not implemented
//~^^ ERROR the trait `core::kinds::Copy` is not implemented
}

fn g<T>(val: T) {
let t: S<T> = S;
let a: &Gettable<T> = &t;
//~^ ERROR the trait `core::kinds::Send` is not implemented
//~^^ ERROR the trait `core::kinds::Copy` is not implemented
Expand All @@ -30,9 +34,15 @@ fn f<T>(val: T) {
fn foo<'a>() {
let t: S<&'a int> = S;
let a = &t as &Gettable<&'a int>;
}

fn foo2<'a>() {
let t: Box<S<String>> = box S;
let a = t as Box<Gettable<String>>;
//~^ ERROR the trait `core::kinds::Copy` is not implemented
}

fn foo3<'a>() {
let t: Box<S<String>> = box S;
let a: Box<Gettable<String>> = t;
//~^ ERROR the trait `core::kinds::Copy` is not implemented
Expand Down
10 changes: 7 additions & 3 deletions src/test/compile-fail/kindck-nonsendable-1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,14 @@ use std::rc::Rc;

fn foo(_x: Rc<uint>) {}

fn main() {
fn bar() {
let x = Rc::new(3u);
let _: proc():Send = proc() foo(x); //~ ERROR `core::kinds::Send` is not implemented
let _: proc():Send = proc() foo(x); //~ ERROR `core::kinds::Send` is not implemented
let _: proc():Send = proc() foo(x); //~ ERROR `core::kinds::Send` is not implemented
}

fn bar2() {
let x = Rc::new(3u);
let _: proc() = proc() foo(x);
}

fn main() { }
2 changes: 1 addition & 1 deletion src/test/compile-fail/unsendable-class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,5 @@ fn foo(i:int, j: Rc<String>) -> foo {
fn main() {
let cat = "kitty".to_string();
let (tx, _) = channel(); //~ ERROR `core::kinds::Send` is not implemented
tx.send(foo(42, Rc::new(cat))); //~ ERROR `core::kinds::Send` is not implemented
tx.send(foo(42, Rc::new(cat)));
}
20 changes: 14 additions & 6 deletions src/test/compile-fail/unsized-enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,22 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

enum Foo<T> { FooSome(T), FooNone }

fn bar<T: Sized>() { }
fn foo<Sized? T>() { bar::<Foo<T>>() }
fn is_sized<T:Sized>() { }
fn not_sized<Sized? T>() { }

enum Foo<U> { FooSome(U), FooNone }
fn foo1<T>() { not_sized::<Foo<T>>() } // Hunky dory.
fn foo2<Sized? T>() { not_sized::<Foo<T>>() }
//~^ ERROR the trait `core::kinds::Sized` is not implemented
//
// Not OK: `T` is not sized.

enum Bar<Sized? U> { BarSome(U), BarNone }
fn bar1<Sized? T>() { not_sized::<Bar<T>>() }
fn bar2<Sized? T>() { is_sized::<Bar<T>>() }
//~^ ERROR the trait `core::kinds::Sized` is not implemented
//~^^ ERROR the trait `core::kinds::Sized` is not implemented
//
// One error is for T being provided to Foo<T>, the other is
// for Foo<T> being provided to bar.
// Not OK: `Bar<T>` is not sized, but it should be.

fn main() { }
19 changes: 14 additions & 5 deletions src/test/compile-fail/unsized-struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,22 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.


fn is_sized<T:Sized>() { }
fn not_sized<Sized? T>() { }

struct Foo<T> { data: T }
fn foo1<T>() { not_sized::<Foo<T>>() } // Hunky dory.
fn foo2<Sized? T>() { not_sized::<Foo<T>>() }
//~^ ERROR the trait `core::kinds::Sized` is not implemented
//
// Not OK: `T` is not sized.

fn bar<T: Sized>() { }
fn foo<Sized? T>() { bar::<Foo<T>>() }
struct Bar<Sized? T> { data: T }
fn bar1<Sized? T>() { not_sized::<Bar<T>>() }
fn bar2<Sized? T>() { is_sized::<Bar<T>>() }
//~^ ERROR the trait `core::kinds::Sized` is not implemented
//~^^ ERROR the trait `core::kinds::Sized` is not implemented
// One error is for the T in Foo<T>, the other is for Foo<T> as a value
// for bar's type parameter.
//
// Not OK: `Bar<T>` is not sized, but it should be.

fn main() { }
3 changes: 3 additions & 0 deletions src/test/compile-fail/unsized3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ fn f8<Sized? X>(x1: &S<X>, x2: &S<X>) {
fn f9<Sized? X>(x1: Box<S<X>>, x2: Box<E<X>>) {
f5(&(*x1, 34i));
//~^ ERROR the trait `core::kinds::Sized` is not implemented
}

fn f10<Sized? X>(x1: Box<S<X>>, x2: Box<E<X>>) {
f5(&(32i, *x2));
//~^ ERROR the trait `core::kinds::Sized` is not implemented
}
Expand Down
2 changes: 2 additions & 0 deletions src/test/compile-fail/unsized5.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ struct S4 {
}
enum E<Sized? X> {
V1(X, int), //~ERROR `core::kinds::Sized` is not implemented
}
enum F<Sized? X> {
V2{f1: X, f: int}, //~ERROR `core::kinds::Sized` is not implemented
}

Expand Down