From b88f86782ecd9319e0e2c875bbf1efecd66ebf41 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 12 Sep 2014 10:45:39 -0400 Subject: [PATCH 01/10] Update error messages in compile-fail tests --- .../compile-fail/bad-method-typaram-kind.rs | 2 +- src/test/compile-fail/bad-sized.rs | 8 ++-- .../builtin-superkinds-double-superkind.rs | 4 +- .../builtin-superkinds-in-metadata.rs | 3 +- .../builtin-superkinds-self-type.rs | 6 +-- .../compile-fail/builtin-superkinds-simple.rs | 2 +- .../builtin-superkinds-typaram-not-send.rs | 2 +- src/test/compile-fail/comm-not-freeze.rs | 6 +-- .../conflicting-implementations-aux.rs | 5 +-- .../conflicting-implementations.rs | 5 +-- .../deriving-span-Default-struct.rs | 2 +- .../compile-fail/deriving-span-Zero-struct.rs | 6 +-- .../deriving-span-Zero-tuple-struct.rs | 6 +-- src/test/compile-fail/drop-on-non-struct.rs | 9 ++-- src/test/compile-fail/dst-bad-assign-2.rs | 4 +- src/test/compile-fail/dst-bad-assign.rs | 1 + src/test/compile-fail/dst-bad-coerce1.rs | 2 +- src/test/compile-fail/dst-bad-coerce2.rs | 4 +- src/test/compile-fail/dst-bad-coercions.rs | 7 ++- src/test/compile-fail/dst-bad-deep.rs | 3 +- .../compile-fail/dst-sized-trait-param.rs | 23 ++++++++++ .../error-should-say-copy-not-pod.rs | 2 +- src/test/compile-fail/ifmt-unimpl.rs | 2 +- src/test/compile-fail/impl-bounds-checking.rs | 2 +- src/test/compile-fail/issue-14915.rs | 4 +- src/test/compile-fail/issue-3907-2.rs | 2 +- src/test/compile-fail/issue-5035-2.rs | 2 +- src/test/compile-fail/issue-5883.rs | 7 ++- src/test/compile-fail/issue-6458-2.rs | 3 +- src/test/compile-fail/issue-7013.rs | 7 +-- src/test/compile-fail/kindck-copy.rs | 26 +++++------ .../compile-fail/kindck-impl-type-params-2.rs | 2 +- .../compile-fail/kindck-impl-type-params.rs | 18 ++++---- .../kindck-inherited-copy-bound.rs | 4 +- src/test/compile-fail/kindck-proc-bounds.rs | 4 +- src/test/compile-fail/kindck-send-object.rs | 9 ++-- src/test/compile-fail/kindck-send-object1.rs | 3 ++ src/test/compile-fail/kindck-send-object2.rs | 4 +- .../kindck-send-unsafe.rs~rust-lang_master | 22 +++++++++ src/test/compile-fail/map-types.rs | 3 +- src/test/compile-fail/marker-no-copy.rs | 2 +- src/test/compile-fail/marker-no-send.rs | 2 +- src/test/compile-fail/marker-no-share.rs | 2 +- src/test/compile-fail/mut-not-freeze.rs | 2 +- .../compile-fail/mutable-enum-indirect.rs | 2 +- src/test/compile-fail/no-send-res-ports.rs | 3 +- src/test/compile-fail/no_send-enum.rs | 3 +- src/test/compile-fail/no_send-rc.rs | 3 +- src/test/compile-fail/no_send-struct.rs | 3 +- src/test/compile-fail/no_share-enum.rs | 3 +- src/test/compile-fail/no_share-rc.rs | 3 +- src/test/compile-fail/no_share-struct.rs | 3 +- .../object-does-not-impl-trait.rs | 4 +- src/test/compile-fail/pinned-deep-copy.rs | 3 +- .../regions-bound-missing-bound-in-impl.rs | 2 - .../compile-fail/regions-bounded-by-send.rs | 3 ++ .../regions-bounded-method-type-parameters.rs | 2 - .../regions-escape-via-trait-or-not.rs | 2 - .../regions-lifetime-bounds-on-fns.rs | 2 - .../compile-fail/repeat-to-run-dtor-twice.rs | 3 +- .../compile-fail/task-rng-isnt-sendable.rs | 2 +- .../trait-bounds-not-on-bare-trait.rs | 2 +- ...rait-bounds-on-structs-and-enums-locals.rs | 7 ++- ...rait-bounds-on-structs-and-enums-static.rs | 3 +- .../trait-bounds-on-structs-and-enums-xc.rs | 15 +------ .../trait-bounds-on-structs-and-enums-xc1.rs | 26 +++++++++++ .../trait-bounds-on-structs-and-enums.rs | 31 +++++-------- .../trait-coercion-generic-bad.rs | 3 +- .../type-params-in-different-spaces-2.rs | 4 +- .../typeck-unsafe-always-share.rs | 2 +- .../unboxed-closures-vtable-mismatch.rs | 3 +- .../unboxed-closures-wrong-trait.rs | 2 +- src/test/compile-fail/unique-pinned-nocopy.rs | 3 +- src/test/compile-fail/unique-unique-kind.rs | 2 +- src/test/compile-fail/unique-vec-res.rs | 6 +-- src/test/compile-fail/unsendable-class.rs | 4 +- src/test/compile-fail/unsized-bare-typaram.rs | 3 +- src/test/compile-fail/unsized-enum.rs | 11 ++++- src/test/compile-fail/unsized-struct.rs | 7 ++- src/test/compile-fail/unsized3.rs | 45 ++++++------------- src/test/compile-fail/unsized6.rs | 32 ++++++------- src/test/compile-fail/unsized7.rs | 43 ++++++++++++++++++ src/test/compile-fail/vec-res-add.rs | 4 +- .../compile-fail/vtable-res-trait-param.rs | 3 +- .../compile-fail/where-clauses-unsatisfied.rs | 5 +-- src/test/run-pass/drop-struct-as-object.rs | 42 +++++++++++++++++ .../run-pass/object-one-type-two-traits.rs | 39 ++++++++++++++++ 87 files changed, 381 insertions(+), 256 deletions(-) create mode 100644 src/test/compile-fail/dst-sized-trait-param.rs create mode 100644 src/test/compile-fail/kindck-send-unsafe.rs~rust-lang_master create mode 100644 src/test/compile-fail/trait-bounds-on-structs-and-enums-xc1.rs create mode 100644 src/test/compile-fail/unsized7.rs create mode 100644 src/test/run-pass/drop-struct-as-object.rs create mode 100644 src/test/run-pass/object-one-type-two-traits.rs diff --git a/src/test/compile-fail/bad-method-typaram-kind.rs b/src/test/compile-fail/bad-method-typaram-kind.rs index b63ecc6b66f26..cf07dc02b9609 100644 --- a/src/test/compile-fail/bad-method-typaram-kind.rs +++ b/src/test/compile-fail/bad-method-typaram-kind.rs @@ -9,7 +9,7 @@ // except according to those terms. fn foo() { - 1u.bar::(); //~ ERROR: does not fulfill `Send` + 1u.bar::(); //~ ERROR `core::kinds::Send` is not implemented } trait bar { diff --git a/src/test/compile-fail/bad-sized.rs b/src/test/compile-fail/bad-sized.rs index fb9a060cb602a..4e0ad8088bee4 100644 --- a/src/test/compile-fail/bad-sized.rs +++ b/src/test/compile-fail/bad-sized.rs @@ -16,10 +16,8 @@ trait Trait {} pub fn main() { let x: Vec = Vec::new(); - //~^ ERROR instantiating a type parameter with an incompatible type `Trait+Sized`, which does not fulfill `Sized` - //~^^ ERROR instantiating a type parameter with an incompatible type `Trait+Sized`, which does not fulfill `Sized` - //~^^^ ERROR instantiating a type parameter with an incompatible type `Trait+Sized`, which does not fulfill `Sized` + //~^ ERROR the trait `core::kinds::Sized` is not implemented + //~^^ ERROR the trait `core::kinds::Sized` is not implemented let x: Vec>> = Vec::new(); - //~^ ERROR instantiating a type parameter with an incompatible type `Trait+Sized`, which does not fulfill `Sized` - //~^^ ERROR instantiating a type parameter with an incompatible type `Trait+Sized`, which does not fulfill `Sized` + //~^ ERROR the trait `core::kinds::Sized` is not implemented } diff --git a/src/test/compile-fail/builtin-superkinds-double-superkind.rs b/src/test/compile-fail/builtin-superkinds-double-superkind.rs index d5a648e3e2001..f3b9c395e4514 100644 --- a/src/test/compile-fail/builtin-superkinds-double-superkind.rs +++ b/src/test/compile-fail/builtin-superkinds-double-superkind.rs @@ -13,9 +13,9 @@ trait Foo : Send+Sync { } -impl Foo for (T,) { } //~ ERROR cannot implement this trait +impl Foo for (T,) { } //~ ERROR the trait `core::kinds::Send` is not implemented -impl Foo for (T,T) { } //~ ERROR cannot implement this trait +impl Foo for (T,T) { } //~ ERROR the trait `core::kinds::Sync` is not implemented impl Foo for (T,T,T) { } // (ok) diff --git a/src/test/compile-fail/builtin-superkinds-in-metadata.rs b/src/test/compile-fail/builtin-superkinds-in-metadata.rs index 889d82383e74e..76835c9955f6e 100644 --- a/src/test/compile-fail/builtin-superkinds-in-metadata.rs +++ b/src/test/compile-fail/builtin-superkinds-in-metadata.rs @@ -21,6 +21,7 @@ struct X(T); impl RequiresShare for X { } -impl RequiresRequiresShareAndSend for X { } //~ ERROR cannot implement this trait +impl RequiresRequiresShareAndSend for X { } +//~^ ERROR the trait `core::kinds::Send` is not implemented fn main() { } diff --git a/src/test/compile-fail/builtin-superkinds-self-type.rs b/src/test/compile-fail/builtin-superkinds-self-type.rs index 726413981a5f1..86d3d7e9cbc6c 100644 --- a/src/test/compile-fail/builtin-superkinds-self-type.rs +++ b/src/test/compile-fail/builtin-superkinds-self-type.rs @@ -12,12 +12,12 @@ // to use capabilities granted by builtin kinds as supertraits. trait Foo : Sync+'static { - fn foo(self, mut chan: Sender) { - chan.send(self); //~ ERROR does not fulfill `Send` - } + fn foo(self, mut chan: Sender) { } } impl Foo for T { } +//~^ ERROR the parameter type `T` may not live long enough +//~^^ ERROR the parameter type `T` may not live long enough fn main() { let (tx, rx) = channel(); diff --git a/src/test/compile-fail/builtin-superkinds-simple.rs b/src/test/compile-fail/builtin-superkinds-simple.rs index caf968612922b..fda83c03a7dce 100644 --- a/src/test/compile-fail/builtin-superkinds-simple.rs +++ b/src/test/compile-fail/builtin-superkinds-simple.rs @@ -14,6 +14,6 @@ trait Foo : Send { } impl <'a> Foo for &'a mut () { } -//~^ ERROR which does not fulfill `Send`, cannot implement this trait +//~^ ERROR does not fulfill the required lifetime fn main() { } diff --git a/src/test/compile-fail/builtin-superkinds-typaram-not-send.rs b/src/test/compile-fail/builtin-superkinds-typaram-not-send.rs index 166ca10ee1875..e77177f7f6d29 100644 --- a/src/test/compile-fail/builtin-superkinds-typaram-not-send.rs +++ b/src/test/compile-fail/builtin-superkinds-typaram-not-send.rs @@ -12,6 +12,6 @@ trait Foo : Send { } -impl Foo for T { } //~ ERROR cannot implement this trait +impl Foo for T { } //~ ERROR the trait `core::kinds::Send` is not implemented fn main() { } diff --git a/src/test/compile-fail/comm-not-freeze.rs b/src/test/compile-fail/comm-not-freeze.rs index 5820818167cbd..b6277a3e2bd98 100644 --- a/src/test/compile-fail/comm-not-freeze.rs +++ b/src/test/compile-fail/comm-not-freeze.rs @@ -11,7 +11,7 @@ fn test() {} fn main() { - test::>(); //~ ERROR: does not fulfill `Sync` - test::>(); //~ ERROR: does not fulfill `Sync` - test::>(); //~ ERROR: does not fulfill `Sync` + test::>(); //~ ERROR: `core::kinds::Sync` is not implemented + test::>(); //~ ERROR: `core::kinds::Sync` is not implemented + test::>(); //~ ERROR: `core::kinds::Sync` is not implemented } diff --git a/src/test/compile-fail/conflicting-implementations-aux.rs b/src/test/compile-fail/conflicting-implementations-aux.rs index 6c7722bbd254d..c1aa6ccd9bde6 100644 --- a/src/test/compile-fail/conflicting-implementations-aux.rs +++ b/src/test/compile-fail/conflicting-implementations-aux.rs @@ -15,10 +15,7 @@ extern crate trait_impl_conflict; use trait_impl_conflict::Foo; -impl Foo for A { -//~^ ERROR conflicting implementations for trait `trait_impl_conflict::Foo` -//~^^ ERROR cannot provide an extension implementation where both trait and type -// are not defined in this crate +impl Foo for A { //~ ERROR E0117 } fn main() { diff --git a/src/test/compile-fail/conflicting-implementations.rs b/src/test/compile-fail/conflicting-implementations.rs index 598da145b9283..b5a04491111bf 100644 --- a/src/test/compile-fail/conflicting-implementations.rs +++ b/src/test/compile-fail/conflicting-implementations.rs @@ -8,15 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: conflicting implementations for trait `Foo` trait Foo { } -impl Foo for int { +impl Foo for int { //~ ERROR conflicting implementations } -impl Foo for A { +impl Foo for A { //~ NOTE conflicting implementation here } diff --git a/src/test/compile-fail/deriving-span-Default-struct.rs b/src/test/compile-fail/deriving-span-Default-struct.rs index 90d567bfd5da9..1da88f2e2577e 100644 --- a/src/test/compile-fail/deriving-span-Default-struct.rs +++ b/src/test/compile-fail/deriving-span-Default-struct.rs @@ -18,7 +18,7 @@ struct Error; #[deriving(Default)] struct Struct { - x: Error //~ ERROR + x: Error //~ ERROR `core::default::Default` is not implemented } fn main() {} diff --git a/src/test/compile-fail/deriving-span-Zero-struct.rs b/src/test/compile-fail/deriving-span-Zero-struct.rs index fec1b3ed492f6..fb7759c6032e8 100644 --- a/src/test/compile-fail/deriving-span-Zero-struct.rs +++ b/src/test/compile-fail/deriving-span-Zero-struct.rs @@ -16,11 +16,9 @@ extern crate rand; struct Error; -#[deriving(Zero)] //~ ERROR failed to find an implementation +#[deriving(Zero)] //~ ERROR not implemented struct Struct { - x: Error //~ ERROR failed to find an implementation - //~^ ERROR failed to find an implementation - //~^^ ERROR type `Error` does not implement any method in scope + x: Error } fn main() {} diff --git a/src/test/compile-fail/deriving-span-Zero-tuple-struct.rs b/src/test/compile-fail/deriving-span-Zero-tuple-struct.rs index 0661e5ee8b285..193e4b5c6b2d5 100644 --- a/src/test/compile-fail/deriving-span-Zero-tuple-struct.rs +++ b/src/test/compile-fail/deriving-span-Zero-tuple-struct.rs @@ -16,11 +16,9 @@ extern crate rand; struct Error; -#[deriving(Zero)] //~ ERROR failed to find an implementation +#[deriving(Zero)] //~ ERROR not implemented struct Struct( - Error //~ ERROR - //~^ ERROR failed to find an implementation - //~^^ ERROR type `Error` does not implement any method in scope + Error ); fn main() {} diff --git a/src/test/compile-fail/drop-on-non-struct.rs b/src/test/compile-fail/drop-on-non-struct.rs index af4c12c754b96..8304afa1141ee 100644 --- a/src/test/compile-fail/drop-on-non-struct.rs +++ b/src/test/compile-fail/drop-on-non-struct.rs @@ -8,12 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - - -type Foo = Vec; - -impl Drop for Foo { -//~^ ERROR cannot provide an extension implementation +impl Drop for int { + //~^ ERROR the Drop trait may only be implemented on structures + //~^^ ERROR cannot provide an extension implementation fn drop(&mut self) { println!("kaboom"); } diff --git a/src/test/compile-fail/dst-bad-assign-2.rs b/src/test/compile-fail/dst-bad-assign-2.rs index 76becdc855dcd..112a424427a86 100644 --- a/src/test/compile-fail/dst-bad-assign-2.rs +++ b/src/test/compile-fail/dst-bad-assign-2.rs @@ -42,6 +42,6 @@ pub fn main() { // Assignment. let f5: &mut Fat = &mut Fat { f1: 5, f2: "some str", ptr: Bar1 {f :42} }; let z: Box = box Bar1 {f: 36}; - f5.ptr = *z; //~ ERROR dynamically sized type on lhs of assignment - //~^ ERROR E0161 + f5.ptr = *z; + //~^ ERROR the trait `core::kinds::Sized` is not implemented } diff --git a/src/test/compile-fail/dst-bad-assign.rs b/src/test/compile-fail/dst-bad-assign.rs index 17149941a7e1a..f18f4a36640c9 100644 --- a/src/test/compile-fail/dst-bad-assign.rs +++ b/src/test/compile-fail/dst-bad-assign.rs @@ -43,4 +43,5 @@ pub fn main() { let f5: &mut Fat = &mut Fat { f1: 5, f2: "some str", ptr: Bar1 {f :42} }; let z: Box = box Bar1 {f: 36}; f5.ptr = Bar1 {f: 36}; //~ ERROR mismatched types: expected `ToBar`, found `Bar1` + //~^ ERROR the trait `core::kinds::Sized` is not implemented for the type `ToBar` } diff --git a/src/test/compile-fail/dst-bad-coerce1.rs b/src/test/compile-fail/dst-bad-coerce1.rs index a609740eaebf5..4247f91a4fc53 100644 --- a/src/test/compile-fail/dst-bad-coerce1.rs +++ b/src/test/compile-fail/dst-bad-coerce1.rs @@ -28,5 +28,5 @@ pub fn main() { let f1 = Fat { ptr: Foo }; let f2: &Fat = &f1; let f3: &Fat = f2; - //~^ ERROR failed to find an implementation of trait Bar for Foo + //~^ ERROR the trait `Bar` is not implemented for the type `Foo` } diff --git a/src/test/compile-fail/dst-bad-coerce2.rs b/src/test/compile-fail/dst-bad-coerce2.rs index 118e4ce7e0834..e1a754b633208 100644 --- a/src/test/compile-fail/dst-bad-coerce2.rs +++ b/src/test/compile-fail/dst-bad-coerce2.rs @@ -22,10 +22,10 @@ pub fn main() { // With a vec of ints. let f1 = Fat { ptr: [1, 2, 3] }; let f2: &Fat<[int, ..3]> = &f1; - let f3: &mut Fat<[int]> = f2; //~ ERROR cannot borrow immutable dereference + let f3: &mut Fat<[int]> = f2; //~ ERROR mismatched types // With a trait. let f1 = Fat { ptr: Foo }; let f2: &Fat = &f1; - let f3: &mut Fat = f2; //~ ERROR cannot borrow immutable dereference + let f3: &mut Fat = f2; //~ ERROR mismatched types } diff --git a/src/test/compile-fail/dst-bad-coercions.rs b/src/test/compile-fail/dst-bad-coercions.rs index cc5d3b520f95c..c3a814e3f44ff 100644 --- a/src/test/compile-fail/dst-bad-coercions.rs +++ b/src/test/compile-fail/dst-bad-coercions.rs @@ -30,10 +30,9 @@ pub fn main() { let y: &T = x; //~ ERROR mismatched types // Test that we cannot convert an immutable ptr to a mutable one using *-ptrs - let x: &mut T = &S; //~ ERROR types differ in mutability - let x: *mut T = &S; //~ ERROR types differ in mutability - let x: *mut S = &S; - //~^ ERROR mismatched types + let x: &mut T = &S; //~ ERROR mismatched types + let x: *mut T = &S; //~ ERROR mismatched types + let x: *mut S = &S; //~ ERROR mismatched types // The below four sets of tests test that we cannot implicitly deref a *-ptr // during a coercion. diff --git a/src/test/compile-fail/dst-bad-deep.rs b/src/test/compile-fail/dst-bad-deep.rs index e2e387e1a48f4..506322d41f531 100644 --- a/src/test/compile-fail/dst-bad-deep.rs +++ b/src/test/compile-fail/dst-bad-deep.rs @@ -21,6 +21,5 @@ pub fn main() { let f: Fat<[int, ..3]> = Fat { ptr: [5i, 6, 7] }; let g: &Fat<[int]> = &f; let h: &Fat> = &Fat { ptr: *g }; - //~^ ERROR trying to initialise a dynamically sized struct - //~^^ ERROR E0161 + //~^ ERROR the trait `core::kinds::Sized` is not implemented } diff --git a/src/test/compile-fail/dst-sized-trait-param.rs b/src/test/compile-fail/dst-sized-trait-param.rs new file mode 100644 index 0000000000000..750b475adb2bb --- /dev/null +++ b/src/test/compile-fail/dst-sized-trait-param.rs @@ -0,0 +1,23 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Check that when you implement a trait that has a sized type +// parameter, the corresponding value must be sized. Also that the +// self type must be sized if appropriate. + +trait Foo { fn take(self, x: &T) { } } // Note: T is sized + +impl Foo<[int]> for uint { } +//~^ ERROR the trait `core::kinds::Sized` is not implemented for the type `[int]` + +impl Foo for [uint] { } +//~^ ERROR the trait `core::kinds::Sized` is not implemented for the type `[uint]` + +pub fn main() { } diff --git a/src/test/compile-fail/error-should-say-copy-not-pod.rs b/src/test/compile-fail/error-should-say-copy-not-pod.rs index 9186dada780c0..3d25c7ee772f6 100644 --- a/src/test/compile-fail/error-should-say-copy-not-pod.rs +++ b/src/test/compile-fail/error-should-say-copy-not-pod.rs @@ -13,5 +13,5 @@ fn check_bound(_: T) {} fn main() { - check_bound("nocopy".to_string()); //~ ERROR does not fulfill `Copy` + check_bound("nocopy".to_string()); //~ ERROR the trait `core::kinds::Copy` is not implemented } diff --git a/src/test/compile-fail/ifmt-unimpl.rs b/src/test/compile-fail/ifmt-unimpl.rs index 897717971bc17..194047ce848f6 100644 --- a/src/test/compile-fail/ifmt-unimpl.rs +++ b/src/test/compile-fail/ifmt-unimpl.rs @@ -10,5 +10,5 @@ fn main() { format!("{:d}", "3"); - //~^ ERROR: failed to find an implementation of trait core::fmt::Signed + //~^ ERROR: the trait `core::fmt::Signed` is not implemented } diff --git a/src/test/compile-fail/impl-bounds-checking.rs b/src/test/compile-fail/impl-bounds-checking.rs index 00c415a860d4f..69a35bcbd7b11 100644 --- a/src/test/compile-fail/impl-bounds-checking.rs +++ b/src/test/compile-fail/impl-bounds-checking.rs @@ -17,7 +17,7 @@ trait Getter { fn get(&self) -> T; } -impl Getter for int { //~ ERROR failed to find an implementation of trait Clone2 for int +impl Getter for int { //~ ERROR the trait `Clone2` is not implemented fn get(&self) -> int { *self } } diff --git a/src/test/compile-fail/issue-14915.rs b/src/test/compile-fail/issue-14915.rs index 3754d669be6a2..75b9626a6596f 100644 --- a/src/test/compile-fail/issue-14915.rs +++ b/src/test/compile-fail/issue-14915.rs @@ -15,8 +15,8 @@ fn main() { let y: Gc = box (GC) 0; println!("{}", x + 1); //~ ERROR binary operation `+` cannot be applied to type `Box` - //~^ ERROR cannot determine a type for this bounded type parameter: unconstrained type + //~^ ERROR unable to infer enough type information println!("{}", y + 1); //~^ ERROR binary operation `+` cannot be applied to type `Gc` - //~^^ ERROR cannot determine a type for this bounded type parameter: unconstrained type + //~^^ ERROR unable to infer enough type information } diff --git a/src/test/compile-fail/issue-3907-2.rs b/src/test/compile-fail/issue-3907-2.rs index 71f91050256ed..981abf6cc23d8 100644 --- a/src/test/compile-fail/issue-3907-2.rs +++ b/src/test/compile-fail/issue-3907-2.rs @@ -17,6 +17,6 @@ struct S { name: int } -fn bar(_x: Foo) {} //~ ERROR variable `_x` has dynamically sized type +fn bar(_x: Foo) {} //~ ERROR the trait `core::kinds::Sized` is not implemented fn main() {} diff --git a/src/test/compile-fail/issue-5035-2.rs b/src/test/compile-fail/issue-5035-2.rs index 0251a06c5bd39..d0830ff8e4d76 100644 --- a/src/test/compile-fail/issue-5035-2.rs +++ b/src/test/compile-fail/issue-5035-2.rs @@ -11,6 +11,6 @@ trait I {} type K = I+'static; -fn foo(_x: K) {} //~ ERROR: variable `_x` has dynamically sized type +fn foo(_x: K) {} //~ ERROR: the trait `core::kinds::Sized` is not implemented fn main() {} diff --git a/src/test/compile-fail/issue-5883.rs b/src/test/compile-fail/issue-5883.rs index 7ea282c599f51..71b1bcd69da33 100644 --- a/src/test/compile-fail/issue-5883.rs +++ b/src/test/compile-fail/issue-5883.rs @@ -15,10 +15,9 @@ struct Struct { } fn new_struct(r: A+'static) -> Struct { - //~^ ERROR variable `r` has dynamically sized type - Struct { r: r } //~ ERROR trying to initialise a dynamically sized struct - //~^ ERROR E0161 - //~^^ ERROR E0161 + //~^ ERROR the trait `core::kinds::Sized` is not implemented + Struct { r: r } + //~^ ERROR the trait `core::kinds::Sized` is not implemented } trait Curve {} diff --git a/src/test/compile-fail/issue-6458-2.rs b/src/test/compile-fail/issue-6458-2.rs index f302472d070bd..701bee85fd732 100644 --- a/src/test/compile-fail/issue-6458-2.rs +++ b/src/test/compile-fail/issue-6458-2.rs @@ -11,5 +11,6 @@ extern crate debug; fn main() { - format!("{:?}", None); //~ ERROR: cannot determine a type for this bounded + // Unconstrained type: + format!("{:?}", None); //~ ERROR: E0101 } diff --git a/src/test/compile-fail/issue-7013.rs b/src/test/compile-fail/issue-7013.rs index ef585998aa5a5..3d16ff0a3fac9 100644 --- a/src/test/compile-fail/issue-7013.rs +++ b/src/test/compile-fail/issue-7013.rs @@ -32,10 +32,5 @@ struct A { fn main() { let a = A {v: box B{v: None} as Box}; - //~^ ERROR cannot pack type `Box`, which does not fulfill `Send`, as a trait bounded by Send - let v = Rc::new(RefCell::new(a)); - let w = v.clone(); - let b = &*v; - let mut b = b.borrow_mut(); - b.v.set(w.clone()); + //~^ ERROR the trait `core::kinds::Send` is not implemented for the type `B` } diff --git a/src/test/compile-fail/kindck-copy.rs b/src/test/compile-fail/kindck-copy.rs index 2ca171ed99837..3524d11d1842a 100644 --- a/src/test/compile-fail/kindck-copy.rs +++ b/src/test/compile-fail/kindck-copy.rs @@ -34,14 +34,14 @@ fn test<'a,T,U:Copy>(_: &'a int) { assert_copy::<&'a [int]>(); // ...unless they are mutable - assert_copy::<&'static mut int>(); //~ ERROR does not fulfill - assert_copy::<&'a mut int>(); //~ ERROR does not fulfill + assert_copy::<&'static mut int>(); //~ ERROR `core::kinds::Copy` is not implemented + assert_copy::<&'a mut int>(); //~ ERROR `core::kinds::Copy` is not implemented // ~ pointers are not ok - assert_copy::>(); //~ ERROR does not fulfill - assert_copy::(); //~ ERROR does not fulfill - assert_copy:: >(); //~ ERROR does not fulfill - assert_copy::>(); //~ ERROR does not fulfill + assert_copy::>(); //~ ERROR `core::kinds::Copy` is not implemented + assert_copy::(); //~ ERROR `core::kinds::Copy` is not implemented + assert_copy:: >(); //~ ERROR `core::kinds::Copy` is not implemented + assert_copy::>(); //~ ERROR `core::kinds::Copy` is not implemented // borrowed object types are generally ok assert_copy::<&'a Dummy>(); @@ -49,14 +49,14 @@ fn test<'a,T,U:Copy>(_: &'a int) { assert_copy::<&'static Dummy+Copy>(); // owned object types are not ok - assert_copy::>(); //~ ERROR does not fulfill - assert_copy::>(); //~ ERROR does not fulfill + assert_copy::>(); //~ ERROR `core::kinds::Copy` is not implemented + assert_copy::>(); //~ ERROR `core::kinds::Copy` is not implemented // mutable object types are not ok - assert_copy::<&'a mut Dummy+Copy>(); //~ ERROR does not fulfill + assert_copy::<&'a mut Dummy+Copy>(); //~ ERROR `core::kinds::Copy` is not implemented // closures are like an `&mut` object - assert_copy::<||>(); //~ ERROR does not fulfill + assert_copy::<||>(); //~ ERROR `core::kinds::Copy` is not implemented // unsafe ptrs are ok assert_copy::<*const int>(); @@ -74,11 +74,11 @@ fn test<'a,T,U:Copy>(_: &'a int) { assert_copy::(); // structs containing non-POD are not ok - assert_copy::(); //~ ERROR does not fulfill + assert_copy::(); //~ ERROR `core::kinds::Copy` is not implemented // managed or ref counted types are not ok - assert_copy::>(); //~ ERROR does not fulfill - assert_copy::>(); //~ ERROR does not fulfill + assert_copy::>(); //~ ERROR `core::kinds::Copy` is not implemented + assert_copy::>(); //~ ERROR `core::kinds::Copy` is not implemented } pub fn main() { diff --git a/src/test/compile-fail/kindck-impl-type-params-2.rs b/src/test/compile-fail/kindck-impl-type-params-2.rs index a034e252d31dc..6b25289567b27 100644 --- a/src/test/compile-fail/kindck-impl-type-params-2.rs +++ b/src/test/compile-fail/kindck-impl-type-params-2.rs @@ -19,5 +19,5 @@ fn take_param(foo: &T) { } fn main() { let x = box 3i; take_param(&x); - //~^ ERROR instantiating a type parameter with an incompatible type + //~^ ERROR the trait `core::kinds::Copy` is not implemented } diff --git a/src/test/compile-fail/kindck-impl-type-params.rs b/src/test/compile-fail/kindck-impl-type-params.rs index 4cc03ee3dcd44..c92887965c0d2 100644 --- a/src/test/compile-fail/kindck-impl-type-params.rs +++ b/src/test/compile-fail/kindck-impl-type-params.rs @@ -20,20 +20,22 @@ impl Gettable for S {} fn f(val: T) { let t: S = S; let a = &t as &Gettable; - //~^ ERROR instantiating a type parameter with an incompatible type `T` + //~^ ERROR the trait `core::kinds::Send` is not implemented + //~^^ ERROR the trait `core::kinds::Copy` is not implemented let a: &Gettable = &t; - //~^ ERROR instantiating a type parameter with an incompatible type `T` + //~^ ERROR the trait `core::kinds::Send` is not implemented + //~^^ ERROR the trait `core::kinds::Copy` is not implemented } -fn main() { - let t: S<&int> = S; - let a = &t as &Gettable<&int>; - //~^ ERROR instantiating a type parameter with an incompatible type +fn foo<'a>() { + let t: S<&'a int> = S; + let a = &t as &Gettable<&'a int>; let t: Box> = box S; let a = t as Box>; - //~^ ERROR instantiating a type parameter with an incompatible type + //~^ ERROR the trait `core::kinds::Copy` is not implemented let t: Box> = box S; let a: Box> = t; - //~^ ERROR instantiating a type parameter with an incompatible type + //~^ ERROR the trait `core::kinds::Copy` is not implemented } +fn main() { } diff --git a/src/test/compile-fail/kindck-inherited-copy-bound.rs b/src/test/compile-fail/kindck-inherited-copy-bound.rs index 2520ed215d55e..51ee38d5cfed2 100644 --- a/src/test/compile-fail/kindck-inherited-copy-bound.rs +++ b/src/test/compile-fail/kindck-inherited-copy-bound.rs @@ -23,8 +23,8 @@ fn take_param(foo: &T) { } fn main() { let x = box 3i; - take_param(&x); //~ ERROR does not fulfill `Copy` + take_param(&x); //~ ERROR `core::kinds::Copy` is not implemented let y = &x; - let z = &x as &Foo; //~ ERROR does not fulfill `Copy` + let z = &x as &Foo; //~ ERROR `core::kinds::Copy` is not implemented } diff --git a/src/test/compile-fail/kindck-proc-bounds.rs b/src/test/compile-fail/kindck-proc-bounds.rs index 57c8cc3da8aab..d87d1a33ca131 100644 --- a/src/test/compile-fail/kindck-proc-bounds.rs +++ b/src/test/compile-fail/kindck-proc-bounds.rs @@ -13,10 +13,10 @@ fn is_freeze() {} fn foo<'a>() { is_send::(); - //~^ ERROR: instantiating a type parameter with an incompatible type + //~^ ERROR: the trait `core::kinds::Send` is not implemented is_freeze::(); - //~^ ERROR: instantiating a type parameter with an incompatible type + //~^ ERROR: the trait `core::kinds::Sync` is not implemented } fn main() { } diff --git a/src/test/compile-fail/kindck-send-object.rs b/src/test/compile-fail/kindck-send-object.rs index 99519263923be..9217d05002d88 100644 --- a/src/test/compile-fail/kindck-send-object.rs +++ b/src/test/compile-fail/kindck-send-object.rs @@ -19,19 +19,20 @@ trait Message : Send { } // careful with object types, who knows what they close over... fn object_ref_with_static_bound_not_ok() { - assert_send::<&'static Dummy+'static>(); //~ ERROR does not fulfill + assert_send::<&'static Dummy+'static>(); + //~^ ERROR the trait `core::kinds::Send` is not implemented } fn box_object_with_no_bound_not_ok<'a>() { - assert_send::>(); //~ ERROR does not fulfill + assert_send::>(); //~ ERROR the trait `core::kinds::Send` is not implemented } fn proc_with_no_bound_not_ok<'a>() { - assert_send::(); //~ ERROR does not fulfill + assert_send::(); //~ ERROR the trait `core::kinds::Send` is not implemented } fn closure_with_no_bound_not_ok<'a>() { - assert_send::<||:'static>(); //~ ERROR does not fulfill + assert_send::<||:'static>(); //~ ERROR the trait `core::kinds::Send` is not implemented } fn object_with_send_bound_ok() { diff --git a/src/test/compile-fail/kindck-send-object1.rs b/src/test/compile-fail/kindck-send-object1.rs index 6a90fd5535604..9b0991e9ac6de 100644 --- a/src/test/compile-fail/kindck-send-object1.rs +++ b/src/test/compile-fail/kindck-send-object1.rs @@ -18,6 +18,7 @@ trait Dummy { } // careful with object types, who knows what they close over... fn test51<'a>() { assert_send::<&'a Dummy>(); //~ ERROR does not fulfill the required lifetime + //~^ ERROR the trait `core::kinds::Send` is not implemented } fn test52<'a>() { assert_send::<&'a Dummy+Send>(); //~ ERROR does not fulfill the required lifetime @@ -35,10 +36,12 @@ fn test61() { // them not ok fn test_70<'a>() { assert_send::(); //~ ERROR does not fulfill the required lifetime + //~^ ERROR the trait `core::kinds::Send` is not implemented } fn test_71<'a>() { assert_send::>(); //~ ERROR does not fulfill the required lifetime + //~^ ERROR the trait `core::kinds::Send` is not implemented } fn main() { } diff --git a/src/test/compile-fail/kindck-send-object2.rs b/src/test/compile-fail/kindck-send-object2.rs index 75006477837c2..d46c6e68c05c2 100644 --- a/src/test/compile-fail/kindck-send-object2.rs +++ b/src/test/compile-fail/kindck-send-object2.rs @@ -14,11 +14,11 @@ fn assert_send() { } trait Dummy { } fn test50() { - assert_send::<&'static Dummy>(); //~ ERROR does not fulfill `Send` + assert_send::<&'static Dummy>(); //~ ERROR the trait `core::kinds::Send` is not implemented } fn test53() { - assert_send::>(); //~ ERROR does not fulfill `Send` + assert_send::>(); //~ ERROR the trait `core::kinds::Send` is not implemented } // ...unless they are properly bounded diff --git a/src/test/compile-fail/kindck-send-unsafe.rs~rust-lang_master b/src/test/compile-fail/kindck-send-unsafe.rs~rust-lang_master new file mode 100644 index 0000000000000..a9bbfcfa26263 --- /dev/null +++ b/src/test/compile-fail/kindck-send-unsafe.rs~rust-lang_master @@ -0,0 +1,22 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn assert_send() { } + +// unsafe ptrs are ok unless they point at unsendable things +fn test70() { + assert_send::<*mut int>(); +} +fn test71<'a>() { + assert_send::<*mut &'a int>(); //~ ERROR does not fulfill the required lifetime +} + +fn main() { +} diff --git a/src/test/compile-fail/map-types.rs b/src/test/compile-fail/map-types.rs index 9a974e595d3c1..cbe391324794f 100644 --- a/src/test/compile-fail/map-types.rs +++ b/src/test/compile-fail/map-types.rs @@ -18,6 +18,5 @@ fn main() { let x: Box> = box HashMap::new(); let x: Box> = x; let y: Box> = box x; - //~^ ERROR failed to find an implementation of trait collections::Map - //~^^ ERROR failed to find an implementation of trait core::collections::Collection + //~^ ERROR the trait `collections::Map` is not implemented } diff --git a/src/test/compile-fail/marker-no-copy.rs b/src/test/compile-fail/marker-no-copy.rs index 5a7cddc250a16..d620c13cc2520 100644 --- a/src/test/compile-fail/marker-no-copy.rs +++ b/src/test/compile-fail/marker-no-copy.rs @@ -14,5 +14,5 @@ fn foo(p: P) { } fn main() { - foo(marker::NoCopy); //~ ERROR does not fulfill + foo(marker::NoCopy); //~ ERROR the trait `core::kinds::Copy` is not implemented } diff --git a/src/test/compile-fail/marker-no-send.rs b/src/test/compile-fail/marker-no-send.rs index 101959035eb9b..813e2548398b5 100644 --- a/src/test/compile-fail/marker-no-send.rs +++ b/src/test/compile-fail/marker-no-send.rs @@ -14,5 +14,5 @@ fn foo(p: P) { } fn main() { - foo(marker::NoSend); //~ ERROR does not fulfill `Send` + foo(marker::NoSend); //~ ERROR the trait `core::kinds::Send` is not implemented } diff --git a/src/test/compile-fail/marker-no-share.rs b/src/test/compile-fail/marker-no-share.rs index 25fe95b80c42c..735e61fa139f0 100644 --- a/src/test/compile-fail/marker-no-share.rs +++ b/src/test/compile-fail/marker-no-share.rs @@ -14,5 +14,5 @@ fn foo(p: P) { } fn main() { - foo(marker::NoSync); //~ ERROR does not fulfill `Sync` + foo(marker::NoSync); //~ ERROR the trait `core::kinds::Sync` is not implemented } diff --git a/src/test/compile-fail/mut-not-freeze.rs b/src/test/compile-fail/mut-not-freeze.rs index a5b6acc447f84..60921c041356f 100644 --- a/src/test/compile-fail/mut-not-freeze.rs +++ b/src/test/compile-fail/mut-not-freeze.rs @@ -14,5 +14,5 @@ fn f(_: T) {} fn main() { let x = RefCell::new(0i); - f(x); //~ ERROR: which does not fulfill `Sync` + f(x); //~ ERROR `core::kinds::Sync` is not implemented } diff --git a/src/test/compile-fail/mutable-enum-indirect.rs b/src/test/compile-fail/mutable-enum-indirect.rs index 9d4c35baea38b..96937524ad513 100644 --- a/src/test/compile-fail/mutable-enum-indirect.rs +++ b/src/test/compile-fail/mutable-enum-indirect.rs @@ -19,5 +19,5 @@ fn bar(_: T) {} fn main() { let x = A(marker::NoSync); - bar(&x); //~ ERROR type parameter with an incompatible type + bar(&x); //~ ERROR the trait `core::kinds::Sync` is not implemented } diff --git a/src/test/compile-fail/no-send-res-ports.rs b/src/test/compile-fail/no-send-res-ports.rs index 5b688c6156ab7..f58350cf0934f 100644 --- a/src/test/compile-fail/no-send-res-ports.rs +++ b/src/test/compile-fail/no-send-res-ports.rs @@ -36,7 +36,8 @@ fn main() { let x = foo(Port(box(GC) ())); task::spawn(proc() { - let y = x; //~ ERROR does not fulfill `Send` + let y = x; + //~^ ERROR does not fulfill `Send` println!("{:?}", y); }); } diff --git a/src/test/compile-fail/no_send-enum.rs b/src/test/compile-fail/no_send-enum.rs index 4395151cbc157..2235a265bba16 100644 --- a/src/test/compile-fail/no_send-enum.rs +++ b/src/test/compile-fail/no_send-enum.rs @@ -19,6 +19,5 @@ fn bar(_: T) {} fn main() { let x = A(marker::NoSend); bar(x); - //~^ ERROR instantiating a type parameter with an incompatible type `Foo`, - // which does not fulfill `Send` + //~^ ERROR `core::kinds::Send` is not implemented } diff --git a/src/test/compile-fail/no_send-rc.rs b/src/test/compile-fail/no_send-rc.rs index 291340e55b856..c05b17afe1d27 100644 --- a/src/test/compile-fail/no_send-rc.rs +++ b/src/test/compile-fail/no_send-rc.rs @@ -15,6 +15,5 @@ fn bar(_: T) {} fn main() { let x = Rc::new(5i); bar(x); - //~^ ERROR instantiating a type parameter with an incompatible type `alloc::rc::Rc`, - // which does not fulfill `Send` + //~^ ERROR `core::kinds::Send` is not implemented } diff --git a/src/test/compile-fail/no_send-struct.rs b/src/test/compile-fail/no_send-struct.rs index 5b083374c51e6..6e84578e92e3b 100644 --- a/src/test/compile-fail/no_send-struct.rs +++ b/src/test/compile-fail/no_send-struct.rs @@ -20,6 +20,5 @@ fn bar(_: T) {} fn main() { let x = Foo { a: 5, ns: marker::NoSend }; bar(x); - //~^ ERROR instantiating a type parameter with an incompatible type `Foo`, - // which does not fulfill `Send` + //~^ ERROR the trait `core::kinds::Send` is not implemented } diff --git a/src/test/compile-fail/no_share-enum.rs b/src/test/compile-fail/no_share-enum.rs index f96d751af7e9d..1a692dab6d490 100644 --- a/src/test/compile-fail/no_share-enum.rs +++ b/src/test/compile-fail/no_share-enum.rs @@ -17,6 +17,5 @@ fn bar(_: T) {} fn main() { let x = A(marker::NoSync); bar(x); - //~^ ERROR instantiating a type parameter with an incompatible type `Foo`, - // which does not fulfill `Sync` + //~^ ERROR the trait `core::kinds::Sync` is not implemented } diff --git a/src/test/compile-fail/no_share-rc.rs b/src/test/compile-fail/no_share-rc.rs index 7a840674be6f0..5572f72d8fe83 100644 --- a/src/test/compile-fail/no_share-rc.rs +++ b/src/test/compile-fail/no_share-rc.rs @@ -16,6 +16,5 @@ fn bar(_: T) {} fn main() { let x = Rc::new(RefCell::new(5i)); bar(x); - //~^ ERROR instantiating a type parameter with an incompatible type - // `std::rc::Rc>`, which does not fulfill `Sync` + //~^ ERROR the trait `core::kinds::Sync` is not implemented } diff --git a/src/test/compile-fail/no_share-struct.rs b/src/test/compile-fail/no_share-struct.rs index 6b87a5fa09c98..1379a9f7382b0 100644 --- a/src/test/compile-fail/no_share-struct.rs +++ b/src/test/compile-fail/no_share-struct.rs @@ -17,6 +17,5 @@ fn bar(_: T) {} fn main() { let x = Foo { a: 5, m: marker::NoSync }; bar(x); - //~^ ERROR instantiating a type parameter with an incompatible type `Foo`, - // which does not fulfill `Sync` + //~^ ERROR the trait `core::kinds::Sync` is not implemented } diff --git a/src/test/compile-fail/object-does-not-impl-trait.rs b/src/test/compile-fail/object-does-not-impl-trait.rs index 0cbdb87d56c54..cfaf149a49cac 100644 --- a/src/test/compile-fail/object-does-not-impl-trait.rs +++ b/src/test/compile-fail/object-does-not-impl-trait.rs @@ -14,6 +14,6 @@ trait Foo {} fn take_foo(f: F) {} -fn take_object(f: Box) { take_foo(f); } //~ ERROR failed to find an implementation of trait -//~^ ERROR failed to find an implementation +fn take_object(f: Box) { take_foo(f); } +//~^ ERROR the trait `Foo` is not implemented fn main() {} diff --git a/src/test/compile-fail/pinned-deep-copy.rs b/src/test/compile-fail/pinned-deep-copy.rs index e62f5fe1a4daf..0e8bb40e0ffee 100644 --- a/src/test/compile-fail/pinned-deep-copy.rs +++ b/src/test/compile-fail/pinned-deep-copy.rs @@ -43,8 +43,7 @@ fn main() { { // Can't do this copy let x = box box box A {y: r(i)}; - let _z = x.clone(); //~ ERROR failed to find an implementation - //~^ ERROR failed to find an implementation + let _z = x.clone(); //~ ERROR not implemented println!("{:?}", x); } println!("{:?}", *i); diff --git a/src/test/compile-fail/regions-bound-missing-bound-in-impl.rs b/src/test/compile-fail/regions-bound-missing-bound-in-impl.rs index 0c9f5004f5787..c6a9f67cfc651 100644 --- a/src/test/compile-fail/regions-bound-missing-bound-in-impl.rs +++ b/src/test/compile-fail/regions-bound-missing-bound-in-impl.rs @@ -12,8 +12,6 @@ // nominal types (but not on other types) and that they are type // checked. -#![no_std] - struct Inv<'a> { // invariant w/r/t 'a x: &'a mut &'a int } diff --git a/src/test/compile-fail/regions-bounded-by-send.rs b/src/test/compile-fail/regions-bounded-by-send.rs index 3c7ffbc8d1fb1..50190411bf09b 100644 --- a/src/test/compile-fail/regions-bounded-by-send.rs +++ b/src/test/compile-fail/regions-bounded-by-send.rs @@ -58,6 +58,7 @@ fn box_with_region_not_ok<'a>() { fn object_with_random_bound_not_ok<'a>() { assert_send::<&'a Dummy+'a>(); //~ ERROR does not fulfill + //~^ ERROR not implemented } fn object_with_send_bound_not_ok<'a>() { @@ -66,10 +67,12 @@ fn object_with_send_bound_not_ok<'a>() { fn proc_with_lifetime_not_ok<'a>() { assert_send::(); //~ ERROR does not fulfill + //~^ ERROR not implemented } fn closure_with_lifetime_not_ok<'a>() { assert_send::<||:'a>(); //~ ERROR does not fulfill + //~^ ERROR not implemented } // unsafe pointers are ok unless they point at unsendable things diff --git a/src/test/compile-fail/regions-bounded-method-type-parameters.rs b/src/test/compile-fail/regions-bounded-method-type-parameters.rs index ba1993686d5d9..279139d8de96a 100644 --- a/src/test/compile-fail/regions-bounded-method-type-parameters.rs +++ b/src/test/compile-fail/regions-bounded-method-type-parameters.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![no_std] - // Check that explicit region bounds are allowed on the various // nominal types (but not on other types) and that they are type // checked. diff --git a/src/test/compile-fail/regions-escape-via-trait-or-not.rs b/src/test/compile-fail/regions-escape-via-trait-or-not.rs index b73b5e0649ff5..adc960b069d05 100644 --- a/src/test/compile-fail/regions-escape-via-trait-or-not.rs +++ b/src/test/compile-fail/regions-escape-via-trait-or-not.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![no_std] - #![allow(dead_code)] trait Deref { diff --git a/src/test/compile-fail/regions-lifetime-bounds-on-fns.rs b/src/test/compile-fail/regions-lifetime-bounds-on-fns.rs index a52d2f9f9a0f7..773d6e2c70365 100644 --- a/src/test/compile-fail/regions-lifetime-bounds-on-fns.rs +++ b/src/test/compile-fail/regions-lifetime-bounds-on-fns.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![no_std] - fn a<'a, 'b:'a>(x: &mut &'a int, y: &mut &'b int) { // Note: this is legal because of the `'b:'a` declaration. *x = *y; diff --git a/src/test/compile-fail/repeat-to-run-dtor-twice.rs b/src/test/compile-fail/repeat-to-run-dtor-twice.rs index 77146b65ae676..8fdf586b3d1de 100644 --- a/src/test/compile-fail/repeat-to-run-dtor-twice.rs +++ b/src/test/compile-fail/repeat-to-run-dtor-twice.rs @@ -24,5 +24,6 @@ impl Drop for Foo { fn main() { let a = Foo { x: 3 }; - let _ = [ a, ..5 ]; //~ ERROR copying a value of non-copyable type + let _ = [ a, ..5 ]; + //~^ ERROR the trait `core::kinds::Copy` is not implemented for the type `Foo` } diff --git a/src/test/compile-fail/task-rng-isnt-sendable.rs b/src/test/compile-fail/task-rng-isnt-sendable.rs index 366e1fd4dcae4..e9997083babd2 100644 --- a/src/test/compile-fail/task-rng-isnt-sendable.rs +++ b/src/test/compile-fail/task-rng-isnt-sendable.rs @@ -16,5 +16,5 @@ fn test_send() {} pub fn main() { test_send::(); - //~^ ERROR: incompatible type `std::rand::TaskRng`, which does not fulfill `Send` + //~^ ERROR `core::kinds::Send` is not implemented } diff --git a/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs b/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs index 78b4ab817bfac..85a2761172d61 100644 --- a/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs +++ b/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs @@ -14,7 +14,7 @@ trait Foo { // This should emit the less confusing error, not the more confusing one. fn foo(_x: Foo + Send) { - //~^ERROR variable `_x` has dynamically sized type `Foo+Send` + //~^ERROR the trait `core::kinds::Sized` is not implemented } fn main() { } diff --git a/src/test/compile-fail/trait-bounds-on-structs-and-enums-locals.rs b/src/test/compile-fail/trait-bounds-on-structs-and-enums-locals.rs index 226556dc78fcb..4233fa843eb61 100644 --- a/src/test/compile-fail/trait-bounds-on-structs-and-enums-locals.rs +++ b/src/test/compile-fail/trait-bounds-on-structs-and-enums-locals.rs @@ -16,12 +16,11 @@ struct Foo { fn main() { let foo = Foo { - //~^ ERROR failed to find an implementation - //~^^ ERROR instantiating a type parameter with an incompatible type + //~^ ERROR not implemented x: 3i }; + let baz: Foo = fail!(); - //~^ ERROR failed to find an implementation - //~^^ ERROR instantiating a type parameter with an incompatible type + //~^ ERROR not implemented } diff --git a/src/test/compile-fail/trait-bounds-on-structs-and-enums-static.rs b/src/test/compile-fail/trait-bounds-on-structs-and-enums-static.rs index 142ead75bcf19..c26cccc8b146c 100644 --- a/src/test/compile-fail/trait-bounds-on-structs-and-enums-static.rs +++ b/src/test/compile-fail/trait-bounds-on-structs-and-enums-static.rs @@ -15,8 +15,7 @@ struct Foo { } static X: Foo = Foo { -//~^ ERROR failed to find an implementation -//~^^ ERROR instantiating a type parameter with an incompatible type +//~^ ERROR not implemented x: 1, }; diff --git a/src/test/compile-fail/trait-bounds-on-structs-and-enums-xc.rs b/src/test/compile-fail/trait-bounds-on-structs-and-enums-xc.rs index 9be519960b81f..d01f9d59fb437 100644 --- a/src/test/compile-fail/trait-bounds-on-structs-and-enums-xc.rs +++ b/src/test/compile-fail/trait-bounds-on-structs-and-enums-xc.rs @@ -15,22 +15,11 @@ extern crate trait_bounds_on_structs_and_enums_xc; use trait_bounds_on_structs_and_enums_xc::{Bar, Foo, Trait}; fn explode(x: Foo) {} -//~^ ERROR failed to find an implementation -//~^^ ERROR instantiating a type parameter with an incompatible type +//~^ ERROR not implemented fn kaboom(y: Bar) {} -//~^ ERROR failed to find an implementation -//~^^ ERROR instantiating a type parameter with an incompatible type +//~^ ERROR not implemented fn main() { - let foo = Foo { - //~^ ERROR failed to find an implementation - //~^^ ERROR instantiating a type parameter with an incompatible type - x: 3i - }; - let bar: Bar = return; - //~^ ERROR failed to find an implementation - //~^^ ERROR instantiating a type parameter with an incompatible type - let _ = bar; } diff --git a/src/test/compile-fail/trait-bounds-on-structs-and-enums-xc1.rs b/src/test/compile-fail/trait-bounds-on-structs-and-enums-xc1.rs new file mode 100644 index 0000000000000..d3689067aef71 --- /dev/null +++ b/src/test/compile-fail/trait-bounds-on-structs-and-enums-xc1.rs @@ -0,0 +1,26 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:trait_bounds_on_structs_and_enums_xc.rs + +extern crate trait_bounds_on_structs_and_enums_xc; + +use trait_bounds_on_structs_and_enums_xc::{Bar, Foo, Trait}; + +fn main() { + let foo = Foo { + //~^ ERROR not implemented + x: 3i + }; + let bar: Bar = return; + //~^ ERROR not implemented + let _ = bar; +} + diff --git a/src/test/compile-fail/trait-bounds-on-structs-and-enums.rs b/src/test/compile-fail/trait-bounds-on-structs-and-enums.rs index ba035dd2c6f19..5fe8e435e6806 100644 --- a/src/test/compile-fail/trait-bounds-on-structs-and-enums.rs +++ b/src/test/compile-fail/trait-bounds-on-structs-and-enums.rs @@ -20,40 +20,34 @@ enum Bar { CBar(uint), } -fn explode(x: Foo) {} -//~^ ERROR failed to find an implementation -//~^^ ERROR instantiating a type parameter with an incompatible type +fn explode(x: Foo) {} +//~^ ERROR not implemented fn kaboom(y: Bar) {} -//~^ ERROR failed to find an implementation -//~^^ ERROR instantiating a type parameter with an incompatible type +//~^ ERROR not implemented -impl Foo { //~ ERROR failed to find an implementation -//~^ ERROR instantiating a type parameter with an incompatible type +impl Foo { +//~^ ERROR the trait `Trait` is not implemented fn uhoh() {} } struct Baz { -//~^ ERROR failed to find an implementation -//~^^ ERROR instantiating a type parameter with an incompatible type +//~^ ERROR not implemented a: Foo, } enum Boo { -//~^ ERROR failed to find an implementation -//~^^ ERROR instantiating a type parameter with an incompatible type +//~^ ERROR not implemented Quux(Bar), } struct Badness { -//~^ ERROR failed to find an implementation -//~^^ ERROR instantiating a type parameter with an incompatible type +//~^ ERROR not implemented b: Foo, } enum MoreBadness { -//~^ ERROR failed to find an implementation -//~^^ ERROR instantiating a type parameter with an incompatible type +//~^ ERROR not implemented EvenMoreBadness(Bar), } @@ -64,15 +58,10 @@ trait PolyTrait { struct Struct; impl PolyTrait> for Struct { -//~^ ERROR failed to find an implementation -//~^^ ERROR instantiating a type parameter with an incompatible type +//~^ ERROR not implemented fn whatever() {} } fn main() { - let bar: Bar = return; - //~^ ERROR failed to find an implementation - //~^^ ERROR instantiating a type parameter with an incompatible type - let _ = bar; } diff --git a/src/test/compile-fail/trait-coercion-generic-bad.rs b/src/test/compile-fail/trait-coercion-generic-bad.rs index 55e5a02cfaebf..74982946d7ddd 100644 --- a/src/test/compile-fail/trait-coercion-generic-bad.rs +++ b/src/test/compile-fail/trait-coercion-generic-bad.rs @@ -25,7 +25,6 @@ impl Trait<&'static str> for Struct { fn main() { let s: Box> = box Struct { person: "Fred" }; - //~^ ERROR expected Trait, found Trait<&'static str> - //~^^ ERROR expected Trait, found Trait<&'static str> + //~^ ERROR type mismatch s.f(1); } diff --git a/src/test/compile-fail/type-params-in-different-spaces-2.rs b/src/test/compile-fail/type-params-in-different-spaces-2.rs index 4143d9d9b849a..580aea651857b 100644 --- a/src/test/compile-fail/type-params-in-different-spaces-2.rs +++ b/src/test/compile-fail/type-params-in-different-spaces-2.rs @@ -15,12 +15,12 @@ trait Tr { // these compile as if Self: Tr, even tho only Self: Tr trait A: Tr { fn test(u: U) -> Self { - Tr::op(u) //~ ERROR expected Tr, found Tr + Tr::op(u) //~ ERROR type mismatch } } trait B: Tr { fn test(u: U) -> Self { - Tr::op(u) //~ ERROR expected Tr, found Tr + Tr::op(u) //~ ERROR type mismatch } } diff --git a/src/test/compile-fail/typeck-unsafe-always-share.rs b/src/test/compile-fail/typeck-unsafe-always-share.rs index 369bd0a15c452..7c74cdc890d85 100644 --- a/src/test/compile-fail/typeck-unsafe-always-share.rs +++ b/src/test/compile-fail/typeck-unsafe-always-share.rs @@ -39,5 +39,5 @@ fn main() { let ns = NoSync{m: marker::NoSync}; test(ns); - //~^ ERROR instantiating a type parameter with an incompatible type `NoSync`, which does not fulfill `Sync` + //~^ ERROR `core::kinds::Sync` is not implemented } diff --git a/src/test/compile-fail/unboxed-closures-vtable-mismatch.rs b/src/test/compile-fail/unboxed-closures-vtable-mismatch.rs index 2ee632b9093c8..a96bde7cca4cd 100644 --- a/src/test/compile-fail/unboxed-closures-vtable-mismatch.rs +++ b/src/test/compile-fail/unboxed-closures-vtable-mismatch.rs @@ -18,8 +18,7 @@ fn call_it>(y: int, mut f: F) -> int { pub fn main() { let f = |&mut: x: uint, y: int| -> int { (x as int) + y }; - let z = call_it(3, f); //~ ERROR expected core::ops::FnMut - //~^ ERROR expected core::ops::FnMut + let z = call_it(3, f); //~ ERROR type mismatch println!("{}", z); } diff --git a/src/test/compile-fail/unboxed-closures-wrong-trait.rs b/src/test/compile-fail/unboxed-closures-wrong-trait.rs index 50d90c6200e12..27f1da75c3aef 100644 --- a/src/test/compile-fail/unboxed-closures-wrong-trait.rs +++ b/src/test/compile-fail/unboxed-closures-wrong-trait.rs @@ -17,6 +17,6 @@ fn c int>(f: F) -> int { fn main() { let z: int = 7; assert_eq!(c(|&: x: int, y| x + y + z), 10); - //~^ ERROR failed to find an implementation + //~^ ERROR not implemented } diff --git a/src/test/compile-fail/unique-pinned-nocopy.rs b/src/test/compile-fail/unique-pinned-nocopy.rs index e5b7bf08715b0..940ca76582802 100644 --- a/src/test/compile-fail/unique-pinned-nocopy.rs +++ b/src/test/compile-fail/unique-pinned-nocopy.rs @@ -20,7 +20,6 @@ impl Drop for r { fn main() { let i = box r { b: true }; - let _j = i.clone(); //~ ERROR failed to find an implementation - //~^ ERROR failed to find an implementation + let _j = i.clone(); //~ ERROR not implemented println!("{:?}", i); } diff --git a/src/test/compile-fail/unique-unique-kind.rs b/src/test/compile-fail/unique-unique-kind.rs index dd0c7953434b6..7d6cdaef85b2f 100644 --- a/src/test/compile-fail/unique-unique-kind.rs +++ b/src/test/compile-fail/unique-unique-kind.rs @@ -16,5 +16,5 @@ fn f(_i: T) { fn main() { let i = box box(GC) 100i; - f(i); //~ ERROR does not fulfill `Send` + f(i); //~ ERROR `core::kinds::Send` is not implemented } diff --git a/src/test/compile-fail/unique-vec-res.rs b/src/test/compile-fail/unique-vec-res.rs index dfb04323005f3..54b1fdea7190d 100644 --- a/src/test/compile-fail/unique-vec-res.rs +++ b/src/test/compile-fail/unique-vec-res.rs @@ -36,10 +36,8 @@ fn main() { let r1 = vec!(box r { i: i1 }); let r2 = vec!(box r { i: i2 }); f(r1.clone(), r2.clone()); - //~^ ERROR failed to find an implementation of - //~^^ ERROR failed to find an implementation of - //~^^^ ERROR failed to find an implementation of - //~^^^^ ERROR failed to find an implementation of + //~^ ERROR the trait `core::clone::Clone` is not implemented + //~^^ ERROR the trait `core::clone::Clone` is not implemented println!("{:?}", (r2, i1.get())); println!("{:?}", (r1, i2.get())); } diff --git a/src/test/compile-fail/unsendable-class.rs b/src/test/compile-fail/unsendable-class.rs index 2991a60835da3..c3fea8e86d4f4 100644 --- a/src/test/compile-fail/unsendable-class.rs +++ b/src/test/compile-fail/unsendable-class.rs @@ -28,6 +28,6 @@ fn foo(i:int, j: Gc) -> foo { fn main() { let cat = "kitty".to_string(); - let (tx, _) = channel(); //~ ERROR does not fulfill `Send` - tx.send(foo(42, box(GC) (cat))); //~ ERROR does not fulfill `Send` + let (tx, _) = channel(); //~ ERROR `core::kinds::Send` is not implemented + tx.send(foo(42, box(GC) (cat))); //~ ERROR `core::kinds::Send` is not implemented } diff --git a/src/test/compile-fail/unsized-bare-typaram.rs b/src/test/compile-fail/unsized-bare-typaram.rs index 6fd749b129819..7b5d42954117c 100644 --- a/src/test/compile-fail/unsized-bare-typaram.rs +++ b/src/test/compile-fail/unsized-bare-typaram.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: instantiating a type parameter with an incompatible type fn bar() { } -fn foo() { bar::() } +fn foo() { bar::() } //~ ERROR the trait `core::kinds::Sized` is not implemented fn main() { } diff --git a/src/test/compile-fail/unsized-enum.rs b/src/test/compile-fail/unsized-enum.rs index 651eb26cadc6f..edef3ae649269 100644 --- a/src/test/compile-fail/unsized-enum.rs +++ b/src/test/compile-fail/unsized-enum.rs @@ -8,7 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: instantiating a type parameter with an incompatible type +enum Foo { FooSome(T), FooNone } + fn bar() { } -fn foo() { bar::>() } +fn foo() { bar::>() } +//~^ 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, the other is +// for Foo being provided to bar. + fn main() { } diff --git a/src/test/compile-fail/unsized-struct.rs b/src/test/compile-fail/unsized-struct.rs index ec6aafb43f46f..58aba1a264648 100644 --- a/src/test/compile-fail/unsized-struct.rs +++ b/src/test/compile-fail/unsized-struct.rs @@ -8,10 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: instantiating a type parameter with an incompatible type - struct Foo { data: T } fn bar() { } fn foo() { bar::>() } +//~^ 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, the other is for Foo as a value +// for bar's type parameter. + fn main() { } diff --git a/src/test/compile-fail/unsized3.rs b/src/test/compile-fail/unsized3.rs index f71afeb1b308f..fba1237340fe5 100644 --- a/src/test/compile-fail/unsized3.rs +++ b/src/test/compile-fail/unsized3.rs @@ -8,12 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Test sized-ness checking in substitution. +// Test sized-ness checking in substitution within fn bodies.. // Unbounded. fn f1(x: &X) { - f2::(x); //~ ERROR instantiating a type parameter with an incompatible type `X`, which does n + f2::(x); + //~^ ERROR the trait `core::kinds::Sized` is not implemented } fn f2(x: &X) { } @@ -21,7 +22,8 @@ fn f2(x: &X) { // Bounded. trait T for Sized? {} fn f3(x: &X) { - f4::(x); //~ ERROR instantiating a type parameter with an incompatible type `X`, which does n + f4::(x); + //~^ ERROR the trait `core::kinds::Sized` is not implemented } fn f4(x: &X) { } @@ -34,7 +36,8 @@ enum E { fn f5(x: &Y) {} fn f6(x: &X) {} fn f7(x1: &E, x2: &E) { - f5(x1); //~ERROR instantiating a type parameter with an incompatible type `E`, which does not + f5(x1); + //~^ ERROR the trait `core::kinds::Sized` is not implemented f6(x2); // ok } @@ -45,40 +48,18 @@ struct S { } fn f8(x1: &S, x2: &S) { - f5(x1); //~ERROR instantiating a type parameter with an incompatible type `S`, which does not + f5(x1); + //~^ ERROR the trait `core::kinds::Sized` is not implemented f6(x2); // ok } // Test some tuples. fn f9(x1: Box>, x2: Box>) { - f5(&(*x1, 34i)); //~ERROR E0161 - //~^ ERROR instantiating a type parameter with an incompatible type - f5(&(32i, *x2)); //~ERROR E0161 - //~^ ERROR instantiating a type parameter with an incompatible type + f5(&(*x1, 34i)); + //~^ ERROR the trait `core::kinds::Sized` is not implemented + f5(&(32i, *x2)); + //~^ ERROR the trait `core::kinds::Sized` is not implemented } -// impl - bounded -trait T1 { -} -struct S3; -impl T1 for S3 { //~ ERROR instantiating a type parameter with an incompatible -} - -// impl - unbounded -trait T2 { -} -impl T2 for S3 { //~ ERROR instantiating a type parameter with an incompatible type -} - -// impl - struct -trait T3 { -} -struct S4; -impl T3 for S4 { //~ ERROR instantiating a type parameter with an incompatible type -} -impl S4 { //~ ERROR instantiating a type parameter with an incompatible type -} - - pub fn main() { } diff --git a/src/test/compile-fail/unsized6.rs b/src/test/compile-fail/unsized6.rs index 6618cce0214f4..0efd178f75b8c 100644 --- a/src/test/compile-fail/unsized6.rs +++ b/src/test/compile-fail/unsized6.rs @@ -14,33 +14,29 @@ trait T for Sized? {} fn f1(x: &X) { - let _: X; //~ERROR variable `_` has dynamically sized type `X` - let _: (int, (X, int)); //~ERROR variable `_` has dynamically sized type `(int,(X,int))` - let y: X; //~ERROR variable `y` has dynamically sized type `X` - let y: (int, (X, int)); //~ERROR variable `y` has dynamically sized type `(int,(X,int))` + let _: X; // <-- this is OK, no bindings created, no initializer. + let _: (int, (X, int)); // same + let y: X; //~ERROR the trait `core::kinds::Sized` is not implemented + let y: (int, (X, int)); //~ERROR the trait `core::kinds::Sized` is not implemented } fn f2(x: &X) { - let _: X; //~ERROR variable `_` has dynamically sized type `X` - let _: (int, (X, int)); //~ERROR variable `_` has dynamically sized type `(int,(X,int))` - let y: X; //~ERROR variable `y` has dynamically sized type `X` - let y: (int, (X, int)); //~ERROR variable `y` has dynamically sized type `(int,(X,int))` + let y: X; //~ERROR the trait `core::kinds::Sized` is not implemented + let y: (int, (X, int)); //~ERROR the trait `core::kinds::Sized` is not implemented } fn f3(x1: Box, x2: Box, x3: Box) { - let y: X = *x1; //~ERROR variable `y` has dynamically sized type `X` - let y = *x2; //~ERROR variable `y` has dynamically sized type `X` - let (y, z) = (*x3, 4i); //~ERROR variable `y` has dynamically sized type `X` - //~^ ERROR E0161 + let y: X = *x1; //~ERROR the trait `core::kinds::Sized` is not implemented + let y = *x2; //~ERROR the trait `core::kinds::Sized` is not implemented + let (y, z) = (*x3, 4i); //~ERROR the trait `core::kinds::Sized` is not implemented } fn f4(x1: Box, x2: Box, x3: Box) { - let y: X = *x1; //~ERROR variable `y` has dynamically sized type `X` - let y = *x2; //~ERROR variable `y` has dynamically sized type `X` - let (y, z) = (*x3, 4i); //~ERROR variable `y` has dynamically sized type `X` - //~^ ERROR E0161 + let y: X = *x1; //~ERROR the trait `core::kinds::Sized` is not implemented + let y = *x2; //~ERROR the trait `core::kinds::Sized` is not implemented + let (y, z) = (*x3, 4i); //~ERROR the trait `core::kinds::Sized` is not implemented } -fn g1(x: X) {} //~ERROR variable `x` has dynamically sized type `X` -fn g2(x: X) {} //~ERROR variable `x` has dynamically sized type `X` +fn g1(x: X) {} //~ERROR the trait `core::kinds::Sized` is not implemented +fn g2(x: X) {} //~ERROR the trait `core::kinds::Sized` is not implemented pub fn main() { } diff --git a/src/test/compile-fail/unsized7.rs b/src/test/compile-fail/unsized7.rs new file mode 100644 index 0000000000000..fd9dffe00d2d5 --- /dev/null +++ b/src/test/compile-fail/unsized7.rs @@ -0,0 +1,43 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test sized-ness checking in substitution in impls. + +trait T for Sized? {} + +// I would like these to fail eventually. +// impl - bounded +trait T1 { +} +struct S3; +impl T1 for S3 { + //~^ ERROR `core::kinds::Sized` is not implemented for the type `X` +} + +// impl - unbounded +trait T2 { +} +struct S4; +impl T2 for S4 { + //~^ ERROR `core::kinds::Sized` is not implemented for the type `X` +} + +// impl - struct +trait T3 { +} +struct S5; +impl T3 for S5 { //~ ERROR not implemented +} + +impl S5 { //~ ERROR not implemented +} + + +fn main() { } diff --git a/src/test/compile-fail/vec-res-add.rs b/src/test/compile-fail/vec-res-add.rs index 8da9511b493de..bfd52d69cb217 100644 --- a/src/test/compile-fail/vec-res-add.rs +++ b/src/test/compile-fail/vec-res-add.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: failed to find an implementation - struct r { i:int } @@ -25,5 +23,7 @@ fn main() { let i = vec!(r(0)); let j = vec!(r(1)); let k = i + j; + //~^ ERROR not implemented println!("{}", j); + //~^ ERROR not implemented } diff --git a/src/test/compile-fail/vtable-res-trait-param.rs b/src/test/compile-fail/vtable-res-trait-param.rs index 2baa89d52f28b..12cfe9c20fa9b 100644 --- a/src/test/compile-fail/vtable-res-trait-param.rs +++ b/src/test/compile-fail/vtable-res-trait-param.rs @@ -24,8 +24,7 @@ impl TraitB for int { fn call_it(b: B) -> int { let y = 4u; - b.gimme_an_a(y) //~ ERROR failed to find an implementation of trait TraitA - //~^ ERROR failed to find an implementation of trait TraitA + b.gimme_an_a(y) //~ ERROR the trait `TraitA` is not implemented } fn main() { diff --git a/src/test/compile-fail/where-clauses-unsatisfied.rs b/src/test/compile-fail/where-clauses-unsatisfied.rs index 2324da6b8f422..4a4a5f3193d3a 100644 --- a/src/test/compile-fail/where-clauses-unsatisfied.rs +++ b/src/test/compile-fail/where-clauses-unsatisfied.rs @@ -15,9 +15,6 @@ struct Struct; fn main() { drop(equal(&Struct, &Struct)) - //~^ ERROR failed to find an implementation of trait core::cmp::Eq - //~^^ ERROR failed to find an implementation of trait core::cmp::PartialEq - //~^^^ ERROR failed to find an implementation of trait core::cmp::Eq - //~^^^^ ERROR failed to find an implementation of trait core::cmp::PartialEq + //~^ ERROR the trait `core::cmp::Eq` is not implemented } diff --git a/src/test/run-pass/drop-struct-as-object.rs b/src/test/run-pass/drop-struct-as-object.rs new file mode 100644 index 0000000000000..6d7715ed9a5a0 --- /dev/null +++ b/src/test/run-pass/drop-struct-as-object.rs @@ -0,0 +1,42 @@ +// Copyright 2012-2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that destructor on a struct runs successfully after the struct +// is boxed and converted to an object. + +static mut value: uint = 0; + +struct Cat { + name : uint, +} + +trait Dummy { + fn get(&self) -> uint; +} + +impl Dummy for Cat { + fn get(&self) -> uint { self.name } +} + +impl Drop for Cat { + fn drop(&mut self) { + unsafe { value = self.name; } + } +} + +pub fn main() { + { + let x = box Cat {name: 22}; + let nyan: Box = x as Box; + } + unsafe { + assert_eq!(value, 22); + } +} diff --git a/src/test/run-pass/object-one-type-two-traits.rs b/src/test/run-pass/object-one-type-two-traits.rs new file mode 100644 index 0000000000000..f8bc0929bfa80 --- /dev/null +++ b/src/test/run-pass/object-one-type-two-traits.rs @@ -0,0 +1,39 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Testing creating two vtables with the same self type, but different +// traits. + +use std::any::Any; +use std::any::AnyRefExt; + +trait Wrap { + fn get(&self) -> int; + fn wrap(self: Box) -> Box; +} + +impl Wrap for int { + fn get(&self) -> int { + *self + } + fn wrap(self: Box) -> Box { + self as Box + } +} + +fn is(x: &Any) -> bool { + x.is::() +} + +fn main() { + let x = box 22i as Box; + println!("x={}", x.get()); + let y = x.wrap(); +} From 713cf373c118517ec2638c4af1b73deceae4d4e0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 12 Sep 2014 10:46:50 -0400 Subject: [PATCH 02/10] Take core as a dependency on librlibc. This is needed so that it can see the lang-items for Sized etc. @acrichto and @thestinger had no objections. --- mk/crates.mk | 2 +- src/librlibc/lib.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/mk/crates.mk b/mk/crates.mk index c0fd04401bcda..0011a7245e56d 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -59,7 +59,7 @@ CRATES := $(TARGET_CRATES) $(HOST_CRATES) TOOLS := compiletest rustdoc rustc DEPS_core := -DEPS_rlibc := +DEPS_rlibc := core DEPS_unicode := core DEPS_alloc := core libc native:jemalloc DEPS_debug := std diff --git a/src/librlibc/lib.rs b/src/librlibc/lib.rs index 2ab7a6c52fac3..c24a7e9ca77d1 100644 --- a/src/librlibc/lib.rs +++ b/src/librlibc/lib.rs @@ -35,12 +35,13 @@ // LLVM to optimize these function calls to themselves! #![no_builtins] +#[phase(plugin, link)] extern crate core; + #[cfg(test)] extern crate native; #[cfg(test)] extern crate test; #[cfg(test)] extern crate debug; #[cfg(test)] #[phase(plugin, link)] extern crate std; -#[cfg(test)] #[phase(plugin, link)] extern crate core; // Require the offset intrinsics for LLVM to properly optimize the // implementations below. If pointer arithmetic is done through integers the From c5754f3971b4bb6ea1c9527863189792ab5ee336 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 12 Sep 2014 10:53:35 -0400 Subject: [PATCH 03/10] Guts of the new trait matching algorithm, not yet in use --- src/librustc/lib.rs | 1 + src/librustc/middle/lang_items.rs | 11 + src/librustc/middle/subst.rs | 28 +- src/librustc/middle/traits/doc.rs | 268 +++++ src/librustc/middle/traits/fulfill.rs | 250 ++++ src/librustc/middle/traits/mod.rs | 438 +++++++ src/librustc/middle/traits/select.rs | 1024 +++++++++++++++++ src/librustc/middle/traits/util.rs | 356 ++++++ src/librustc/middle/ty.rs | 116 +- src/librustc/middle/ty_fold.rs | 95 +- .../middle/typeck/infer/error_reporting.rs | 7 +- src/librustc/middle/typeck/infer/mod.rs | 161 ++- src/librustc/middle/typeck/infer/resolve.rs | 27 +- src/librustc/middle/typeck/infer/skolemize.rs | 157 +++ src/librustc/middle/typeck/infer/unify.rs | 23 + 15 files changed, 2856 insertions(+), 106 deletions(-) create mode 100644 src/librustc/middle/traits/doc.rs create mode 100644 src/librustc/middle/traits/fulfill.rs create mode 100644 src/librustc/middle/traits/mod.rs create mode 100644 src/librustc/middle/traits/select.rs create mode 100644 src/librustc/middle/traits/util.rs create mode 100644 src/librustc/middle/typeck/infer/skolemize.rs diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index fd643a70c7b95..af3d19c4d2d40 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -108,6 +108,7 @@ pub mod middle { pub mod save; pub mod stability; pub mod subst; + pub mod traits; pub mod trans; pub mod ty; pub mod ty_fold; diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 24782240f06c4..1ea0681085b1a 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -85,6 +85,17 @@ impl LanguageItems { } } + pub fn from_builtin_kind(&self, bound: ty::BuiltinBound) + -> Result + { + match bound { + ty::BoundSend => self.require(SendTraitLangItem), + ty::BoundSized => self.require(SizedTraitLangItem), + ty::BoundCopy => self.require(CopyTraitLangItem), + ty::BoundSync => self.require(SyncTraitLangItem), + } + } + pub fn to_builtin_kind(&self, id: ast::DefId) -> Option { if Some(id) == self.send_trait() { Some(ty::BoundSend) diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index c1c23dff98406..23f53d9b4ab80 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -333,6 +333,16 @@ impl VecPerParamSpace { } } + fn new_internal(content: Vec, type_limit: uint, self_limit: uint) + -> VecPerParamSpace + { + VecPerParamSpace { + type_limit: type_limit, + self_limit: self_limit, + content: content, + } + } + pub fn sort(t: Vec, space: |&T| -> ParamSpace) -> VecPerParamSpace { let mut result = VecPerParamSpace::empty(); for t in t.move_iter() { @@ -448,13 +458,17 @@ impl VecPerParamSpace { } pub fn map(&self, pred: |&T| -> U) -> VecPerParamSpace { - // FIXME (#15418): this could avoid allocating the intermediate - // Vec's, but note that the values of type_limit and self_limit - // also need to be kept in sync during construction. - VecPerParamSpace::new( - self.get_slice(TypeSpace).iter().map(|p| pred(p)).collect(), - self.get_slice(SelfSpace).iter().map(|p| pred(p)).collect(), - self.get_slice(FnSpace).iter().map(|p| pred(p)).collect()) + let result = self.iter().map(pred).collect(); + VecPerParamSpace::new_internal(result, + self.type_limit, + self.self_limit) + } + + pub fn map_move(self, pred: |T| -> U) -> VecPerParamSpace { + let (t, s, f) = self.split(); + VecPerParamSpace::new(t.move_iter().map(|p| pred(p)).collect(), + s.move_iter().map(|p| pred(p)).collect(), + f.move_iter().map(|p| pred(p)).collect()) } pub fn map_rev(&self, pred: |&T| -> U) -> VecPerParamSpace { diff --git a/src/librustc/middle/traits/doc.rs b/src/librustc/middle/traits/doc.rs new file mode 100644 index 0000000000000..98db226387453 --- /dev/null +++ b/src/librustc/middle/traits/doc.rs @@ -0,0 +1,268 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! + +# TRAIT RESOLUTION + +This document describes the general process and points out some non-obvious +things. + +## Major concepts + +Trait resolution is the process of pairing up an impl with each +reference to a trait. So, for example, if there is a generic function like: + + fn clone_slice(x: &[T]) -> Vec { ... } + +and then a call to that function: + + let v: Vec = clone_slice([1, 2, 3].as_slice()) + +it is the job of trait resolution to figure out (in which case) +whether there exists an impl of `int : Clone` + +Note that in some cases, like generic functions, we may not be able to +find a specific impl, but we can figure out that the caller must +provide an impl. To see what I mean, consider the body of `clone_slice`: + + fn clone_slice(x: &[T]) -> Vec { + let mut v = Vec::new(); + for e in x.iter() { + v.push((*e).clone()); // (*) + } + } + +The line marked `(*)` is only legal if `T` (the type of `*e`) +implements the `Clone` trait. Naturally, since we don't know what `T` +is, we can't find the specific impl; but based on the bound `T:Clone`, +we can say that there exists an impl which the caller must provide. + +We use the term *obligation* to refer to a trait reference in need of +an impl. + +## Overview + +Trait resolution consists of three major parts: + +- SELECTION: Deciding how to resolve a specific obligation. For + example, selection might decide that a specific obligation can be + resolved by employing an impl which matches the self type, or by + using a parameter bound. In the case of an impl, Selecting one + obligation can create *nested obligations* because of where clauses + on the impl itself. + +- FULFILLMENT: The fulfillment code is what tracks that obligations + are completely fulfilled. Basically it is a worklist of obligations + to be selected: once selection is successful, the obligation is + removed from the worklist and any nested obligations are enqueued. + +- COHERENCE: The coherence checks are intended to ensure that there + are never overlapping impls, where two impls could be used with + equal precedence. + +## Selection + +Selection is the process of deciding whether an obligation can be +resolved and, if so, how it is to be resolved (via impl, where clause, etc). +The main interface is the `select()` function, which takes an obligation +and returns a `SelectionResult`. There are three possible outcomes: + +- `Ok(Some(selection))` -- yes, the obligation can be resolved, and + `selection` indicates how. If the impl was resolved via an impl, + then `selection` may also indicate nested obligations that are required + by the impl. + +- `Ok(None)` -- we are not yet sure whether the obligation can be + resolved or not. This happens most commonly when the obligation + contains unbound type variables. + +- `Err(err)` -- the obligation definitely cannot be resolved due to a + type error, or because there are no impls that could possibly apply, + etc. + +The basic algorithm for selection is broken into two big phases: +candidate assembly and confirmation. + +### Candidate assembly + +Searches for impls/where-clauses/etc that might +possibly be used to satisfy the obligation. Each of those is called +a candidate. To avoid ambiguity, we want to find exactly one +candidate that is definitively applicable. In some cases, we may not +know whether an impl/where-clause applies or not -- this occurs when +the obligation contains unbound inference variables. + +One important point is that candidate assembly considers *only the +input types* of the obligation when deciding whether an impl applies +or not. Consider the following example: + + trait Convert { // T is output, Self is input + fn convert(&self) -> T; + } + + impl Convert for int { ... } + +Now assume we have an obligation `int : Convert`. During +candidate assembly, the impl above would be considered a definitively +applicable candidate, because it has the same self type (`int`). The +fact that the output type parameter `T` is `uint` on the impl and +`char` in the obligation is not considered. + +#### Skolemization + +We (at least currently) wish to guarantee "crate concatenability" -- +which basically means that you could take two crates, concatenate +them textually, and the combined crate would continue to compile. The +only real way that this relates to trait matching is with +inference. We have to be careful not to influence unbound type +variables during the selection process, basically. + +Here is an example: + + trait Foo { fn method() { ... }} + impl Foo for int { ... } + + fn something() { + let mut x = None; // `x` has type `Option` + loop { + match x { + Some(ref y) => { // `y` has type ? + y.method(); // (*) + ... + }}} + } + +The question is, can we resolve the call to `y.method()`? We don't yet +know what type `y` has. However, there is only one impl in scope, and +it is for `int`, so perhaps we could deduce that `y` *must* have type +`int` (and hence the type of `x` is `Option`)? This is actually +sound reasoning: `int` is the only type in scope that could possibly +make this program type check. However, this deduction is a bit +"unstable", though, because if we concatenated with another crate that +defined a newtype and implemented `Foo` for this newtype, then the +inference would fail, because there would be two potential impls, not +one. + +It is unclear how important this property is. It might be nice to drop it. +But for the time being we maintain it. + +The way we do this is by *skolemizing* the obligation self type during +the selection process -- skolemizing means, basically, replacing all +unbound type variables with a new "skolemized" type. Each skolemized +type is basically considered "as if" it were some fresh type that is +distinct from all other types. The skolemization process also replaces +lifetimes with `'static`, see the section on lifetimes below for an +explanation. + +In the example above, this means that when matching `y.method()` we +would convert the type of `y` from a type variable `?` to a skolemized +type `X`. Then, since `X` cannot unify with `int`, the match would +fail. Special code exists to check that the match failed because a +skolemized type could not be unified with another kind of type -- this is +not considered a definitive failure, but rather an ambiguous result, +since if the type variable were later to be unified with int, then this +obligation could be resolved then. + +*Note:* Currently, method matching does not use the trait resolution +code, so if you in fact type in the example above, it may +compile. Hopefully this will be fixed in later patches. + +#### Matching + +The subroutines that decide whether a particular impl/where-clause/etc +applies to a particular obligation. At the moment, this amounts to +unifying the self types, but in the future we may also recursively +consider some of the nested obligations, in the case of an impl. + +#### Lifetimes and selection + +Because of how that lifetime inference works, it is not possible to +give back immediate feedback as to whether a unification or subtype +relationship between lifetimes holds or not. Therefore, lifetime +matching is *not* considered during selection. This is achieved by +having the skolemization process just replace *ALL* lifetimes with +`'static`. Later, during confirmation, the non-skolemized self-type +will be unified with the type from the impl (or whatever). This may +yield lifetime constraints that will later be found to be in error (in +contrast, the non-lifetime-constraints have already been checked +during selection and can never cause an error, though naturally they +may lead to other errors downstream). + +#### Where clauses + +Besides an impl, the other major way to resolve an obligation is via a +where clause. The selection process is always given a *parameter +environment* which contains a list of where clauses, which are +basically obligations that can assume are satisfiable. We will iterate +over that list and check whether our current obligation can be found +in that list, and if so it is considered satisfied. More precisely, we +want to check whether there is a where-clause obligation that is for +the same trait (or some subtrait) and for which the self types match, +using the definition of *matching* given above. + +Consider this simple example: + + trait A1 { ... } + trait A2 : A1 { ... } + + trait B { ... } + + fn foo { ... } + +Clearly we can use methods offered by `A1`, `A2`, or `B` within the +body of `foo`. In each case, that will incur an obligation like `X : +A1` or `X : A2`. The parameter environment will contain two +where-clauses, `X : A2` and `X : B`. For each obligation, then, we +search this list of where-clauses. To resolve an obligation `X:A1`, +we would note that `X:A2` implies that `X:A1`. + +### Confirmation + +Confirmation unifies the output type parameters of the trait with the +values found in the obligation, possibly yielding a type error. If we +return to our example of the `Convert` trait from the previous +section, confirmation is where an error would be reported, because the +impl specified that `T` would be `uint`, but the obligation reported +`char`. Hence the result of selection would be an error. + +### Selection during translation + +During type checking, we do not store the results of trait selection. +We simply wish to verify that trait selection will succeed. Then +later, at trans time, when we have all concrete types available, we +can repeat the trait selection. In this case, we do not consider any +where-clauses to be in scope. We know that therefore each resolution +will resolve to a particular impl. + +One interesting twist has to do with nested obligations. In general, in trans, +we only need to do a "shallow" selection for an obligation. That is, we wish to +identify which impl applies, but we do not (yet) need to decide how to select +any nested obligations. Nonetheless, we *do* currently do a complete resolution, +and that is because it can sometimes inform the results of type inference. That is, +we do not have the full substitutions in terms of the type varibales of the impl available +to us, so we must run trait selection to figure everything out. + +Here is an example: + + trait Foo { ... } + impl> Foo for Vec { ... } + + impl Bar for int { ... } + +After one shallow round of selection for an obligation like `Vec +: Foo`, we would know which impl we want, and we would know that +`T=int`, but we do not know the type of `U`. We must select the +nested obligation `int : Bar` to find out that `U=uint`. + +It would be good to only do *just as much* nested resolution as +necessary. Currently, though, we just do a full resolution. + +*/ diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs new file mode 100644 index 0000000000000..78d105c251edb --- /dev/null +++ b/src/librustc/middle/traits/fulfill.rs @@ -0,0 +1,250 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use middle::ty; +use middle::typeck::infer::{InferCtxt, skolemize}; +use util::nodemap::DefIdMap; +use util::ppaux::Repr; + +use super::Ambiguity; +use super::Obligation; +use super::FulfillmentError; +use super::SelectionError; +use super::select::SelectionContext; +use super::Unimplemented; + +/** + * The fulfillment context is used to drive trait resolution. It + * consists of a list of obligations that must be (eventually) + * satisfied. The job is to track which are satisfied, which yielded + * errors, and which are still pending. At any point, users can call + * `select_where_possible`, and the fulfilment context will try to do + * selection, retaining only those obligations that remain + * ambiguous. This may be helpful in pushing type inference + * along. Once all type inference constraints have been generated, the + * method `select_all_or_error` can be used to report any remaining + * ambiguous cases as errors. + */ +pub struct FulfillmentContext { + // A list of all obligations that have been registered with this + // fulfillment context. + trait_obligations: Vec, + + // For semi-hacky reasons (see FIXME below) we keep the builtin + // trait obligations segregated. + builtin_obligations: Vec, +} + +impl FulfillmentContext { + pub fn new() -> FulfillmentContext { + FulfillmentContext { + trait_obligations: Vec::new(), + builtin_obligations: Vec::new() + } + } + + pub fn register_obligation(&mut self, + tcx: &ty::ctxt, + obligation: Obligation) + { + debug!("register_obligation({})", obligation.repr(tcx)); + match tcx.lang_items.to_builtin_kind(obligation.trait_ref.def_id) { + Some(_) => { + self.builtin_obligations.push(obligation); + } + None => { + self.trait_obligations.push(obligation); + } + } + } + + pub fn select_all_or_error(&mut self, + infcx: &InferCtxt, + param_env: &ty::ParameterEnvironment, + unboxed_closures: &DefIdMap) + -> Result<(),Vec> + { + try!(self.select_where_possible(infcx, param_env, + unboxed_closures)); + + // Anything left is ambiguous. + let errors: Vec = + self.trait_obligations + .iter() + .map(|o| FulfillmentError::new((*o).clone(), Ambiguity)) + .collect(); + + if errors.is_empty() { + Ok(()) + } else { + Err(errors) + } + } + + pub fn select_where_possible(&mut self, + infcx: &InferCtxt, + param_env: &ty::ParameterEnvironment, + unboxed_closures: &DefIdMap) + -> Result<(),Vec> + { + let tcx = infcx.tcx; + let selcx = SelectionContext::new(infcx, param_env, + unboxed_closures); + + debug!("select_where_possible({} obligations) start", + self.trait_obligations.len()); + + let mut errors = Vec::new(); + + loop { + let count = self.trait_obligations.len(); + + debug!("select_where_possible({} obligations) iteration", + count); + + let mut selections = Vec::new(); + + // First pass: walk each obligation, retaining + // only those that we cannot yet process. + self.trait_obligations.retain(|obligation| { + match selcx.select(obligation) { + Ok(None) => { + true + } + Ok(Some(s)) => { + selections.push(s); + false + } + Err(selection_err) => { + debug!("obligation: {} error: {}", + obligation.repr(tcx), + selection_err.repr(tcx)); + + errors.push(FulfillmentError::new( + (*obligation).clone(), + SelectionError(selection_err))); + false + } + } + }); + + if self.trait_obligations.len() == count { + // Nothing changed. + break; + } + + // Now go through all the successful ones, + // registering any nested obligations for the future. + for selection in selections.move_iter() { + selection.map_move_nested( + |o| self.register_obligation(tcx, o)); + } + } + + debug!("select_where_possible({} obligations, {} errors) done", + self.trait_obligations.len(), + errors.len()); + + if errors.len() == 0 { + Ok(()) + } else { + Err(errors) + } + } + + pub fn check_builtin_bound_obligations( + &self, + infcx: &InferCtxt) + -> Result<(),Vec> + { + let tcx = infcx.tcx; + let mut errors = Vec::new(); + debug!("check_builtin_bound_obligations"); + for obligation in self.builtin_obligations.iter() { + debug!("obligation={}", obligation.repr(tcx)); + + let def_id = obligation.trait_ref.def_id; + let bound = match tcx.lang_items.to_builtin_kind(def_id) { + Some(bound) => { bound } + None => { continue; } + }; + + let unskol_self_ty = obligation.self_ty(); + + // Skolemize the self-type so that it no longer contains + // inference variables. Note that this also replaces + // regions with 'static. You might think that this is not + // ok, because checking whether something is `Send` + // implies checking whether it is 'static: that's true, + // but in fact the region bound is fed into region + // inference separately and enforced there (and that has + // even already been done before this code executes, + // generally speaking). + let self_ty = skolemize(infcx, unskol_self_ty); + + debug!("bound={} self_ty={}", bound, self_ty.repr(tcx)); + if ty::type_is_error(self_ty) { + // Indicates an error that was/will-be + // reported elsewhere. + continue; + } + + // Determine if builtin bound is met. + let tc = ty::type_contents(tcx, self_ty); + debug!("tc={}", tc); + let met = match bound { + ty::BoundSend => tc.is_sendable(tcx), + ty::BoundSized => tc.is_sized(tcx), + ty::BoundCopy => tc.is_copy(tcx), + ty::BoundSync => tc.is_sync(tcx), + }; + + if met { + continue; + } + + // FIXME -- This is kind of a hack: it requently happens + // that some earlier error prevents types from being fully + // inferred, and then we get a bunch of uninteresting + // errors saying something like " doesn't + // implement Sized". It may even be true that we could + // just skip over all checks where the self-ty is an + // inference variable, but I was afraid that there might + // be an inference variable created, registered as an + // obligation, and then never forced by writeback, and + // hence by skipping here we'd be ignoring the fact that + // we don't KNOW the type works out. Though even that + // would probably be harmless, given that we're only + // talking about builtin traits, which are known to be + // inhabited. But in any case I just threw in this check + // for has_errors() to be sure that compilation isn't + // happening anyway. In that case, why inundate the user. + if ty::type_needs_infer(self_ty) && + tcx.sess.has_errors() + { + debug!("skipping printout because self_ty={}", + self_ty.repr(tcx)); + continue; + } + + errors.push( + FulfillmentError::new( + (*obligation).clone(), + SelectionError(Unimplemented))); + } + + if errors.is_empty() { + Ok(()) + } else { + Err(errors) + } + } +} + diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs new file mode 100644 index 0000000000000..62b3c982ccd0a --- /dev/null +++ b/src/librustc/middle/traits/mod.rs @@ -0,0 +1,438 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! + * Trait Resolution. See doc.rs. + */ + +use middle::subst; +use middle::ty; +use middle::typeck::infer::InferCtxt; +use std::rc::Rc; +use syntax::ast; +use syntax::codemap::{Span, DUMMY_SP}; +use util::nodemap::DefIdMap; + +pub use self::fulfill::FulfillmentContext; +pub use self::select::SelectionContext; +pub use self::util::supertraits; +pub use self::util::transitive_bounds; +pub use self::util::Supertraits; +pub use self::util::search_trait_and_supertraits_from_bound; + +mod coherence; +mod fulfill; +mod select; +mod util; + +/** + * An `Obligation` represents some trait reference (e.g. `int:Eq`) for + * which the vtable must be found. The process of finding a vtable is + * called "resolving" the `Obligation`. This process consists of + * either identifying an `impl` (e.g., `impl Eq for int`) that + * provides the required vtable, or else finding a bound that is in + * scope. The eventual result is usually a `Selection` (defined below). + */ +#[deriving(Clone)] +pub struct Obligation { + pub cause: ObligationCause, + pub recursion_depth: uint, + pub trait_ref: Rc, +} + +/** + * Why did we incur this obligation? Used for error reporting. + */ +#[deriving(Clone)] +pub struct ObligationCause { + pub span: Span, + pub code: ObligationCauseCode +} + +#[deriving(Clone)] +pub enum ObligationCauseCode { + /// Not well classified or should be obvious from span. + MiscObligation, + + /// In an impl of trait X for type Y, type Y must + /// also implement all supertraits of X. + ItemObligation(ast::DefId), + + /// Obligation incurred due to an object cast. + ObjectCastObligation(/* Object type */ ty::t), + + /// Various cases where expressions must be sized/copy/etc: + AssignmentLhsSized, // L = X implies that L is Sized + StructInitializerSized, // S { ... } must be Sized + VariableType(ast::NodeId), // Type of each variable must be Sized + RepeatVec, // [T,..n] --> T must be Copy +} + +pub static DUMMY_CAUSE: ObligationCause = + ObligationCause { span: DUMMY_SP, + code: MiscObligation }; + +pub type Obligations = subst::VecPerParamSpace; + +pub type Selection = Vtable; + +#[deriving(Clone,Show)] +pub enum SelectionError { + Unimplemented, + Overflow, + OutputTypeParameterMismatch(Rc, ty::type_err) +} + +pub struct FulfillmentError { + pub obligation: Obligation, + pub code: FulfillmentErrorCode +} + +#[deriving(Clone)] +pub enum FulfillmentErrorCode { + SelectionError(SelectionError), + Ambiguity, +} + +/** + * When performing resolution, it is typically the case that there + * can be one of three outcomes: + * + * - `Ok(Some(r))`: success occurred with result `r` + * - `Ok(None)`: could not definitely determine anything, usually due + * to inconclusive type inference. + * - `Err(e)`: error `e` occurred + */ +pub type SelectionResult = Result,SelectionError>; + +#[deriving(PartialEq,Eq,Show)] +pub enum EvaluationResult { + EvaluatedToMatch, + EvaluatedToAmbiguity, + EvaluatedToUnmatch +} + +/** + * Given the successful resolution of an obligation, the `Vtable` + * indicates where the vtable comes from. Note that while we call this + * a "vtable", it does not necessarily indicate dynamic dispatch at + * runtime. `Vtable` instances just tell the compiler where to find + * methods, but in generic code those methods are typically statically + * dispatched -- only when an object is constructed is a `Vtable` + * instance reified into an actual vtable. + * + * For example, the vtable may be tied to a specific impl (case A), + * or it may be relative to some bound that is in scope (case B). + * + * + * ``` + * impl Clone for Option { ... } // Impl_1 + * impl Clone for Box { ... } // Impl_2 + * impl Clone for int { ... } // Impl_3 + * + * fn foo(concrete: Option>, + * param: T, + * mixed: Option) { + * + * // Case A: Vtable points at a specific impl. Only possible when + * // type is concretely known. If the impl itself has bounded + * // type parameters, Vtable will carry resolutions for those as well: + * concrete.clone(); // Vtable(Impl_1, [Vtable(Impl_2, [Vtable(Impl_3)])]) + * + * // Case B: Vtable must be provided by caller. This applies when + * // type is a type parameter. + * param.clone(); // VtableParam(Oblig_1) + * + * // Case C: A mix of cases A and B. + * mixed.clone(); // Vtable(Impl_1, [VtableParam(Oblig_1)]) + * } + * ``` + * + * ### The type parameter `N` + * + * See explanation on `VtableImpl`. + */ +#[deriving(Show,Clone)] +pub enum Vtable { + /// Vtable identifying a particular impl. + VtableImpl(VtableImpl), + + /// Vtable automatically generated for an unboxed closure. The def + /// ID is the ID of the closure expression. This is a `VtableImpl` + /// in spirit, but the impl is generated by the compiler and does + /// not appear in the source. + VtableUnboxedClosure(ast::DefId), + + /// Successful resolution to an obligation provided by the caller + /// for some type parameter. + VtableParam(VtableParam), + + /// Successful resolution for a builtin trait. + VtableBuiltin, +} + +/** + * Identifies a particular impl in the source, along with a set of + * substitutions from the impl's type/lifetime parameters. The + * `nested` vector corresponds to the nested obligations attached to + * the impl's type parameters. + * + * The type parameter `N` indicates the type used for "nested + * obligations" that are required by the impl. During type check, this + * is `Obligation`, as one might expect. During trans, however, this + * is `()`, because trans only requires a shallow resolution of an + * impl, and nested obligations are satisfied later. + */ +#[deriving(Clone)] +pub struct VtableImpl { + pub impl_def_id: ast::DefId, + pub substs: subst::Substs, + pub nested: subst::VecPerParamSpace +} + +/** + * A vtable provided as a parameter by the caller. For example, in a + * function like `fn foo(...)`, if the `eq()` method is invoked + * on an instance of `T`, the vtable would be of type `VtableParam`. + */ +#[deriving(Clone)] +pub struct VtableParam { + // In the above example, this would `Eq` + pub bound: Rc, +} + +pub fn try_select_obligation(infcx: &InferCtxt, + param_env: &ty::ParameterEnvironment, + unboxed_closures: &DefIdMap, + obligation: &Obligation) + -> SelectionResult +{ + /*! + * Attempts to select the impl/bound/etc for the obligation + * given. Returns `None` if we are unable to resolve, either + * because of ambiguity or due to insufficient inference. Note + * that selection is a shallow process and hence the result may + * contain nested obligations that must be resolved. The caller is + * responsible for ensuring that those get resolved. (But see + * `try_select_obligation_deep` below.) + */ + + let selcx = select::SelectionContext::new(infcx, param_env, unboxed_closures); + selcx.select(obligation) +} + +pub fn evaluate_obligation(infcx: &InferCtxt, + param_env: &ty::ParameterEnvironment, + obligation: &Obligation, + unboxed_closures: &DefIdMap) + -> EvaluationResult +{ + /*! + * Attempts to resolve the obligation given. Returns `None` if + * we are unable to resolve, either because of ambiguity or + * due to insufficient inference. + */ + + let selcx = select::SelectionContext::new(infcx, param_env, + unboxed_closures); + selcx.evaluate_obligation(obligation) +} + +pub fn evaluate_impl(infcx: &InferCtxt, + param_env: &ty::ParameterEnvironment, + unboxed_closures: &DefIdMap, + cause: ObligationCause, + impl_def_id: ast::DefId, + self_ty: ty::t) + -> EvaluationResult +{ + /*! + * Tests whether the impl `impl_def_id` can be applied to the self + * type `self_ty`. This is similar to "selection", but simpler: + * + * - It does not take a full trait-ref as input, so it skips over + * the "confirmation" step which would reconcile output type + * parameters. + * - It returns an `EvaluationResult`, which is a tri-value return + * (yes/no/unknown). + */ + + let selcx = select::SelectionContext::new(infcx, param_env, unboxed_closures); + selcx.evaluate_impl(impl_def_id, cause, self_ty) +} + +pub fn select_inherent_impl(infcx: &InferCtxt, + param_env: &ty::ParameterEnvironment, + unboxed_closures: &DefIdMap, + cause: ObligationCause, + impl_def_id: ast::DefId, + self_ty: ty::t) + -> SelectionResult> +{ + /*! + * Matches the self type of the inherent impl `impl_def_id` + * against `self_ty` and returns the resulting resolution. This + * routine may modify the surrounding type context (for example, + * it may unify variables). + */ + + // This routine is only suitable for inherent impls. This is + // because it does not attempt to unify the output type parameters + // from the trait ref against the values from the obligation. + // (These things do not apply to inherent impls, for which there + // is no trait ref nor obligation.) + // + // Matching against non-inherent impls should be done with + // `try_resolve_obligation()`. + assert!(ty::impl_trait_ref(infcx.tcx, impl_def_id).is_none()); + + let selcx = select::SelectionContext::new(infcx, param_env, + unboxed_closures); + selcx.select_inherent_impl(impl_def_id, cause, self_ty) +} + +pub fn is_orphan_impl(tcx: &ty::ctxt, + impl_def_id: ast::DefId) + -> bool +{ + /*! + * True if neither the trait nor self type is local. Note that + * `impl_def_id` must refer to an impl of a trait, not an inherent + * impl. + */ + + !coherence::impl_is_local(tcx, impl_def_id) +} + +pub fn overlapping_impls(infcx: &InferCtxt, + impl1_def_id: ast::DefId, + impl2_def_id: ast::DefId) + -> bool +{ + /*! + * True if there exist types that satisfy both of the two given impls. + */ + + coherence::impl_can_satisfy(infcx, impl1_def_id, impl2_def_id) && + coherence::impl_can_satisfy(infcx, impl2_def_id, impl1_def_id) +} + +pub fn obligations_for_generics(tcx: &ty::ctxt, + cause: ObligationCause, + generics: &ty::Generics, + substs: &subst::Substs) + -> subst::VecPerParamSpace +{ + /*! + * Given generics for an impl like: + * + * impl ... + * + * and a substs vector like ``, yields a result like + * + * [[Foo for A0, Bar for B0, Qux for B0], [], []] + */ + + util::obligations_for_generics(tcx, cause, 0, generics, substs) +} + +pub fn obligation_for_builtin_bound(tcx: &ty::ctxt, + cause: ObligationCause, + source_ty: ty::t, + builtin_bound: ty::BuiltinBound) + -> Obligation +{ + util::obligation_for_builtin_bound(tcx, cause, builtin_bound, 0, source_ty) +} + +impl Obligation { + pub fn new(cause: ObligationCause, trait_ref: Rc) -> Obligation { + Obligation { cause: cause, + recursion_depth: 0, + trait_ref: trait_ref } + } + + pub fn misc(span: Span, trait_ref: Rc) -> Obligation { + Obligation::new(ObligationCause::misc(span), trait_ref) + } + + pub fn self_ty(&self) -> ty::t { + self.trait_ref.self_ty() + } +} + +impl ObligationCause { + pub fn new(span: Span, code: ObligationCauseCode) -> ObligationCause { + ObligationCause { span: span, code: code } + } + + pub fn misc(span: Span) -> ObligationCause { + ObligationCause { span: span, code: MiscObligation } + } +} + +impl Vtable { + pub fn map_nested(&self, op: |&N| -> M) -> Vtable { + match *self { + VtableImpl(ref i) => VtableImpl(i.map_nested(op)), + VtableUnboxedClosure(d) => VtableUnboxedClosure(d), + VtableParam(ref p) => VtableParam((*p).clone()), + VtableBuiltin => VtableBuiltin, + } + } + + pub fn map_move_nested(self, op: |N| -> M) -> Vtable { + match self { + VtableImpl(i) => VtableImpl(i.map_move_nested(op)), + VtableUnboxedClosure(d) => VtableUnboxedClosure(d), + VtableParam(p) => VtableParam(p), + VtableBuiltin => VtableBuiltin, + } + } +} + +impl VtableImpl { + pub fn map_nested(&self, + op: |&N| -> M) + -> VtableImpl + { + VtableImpl { + impl_def_id: self.impl_def_id, + substs: self.substs.clone(), + nested: self.nested.map(op) + } + } + + pub fn map_move_nested(self, op: |N| -> M) -> VtableImpl { + let VtableImpl { impl_def_id, substs, nested } = self; + VtableImpl { + impl_def_id: impl_def_id, + substs: substs, + nested: nested.map_move(op) + } + } +} + +impl EvaluationResult { + pub fn potentially_applicable(&self) -> bool { + match *self { + EvaluatedToMatch | EvaluatedToAmbiguity => true, + EvaluatedToUnmatch => false + } + } +} + +impl FulfillmentError { + fn new(obligation: Obligation, code: FulfillmentErrorCode) + -> FulfillmentError + { + FulfillmentError { obligation: obligation, code: code } + } +} diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs new file mode 100644 index 0000000000000..681e2650f39fa --- /dev/null +++ b/src/librustc/middle/traits/select.rs @@ -0,0 +1,1024 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! See `doc.rs` for high-level documentation */ + +use super::{Obligation, ObligationCause}; +use super::{EvaluationResult, EvaluatedToMatch, + EvaluatedToAmbiguity, EvaluatedToUnmatch}; +use super::{SelectionError, Unimplemented, Overflow, + OutputTypeParameterMismatch}; +use super::{Selection}; +use super::{SelectionResult}; +use super::{VtableBuiltin, VtableImpl, VtableParam, VtableUnboxedClosure}; +use super::{util}; + +use middle::subst::{Subst, Substs, VecPerParamSpace}; +use middle::ty; +use middle::typeck::check::regionmanip; +use middle::typeck::infer; +use middle::typeck::infer::InferCtxt; +use std::rc::Rc; +use syntax::ast; +use util::nodemap::DefIdMap; +use util::ppaux::Repr; + +pub struct SelectionContext<'cx, 'tcx:'cx> { + infcx: &'cx InferCtxt<'cx, 'tcx>, + param_env: &'cx ty::ParameterEnvironment, + unboxed_closures: &'cx DefIdMap, +} + +// pub struct SelectionCache { +// hashmap: RefCell>, +// } + +// #[deriving(Hash,Eq,PartialEq)] +// struct CacheKey { +// trait_def_id: ast::DefId, +// skol_obligation_self_ty: ty::t, +// } + +enum MatchResult { + Matched(T), + AmbiguousMatch, + NoMatch +} + +/** + * The selection process begins by considering all impls, where + * clauses, and so forth that might resolve an obligation. Sometimes + * we'll be able to say definitively that (e.g.) an impl does not + * apply to the obligation: perhaps it is defined for `uint` but the + * obligation is for `int`. In that case, we drop the impl out of the + * list. But the other cases are considered *candidates*. + * + * Candidates can either be definitive or ambiguous. An ambiguous + * 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 + * 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 + * trait (that is, an impl applied to all T), and a type parameter + * with a where clause. In that case, we can have a candidate from the + * where clause and a second candidate from the impl. This is not a + * problem because coherence guarantees us that the impl which would + * be used to satisfy the where clause is the same one that we see + * now. To resolve this issue, therefore, we ignore impls if we find a + * matching where clause. Part of the reason for this is that where + * clauses can give additional information (like, the types of output + * parameters) that would have to be inferred from the impl. + */ +#[deriving(Clone)] +enum Candidate { + MatchedBuiltinCandidate, + AmbiguousBuiltinCandidate, + MatchedParamCandidate(VtableParam), + AmbiguousParamCandidate, + Impl(ImplCandidate), + MatchedUnboxedClosureCandidate(/* closure */ ast::DefId) +} + +#[deriving(Clone)] +enum ImplCandidate { + MatchedImplCandidate(ast::DefId), + AmbiguousImplCandidate(ast::DefId), +} + +impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { + pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>, + param_env: &'cx ty::ParameterEnvironment, + unboxed_closures: &'cx DefIdMap) + -> SelectionContext<'cx, 'tcx> { + SelectionContext { infcx: infcx, param_env: param_env, + unboxed_closures: unboxed_closures } + } + + pub fn tcx(&self) -> &'cx ty::ctxt<'tcx> { + self.infcx.tcx + } + + /////////////////////////////////////////////////////////////////////////// + // Selection + // + // The selection phase tries to identify *how* an obligation will + // be resolved. For example, it will identify which impl or + // parameter bound is to be used. The process can be inconclusive + // if the self type in the obligation is not fully inferred. Selection + // can result in an error in one of two ways: + // + // 1. If no applicable impl or parameter bound can be found. + // 2. If the output type parameters in the obligation do not match + // those specified by the impl/bound. For example, if the obligation + // is `Vec:Iterable`, but the impl specifies + // `impl Iterable for Vec`, than an error would result. + + pub fn select(&self, obligation: &Obligation) -> SelectionResult { + /*! + * Evaluates whether the obligation can be satisfied. Returns + * an indication of whether the obligation can be satisfied + * and, if so, by what means. Never affects surrounding typing + * environment. + */ + + debug!("select({})", obligation.repr(self.tcx())); + + match try!(self.candidate_from_obligation(obligation)) { + None => Ok(None), + Some(candidate) => self.confirm_candidate(obligation, candidate), + } + } + + pub fn select_inherent_impl(&self, + impl_def_id: ast::DefId, + obligation_cause: ObligationCause, + obligation_self_ty: ty::t) + -> SelectionResult> + { + debug!("select_inherent_impl(impl_def_id={}, obligation_self_ty={})", + impl_def_id.repr(self.tcx()), + obligation_self_ty.repr(self.tcx())); + + match self.candidate_from_impl(impl_def_id, + obligation_cause, + obligation_self_ty) { + Some(MatchedImplCandidate(impl_def_id)) => { + let vtable_impl = + try!(self.confirm_inherent_impl_candidate( + impl_def_id, + obligation_cause, + obligation_self_ty, + 0)); + Ok(Some(vtable_impl)) + } + Some(AmbiguousImplCandidate(_)) => { + Ok(None) + } + None => { + Err(Unimplemented) + } + } + } + + /////////////////////////////////////////////////////////////////////////// + // EVALUATION + // + // Tests whether an obligation can be selected or whether an impl can be + // applied to particular types. It skips the "confirmation" step and + // hence completely ignores output type parameters. + + pub fn evaluate_obligation(&self, + obligation: &Obligation) + -> EvaluationResult + { + /*! + * Evaluates whether the obligation `obligation` can be + * satisfied (by any means). + */ + + debug!("evaluate_obligation({})", + obligation.repr(self.tcx())); + + match self.candidate_from_obligation(obligation) { + Ok(Some(c)) => c.to_evaluation_result(), + Ok(None) => EvaluatedToAmbiguity, + Err(_) => EvaluatedToUnmatch, + } + } + + pub fn evaluate_impl(&self, + impl_def_id: ast::DefId, + obligation_cause: ObligationCause, + obligation_self_ty: ty::t) + -> EvaluationResult + { + /*! + * Evaluates whether the impl with id `impl_def_id` could be + * applied to the self type `obligation_self_ty`. This can be + * used either for trait or inherent impls. + */ + + debug!("evaluate_impl(impl_def_id={}, obligation_self_ty={})", + impl_def_id.repr(self.tcx()), + obligation_self_ty.repr(self.tcx())); + + match self.candidate_from_impl(impl_def_id, + obligation_cause, + obligation_self_ty) { + Some(c) => c.to_evaluation_result(), + None => EvaluatedToUnmatch, + } + } + + /////////////////////////////////////////////////////////////////////////// + // CANDIDATE ASSEMBLY + // + // The selection process begins by examining all in-scope impls, + // caller obligations, and so forth and assembling a list of + // candidates. See `doc.rs` and the `Candidate` type for more details. + + fn candidate_from_obligation(&self, obligation: &Obligation) + -> SelectionResult + { + debug!("candidate_from_obligation({}, self_ty={})", + obligation.repr(self.tcx()), + self.infcx.ty_to_string(obligation.self_ty())); + + let skol_obligation_self_ty = + infer::skolemize(self.infcx, obligation.self_ty()); + + // First, check the cache. + match self.check_candidate_cache(obligation, skol_obligation_self_ty) { + Some(c) => { + return Ok(Some(c)); + } + None => { } + } + + let mut candidates = + try!(self.assemble_candidates(obligation, + skol_obligation_self_ty)); + + debug!("candidate_from_obligation: {} candidates for {}", + candidates.len(), obligation.repr(self.tcx())); + + // Examine candidates to determine outcome. Ideally we will + // have exactly one candidate that is definitively applicable. + + if candidates.len() == 0 { + // Annoying edge case: if there are no impls, then there + // is no way that this trait reference is implemented, + // *unless* it contains unbound variables. In that case, + // it is possible that one of those unbound variables will + // be bound to a new type from some other crate which will + // also contain impls. + let trait_ref = &*obligation.trait_ref; + return if !self.trait_ref_unconstrained(trait_ref) { + debug!("candidate_from_obligation({}) -> 0 matches, unimpl", + obligation.repr(self.tcx())); + Err(Unimplemented) + } else { + debug!("candidate_from_obligation({}) -> 0 matches, ambig", + obligation.repr(self.tcx())); + Ok(None) + }; + } + + if candidates.len() > 1 { + // Ambiguity. Possibly we should report back more + // information on the potential candidates so we can give + // a better error message. + debug!("candidate_from_obligation({}) -> multiple matches, ambig", + obligation.repr(self.tcx())); + + return Ok(None); + } + + let candidate = candidates.pop().unwrap(); + self.insert_candidate_cache(obligation, skol_obligation_self_ty, + candidate.clone()); + Ok(Some(candidate)) + } + + fn check_candidate_cache(&self, + _obligation: &Obligation, + _skol_obligation_self_ty: ty::t) + -> Option + { + // let cache_key = CacheKey::new(obligation.trait_ref.def_id, + // skol_obligation_self_ty); + // let hashmap = self.tcx().selection_cache.hashmap.borrow(); + // hashmap.find(&cache_key).map(|c| (*c).clone()) + None + } + + fn insert_candidate_cache(&self, + _obligation: &Obligation, + _skol_obligation_self_ty: ty::t, + _candidate: Candidate) + { + // FIXME -- Enable caching. I think the right place to put the cache + // is in the ParameterEnvironment, not the tcx, because otherwise + // when there are distinct where clauses in scope the cache can get + // confused. + // + //let cache_key = CacheKey::new(obligation.trait_ref.def_id, + // skol_obligation_self_ty); + //let mut hashmap = self.tcx().selection_cache.hashmap.borrow_mut(); + //hashmap.insert(cache_key, candidate); + } + + fn assemble_candidates(&self, + obligation: &Obligation, + skol_obligation_self_ty: ty::t) + -> Result, SelectionError> + { + // Check for overflow. + + let recursion_limit = self.infcx.tcx.sess.recursion_limit.get(); + if obligation.recursion_depth >= recursion_limit { + debug!("{} --> overflow", obligation.repr(self.tcx())); + return Err(Overflow); + } + + let mut candidates = Vec::new(); + + match self.tcx().lang_items.to_builtin_kind(obligation.trait_ref.def_id) { + Some(_) => { + // FIXME -- The treatment of builtin bounds is a bit + // hacky right now. Eventually, the idea is to move + // the logic for selection out of type_contents and + // into this module (And make it based on the generic + // mechanisms of OIBTT2). However, I want to land + // some code today, so we're going to cut a few + // corners. What we do now is that the trait selection + // code always considers builtin obligations to + // match. The fulfillment code (which also has the job + // of tracking all the traits that must hold) will + // then just accumulate the various + // builtin-bound-related obligations that must be met. + // Later, at the end of typeck, after writeback etc, + // we will rewalk this list and extract all the + // builtin-bound-related obligations and test them + // again using type contents. Part of the motivation + // for this is that the type contents code requires + // that writeback has been completed in some cases. + + candidates.push(AmbiguousBuiltinCandidate); + } + + None => { + // Other bounds. Consider both in-scope bounds from fn decl + // and applicable impls. + + try!(self.assemble_candidates_from_caller_bounds( + obligation, + skol_obligation_self_ty, + &mut candidates)); + + try!(self.assemble_unboxed_candidates( + obligation, + skol_obligation_self_ty, + &mut candidates)); + + // If there is a fn bound that applies, forego the + // impl search. It can only generate conflicts. + + if candidates.len() == 0 { + try!(self.assemble_candidates_from_impls( + obligation, + skol_obligation_self_ty, + &mut candidates)); + } + } + } + + Ok(candidates) + } + + fn assemble_candidates_from_caller_bounds(&self, + obligation: &Obligation, + skol_obligation_self_ty: ty::t, + candidates: &mut Vec) + -> Result<(),SelectionError> + { + /*! + * Given an obligation like ``, search the obligations + * that the caller supplied to find out whether it is listed among + * them. + * + * Never affects inference environment. +v */ + + debug!("assemble_candidates_from_caller_bounds({})", + obligation.repr(self.tcx())); + + for caller_obligation in self.param_env.caller_obligations.iter() { + debug!("caller_obligation={}", + caller_obligation.repr(self.tcx())); + + // Skip over obligations that don't apply to + // `self_ty`. + let caller_bound = &caller_obligation.trait_ref; + let caller_self_ty = caller_bound.substs.self_ty().unwrap(); + match self.match_self_types(obligation.cause, + caller_self_ty, + skol_obligation_self_ty) { + AmbiguousMatch => { + debug!("-> AmbiguousParamCandidate"); + candidates.push(AmbiguousParamCandidate); + return Ok(()); + } + NoMatch => { + continue; + } + Matched(()) => { } + } + + // Search through the trait (and its supertraits) to + // see if it matches the def-id we are looking for. + let caller_bound = (*caller_bound).clone(); + match util::search_trait_and_supertraits_from_bound( + self.infcx.tcx, caller_bound, + |d| d == obligation.trait_ref.def_id) + { + Some(vtable_param) => { + // If so, we're done! + debug!("-> MatchedParamCandidate({})", vtable_param); + candidates.push(MatchedParamCandidate(vtable_param)); + return Ok(()); + } + + None => { + } + } + } + + Ok(()) + } + + fn assemble_unboxed_candidates(&self, + obligation: &Obligation, + skol_obligation_self_ty: ty::t, + candidates: &mut Vec) + -> Result<(),SelectionError> + { + /*! + * Check for the artificial impl that the compiler will create + * for an obligation like `X : FnMut<..>` where `X` is an + * unboxed closure type. + */ + + let closure_def_id = match ty::get(skol_obligation_self_ty).sty { + ty::ty_unboxed_closure(id, _) => id, + _ => { return Ok(()); } + }; + + let tcx = self.tcx(); + let fn_traits = [ + (ty::FnUnboxedClosureKind, tcx.lang_items.fn_trait()), + (ty::FnMutUnboxedClosureKind, tcx.lang_items.fn_mut_trait()), + (ty::FnOnceUnboxedClosureKind, tcx.lang_items.fn_once_trait()), + ]; + for tuple in fn_traits.iter() { + let kind = match tuple { + &(kind, Some(ref fn_trait)) + if *fn_trait == obligation.trait_ref.def_id => + { + kind + } + _ => continue, + }; + + // Check to see whether the argument and return types match. + let closure_kind = match self.unboxed_closures.find(&closure_def_id) { + Some(closure) => closure.kind, + None => { + self.tcx().sess.span_bug( + obligation.cause.span, + format!("No entry for unboxed closure: {}", + closure_def_id.repr(self.tcx())).as_slice()); + } + }; + + if closure_kind != kind { + continue; + } + + candidates.push(MatchedUnboxedClosureCandidate(closure_def_id)); + } + + Ok(()) + } + + fn assemble_candidates_from_impls(&self, + obligation: &Obligation, + skol_obligation_self_ty: ty::t, + candidates: &mut Vec) + -> Result<(), SelectionError> + { + /*! + * Search for impls that might apply to `obligation`. + */ + + let all_impls = self.all_impls(obligation.trait_ref.def_id); + for &impl_def_id in all_impls.iter() { + self.infcx.probe(|| { + match self.candidate_from_impl(impl_def_id, + obligation.cause, + skol_obligation_self_ty) { + Some(c) => { + candidates.push(Impl(c)); + } + + None => { } + } + }); + } + Ok(()) + } + + fn candidate_from_impl(&self, + impl_def_id: ast::DefId, + obligation_cause: ObligationCause, + skol_obligation_self_ty: ty::t) + -> Option + { + match self.match_impl_self_types(impl_def_id, + obligation_cause, + skol_obligation_self_ty) { + Matched(_) => { + Some(MatchedImplCandidate(impl_def_id)) + } + + AmbiguousMatch => { + Some(AmbiguousImplCandidate(impl_def_id)) + } + + NoMatch => { + None + } + } + } + + /////////////////////////////////////////////////////////////////////////// + // CONFIRMATION + // + // Confirmation unifies the output type parameters of the trait + // with the values found in the obligation, possibly yielding a + // type error. See `doc.rs` for more details. + + fn confirm_candidate(&self, + obligation: &Obligation, + candidate: Candidate) + -> SelectionResult + { + debug!("confirm_candidate({}, {})", + obligation.repr(self.tcx()), + candidate.repr(self.tcx())); + + match candidate { + AmbiguousBuiltinCandidate | + AmbiguousParamCandidate | + Impl(AmbiguousImplCandidate(_)) => { + Ok(None) + } + + MatchedBuiltinCandidate => { + Ok(Some(VtableBuiltin)) + } + + MatchedParamCandidate(param) => { + Ok(Some(VtableParam( + try!(self.confirm_param_candidate(obligation, param))))) + } + + Impl(MatchedImplCandidate(impl_def_id)) => { + let vtable_impl = try!(self.confirm_impl_candidate(obligation, + impl_def_id)); + Ok(Some(VtableImpl(vtable_impl))) + } + + MatchedUnboxedClosureCandidate(closure_def_id) => { + try!(self.confirm_unboxed_closure_candidate(obligation, closure_def_id)); + Ok(Some(VtableUnboxedClosure(closure_def_id))) + } + } + } + + fn confirm_param_candidate(&self, + obligation: &Obligation, + param: VtableParam) + -> Result + { + debug!("confirm_param_candidate({},{})", + obligation.repr(self.tcx()), + param.repr(self.tcx())); + + let () = try!(self.confirm(obligation.cause, + obligation.trait_ref.clone(), + param.bound.clone())); + Ok(param) + } + + fn confirm_impl_candidate(&self, + obligation: &Obligation, + impl_def_id: ast::DefId) + -> Result,SelectionError> + { + debug!("confirm_impl_candidate({},{})", + obligation.repr(self.tcx()), + impl_def_id.repr(self.tcx())); + + // For a non-inhernet impl, we begin the same way as an + // inherent impl, by matching the self-type and assembling + // list of nested obligations. + let vtable_impl = + try!(self.confirm_inherent_impl_candidate( + impl_def_id, + obligation.cause, + obligation.trait_ref.self_ty(), + obligation.recursion_depth)); + + // But then we must also match the output types. + let () = try!(self.confirm_impl_vtable(impl_def_id, + obligation.cause, + obligation.trait_ref.clone(), + &vtable_impl.substs)); + Ok(vtable_impl) + } + + fn confirm_inherent_impl_candidate(&self, + impl_def_id: ast::DefId, + obligation_cause: ObligationCause, + obligation_self_ty: ty::t, + obligation_recursion_depth: uint) + -> Result, + SelectionError> + { + let substs = match self.match_impl_self_types(impl_def_id, + obligation_cause, + obligation_self_ty) { + Matched(substs) => substs, + AmbiguousMatch | NoMatch => { + self.tcx().sess.bug( + format!("Impl {} was matchable against {} but now is not", + impl_def_id.repr(self.tcx()), + obligation_self_ty.repr(self.tcx())) + .as_slice()); + } + }; + + let impl_obligations = + self.impl_obligations(obligation_cause, + obligation_recursion_depth, + impl_def_id, + &substs); + let vtable_impl = VtableImpl { impl_def_id: impl_def_id, + substs: substs, + nested: impl_obligations }; + + Ok(vtable_impl) + } + + fn confirm_unboxed_closure_candidate(&self, + obligation: &Obligation, + closure_def_id: ast::DefId) + -> Result<(),SelectionError> + { + debug!("confirm_unboxed_closure_candidate({},{})", + obligation.repr(self.tcx()), + closure_def_id.repr(self.tcx())); + + let closure_type = match self.unboxed_closures.find(&closure_def_id) { + Some(closure) => closure.closure_type.clone(), + None => { + self.tcx().sess.span_bug( + obligation.cause.span, + format!("No entry for unboxed closure: {}", + closure_def_id.repr(self.tcx())).as_slice()); + } + }; + + // FIXME(pcwalton): This is a bogus thing to do, but + // it'll do for now until we get the new trait-bound + // region skolemization working. + let (_, new_signature) = + regionmanip::replace_late_bound_regions_in_fn_sig( + self.tcx(), + &closure_type.sig, + |br| self.infcx.next_region_var( + infer::LateBoundRegion(obligation.cause.span, br))); + + let arguments_tuple = *new_signature.inputs.get(0); + let trait_ref = Rc::new(ty::TraitRef { + def_id: obligation.trait_ref.def_id, + substs: Substs::new_trait( + vec![arguments_tuple, new_signature.output], + vec![], + obligation.self_ty()) + }); + + self.confirm(obligation.cause, + obligation.trait_ref.clone(), + trait_ref) + } + + /////////////////////////////////////////////////////////////////////////// + // Matching + // + // Matching is a common path used for both evaluation and + // confirmation. It basically unifies types that appear in impls + // and traits. This does affect the surrounding environment; + // therefore, when used during evaluation, match routines must be + // run inside of a `probe()` so that their side-effects are + // contained. + + fn match_impl_self_types(&self, + impl_def_id: ast::DefId, + obligation_cause: ObligationCause, + obligation_self_ty: ty::t) + -> MatchResult + { + /*! + * Determines whether the self type declared against + * `impl_def_id` matches `obligation_self_ty`. If successful, + * returns the substitutions used to make them match. See + * `match_impl()`. For example, if `impl_def_id` is declared + * as: + * + * impl Foo for ~T { ... } + * + * and `obligation_self_ty` is `int`, we'd back an `Err(_)` + * result. But if `obligation_self_ty` were `~int`, we'd get + * back `Ok(T=int)`. + */ + + // Create fresh type variables for each type parameter declared + // on the impl etc. + let impl_substs = util::fresh_substs_for_impl(self.infcx, + obligation_cause.span, + impl_def_id); + + // Find the self type for the impl. + let impl_self_ty = ty::lookup_item_type(self.tcx(), impl_def_id).ty; + let impl_self_ty = impl_self_ty.subst(self.tcx(), &impl_substs); + + debug!("match_impl_self_types(obligation_self_ty={}, impl_self_ty={})", + obligation_self_ty.repr(self.tcx()), + impl_self_ty.repr(self.tcx())); + + match self.match_self_types(obligation_cause, + impl_self_ty, + obligation_self_ty) { + Matched(()) => { + debug!("Matched impl_substs={}", impl_substs.repr(self.tcx())); + Matched(impl_substs) + } + AmbiguousMatch => { + debug!("AmbiguousMatch"); + AmbiguousMatch + } + NoMatch => { + debug!("NoMatch"); + NoMatch + } + } + } + + fn match_self_types(&self, + cause: ObligationCause, + + // The self type provided by the impl/caller-obligation: + provided_self_ty: ty::t, + + // The self type the obligation is for: + required_self_ty: ty::t) + -> MatchResult<()> + { + // FIXME(#5781) -- equating the types is stronger than + // necessary. Should consider variance of trait w/r/t Self. + + let origin = infer::RelateSelfType(cause.span); + match self.infcx.eq_types(false, + origin, + provided_self_ty, + required_self_ty) { + Ok(()) => Matched(()), + Err(ty::terr_sorts(ty::expected_found{expected: t1, found: t2})) => { + // This error occurs when there is an unresolved type + // variable in the `required_self_ty` that was forced + // to unify with a non-type-variable. That basically + // means we don't know enough to say with certainty + // whether there is a match or not -- it depends on + // how that type variable is ultimately resolved. + if ty::type_is_skolemized(t1) || ty::type_is_skolemized(t2) { + AmbiguousMatch + } else { + NoMatch + } + } + Err(_) => NoMatch, + } + } + + /////////////////////////////////////////////////////////////////////////// + // Confirmation + // + // The final step of selection: once we know how an obligation is + // is resolved, we confirm that selection in order to have + // side-effects on the typing environment. This step also unifies + // the output type parameters from the obligation with those found + // on the impl/bound, which may yield type errors. + + fn confirm_impl_vtable(&self, + impl_def_id: ast::DefId, + obligation_cause: ObligationCause, + obligation_trait_ref: Rc, + substs: &Substs) + -> Result<(), SelectionError> + { + /*! + * Relates the output type parameters from an impl to the + * trait. This may lead to type errors. The confirmation step + * is separated from the main match procedure because these + * type errors do not cause us to select another impl. + * + * As an example, consider matching the obligation + * `Iterator for Elems` using the following impl: + * + * impl Iterator for Elems { ... } + * + * The match phase will succeed with substitution `T=int`. + * The confirm step will then try to unify `int` and `char` + * and yield an error. + */ + + let impl_trait_ref = ty::impl_trait_ref(self.tcx(), + impl_def_id).unwrap(); + let impl_trait_ref = impl_trait_ref.subst(self.tcx(), + substs); + self.confirm(obligation_cause, obligation_trait_ref, impl_trait_ref) + } + + fn confirm(&self, + obligation_cause: ObligationCause, + obligation_trait_ref: Rc, + expected_trait_ref: Rc) + -> Result<(), SelectionError> + { + /*! + * After we have determined which impl applies, and with what + * substitutions, there is one last step. We have to go back + * and relate the "output" type parameters from the obligation + * to the types that are specified in the impl. + * + * For example, imagine we have: + * + * impl Iterator for Vec { ... } + * + * and our obligation is `Iterator for Vec` (note + * the mismatch in the obligation types). Up until this step, + * no error would be reported: the self type is `Vec`, + * and that matches `Vec` with the substitution `T=int`. + * At this stage, we could then go and check that the type + * parameters to the `Iterator` trait match. + * (In terms of the parameters, the `expected_trait_ref` + * here would be `Iterator for Vec`, and the + * `obligation_trait_ref` would be `Iterator for Vec`. + * + * Note that this checking occurs *after* the impl has + * selected, because these output type parameters should not + * affect the selection of the impl. Therefore, if there is a + * mismatch, we report an error to the user. + */ + + let origin = infer::RelateOutputImplTypes(obligation_cause.span); + + let obligation_trait_ref = obligation_trait_ref.clone(); + match self.infcx.sub_trait_refs(false, + origin, + expected_trait_ref.clone(), + obligation_trait_ref) { + Ok(()) => Ok(()), + Err(e) => Err(OutputTypeParameterMismatch(expected_trait_ref, e)) + } + } + + /////////////////////////////////////////////////////////////////////////// + // Miscellany + + fn all_impls(&self, trait_def_id: ast::DefId) -> Vec { + /*! + * Returns se tof all impls for a given trait. + */ + + ty::populate_implementations_for_trait_if_necessary(self.tcx(), + trait_def_id); + match self.tcx().trait_impls.borrow().find(&trait_def_id) { + None => Vec::new(), + Some(impls) => impls.borrow().clone() + } + } + + fn impl_obligations(&self, + cause: ObligationCause, + recursion_depth: uint, + impl_def_id: ast::DefId, + impl_substs: &Substs) + -> VecPerParamSpace + { + let impl_generics = ty::lookup_item_type(self.tcx(), + impl_def_id).generics; + util::obligations_for_generics(self.tcx(), cause, recursion_depth, + &impl_generics, impl_substs) + } + + fn trait_ref_unconstrained(&self, + trait_ref: &ty::TraitRef) + -> bool + { + /*! + * True if the self type of the trait-ref contains + * unconstrained type variables. + */ + + let mut found_skol = false; + + // Skolemization replaces all unconstrained type vars with + // a SkolemizedTy instance. Then we search to see if we + // found any. + let skol_ty = infer::skolemize(self.infcx, trait_ref.self_ty()); + ty::walk_ty(skol_ty, |t| { + match ty::get(t).sty { + ty::ty_infer(ty::SkolemizedTy(_)) => { found_skol = true; } + _ => { } + } + }); + + found_skol + } +} + +impl Candidate { + fn to_evaluation_result(&self) -> EvaluationResult { + match *self { + Impl(ref i) => i.to_evaluation_result(), + + MatchedUnboxedClosureCandidate(..) | + MatchedBuiltinCandidate | + MatchedParamCandidate(..) => { + EvaluatedToMatch + } + + AmbiguousBuiltinCandidate | + AmbiguousParamCandidate => { + EvaluatedToAmbiguity + } + } + } +} + +impl ImplCandidate { + fn to_evaluation_result(&self) -> EvaluationResult { + match *self { + MatchedImplCandidate(..) => EvaluatedToMatch, + AmbiguousImplCandidate(..) => EvaluatedToAmbiguity + } + } +} + +impl Repr for Candidate { + fn repr(&self, tcx: &ty::ctxt) -> String { + match *self { + MatchedBuiltinCandidate => format!("MatchedBuiltinCandidate"), + AmbiguousBuiltinCandidate => format!("AmbiguousBuiltinCandidate"), + MatchedUnboxedClosureCandidate(c) => format!("MatchedUnboxedClosureCandidate({})", c), + MatchedParamCandidate(ref r) => format!("MatchedParamCandidate({})", + r.repr(tcx)), + AmbiguousParamCandidate => format!("AmbiguousParamCandidate"), + Impl(ref i) => i.repr(tcx) + } + } +} + +impl Repr for ImplCandidate { + fn repr(&self, tcx: &ty::ctxt) -> String { + match *self { + MatchedImplCandidate(ref d) => format!("MatchedImplCandidate({})", + d.repr(tcx)), + AmbiguousImplCandidate(ref d) => format!("AmbiguousImplCandidate({})", + d.repr(tcx)), + } + } +} + + +// impl SelectionCache { +// pub fn new() -> SelectionCache { +// SelectionCache { +// hashmap: RefCell::new(HashMap::new()) +// } +// } +// } + +// impl CacheKey { +// pub fn new(trait_def_id: ast::DefId, +// skol_obligation_self_ty: ty::t) +// -> CacheKey +// { +// CacheKey { +// trait_def_id: trait_def_id, +// skol_obligation_self_ty: skol_obligation_self_ty +// } +// } +// } diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs new file mode 100644 index 0000000000000..11b954f2ba6af --- /dev/null +++ b/src/librustc/middle/traits/util.rs @@ -0,0 +1,356 @@ + +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use middle::subst; +use middle::subst::{ParamSpace, Subst, Substs, VecPerParamSpace}; +use middle::typeck::infer::InferCtxt; +use middle::ty; +use std::fmt; +use std::rc::Rc; +use syntax::ast; +use syntax::codemap::Span; +use util::ppaux::Repr; + +use super::{Obligation, ObligationCause, VtableImpl, VtableParam}; + +/////////////////////////////////////////////////////////////////////////// +// Supertrait iterator + +pub struct Supertraits<'cx, 'tcx:'cx> { + tcx: &'cx ty::ctxt<'tcx>, + stack: Vec, +} + +struct SupertraitEntry { + position: uint, + supertraits: Vec>, +} + +pub fn supertraits<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>, + trait_ref: Rc) + -> Supertraits<'cx, 'tcx> +{ + /*! + * Returns an iterator over the trait reference `T` and all of its + * supertrait references. May contain duplicates. In general + * the ordering is not defined. + * + * Example: + * + * ``` + * trait Foo { ... } + * trait Bar : Foo { ... } + * trait Baz : Bar+Foo { ... } + * ``` + * + * `supertraits(Baz)` yields `[Baz, Bar, Foo, Foo]` in some order. + */ + + transitive_bounds(tcx, [trait_ref]) +} + +pub fn transitive_bounds<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>, + bounds: &[Rc]) + -> Supertraits<'cx, 'tcx> +{ + let bounds = Vec::from_fn(bounds.len(), |i| bounds[i].clone()); + let entry = SupertraitEntry { position: 0, supertraits: bounds }; + Supertraits { tcx: tcx, stack: vec![entry] } +} + +impl<'cx, 'tcx> Supertraits<'cx, 'tcx> { + fn push(&mut self, trait_ref: &ty::TraitRef) { + let bounds = ty::bounds_for_trait_ref(self.tcx, trait_ref); + let entry = SupertraitEntry { position: 0, + supertraits: bounds.trait_bounds }; + self.stack.push(entry); + } + + pub fn indices(&self) -> Vec { + /*! + * Returns the path taken through the trait supertraits to + * reach the current point. + */ + + self.stack.iter().map(|e| e.position).collect() + } +} + +impl<'cx, 'tcx> Iterator> for Supertraits<'cx, 'tcx> { + fn next(&mut self) -> Option> { + loop { + // Extract next item from top-most stack frame, if any. + let next_trait = match self.stack.mut_last() { + None => { + // No more stack frames. Done. + return None; + } + Some(entry) => { + let p = entry.position; + if p < entry.supertraits.len() { + // Still more supertraits left in the top stack frame. + entry.position += 1; + + let next_trait = + (*entry.supertraits.get(p)).clone(); + Some(next_trait) + } else { + None + } + } + }; + + match next_trait { + Some(next_trait) => { + self.push(&*next_trait); + return Some(next_trait); + } + + None => { + // Top stack frame is exhausted, pop it. + self.stack.pop(); + } + } + } + } +} + +// determine the `self` type, using fresh variables for all variables +// declared on the impl declaration e.g., `impl for ~[(A,B)]` +// would return ($0, $1) where $0 and $1 are freshly instantiated type +// variables. +pub fn fresh_substs_for_impl(infcx: &InferCtxt, + span: Span, + impl_def_id: ast::DefId) + -> Substs +{ + let tcx = infcx.tcx; + let impl_generics = ty::lookup_item_type(tcx, impl_def_id).generics; + infcx.fresh_substs_for_generics(span, &impl_generics) +} + +impl fmt::Show for VtableImpl { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "VtableImpl({})", self.impl_def_id) + } +} + +impl fmt::Show for VtableParam { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "VtableParam(...)") + } +} + +pub fn obligations_for_generics(tcx: &ty::ctxt, + cause: ObligationCause, + recursion_depth: uint, + generics: &ty::Generics, + substs: &Substs) + -> VecPerParamSpace +{ + /*! See `super::obligations_for_generics` */ + + debug!("obligations_for_generics(generics={}, substs={})", + generics.repr(tcx), substs.repr(tcx)); + + let mut obligations = VecPerParamSpace::empty(); + + for def in generics.types.iter() { + push_obligations_for_param_bounds(tcx, + cause, + recursion_depth, + def.space, + def.index, + &def.bounds, + substs, + &mut obligations); + } + + debug!("obligations() ==> {}", obligations.repr(tcx)); + + return obligations; +} + +fn push_obligations_for_param_bounds( + tcx: &ty::ctxt, + cause: ObligationCause, + recursion_depth: uint, + space: subst::ParamSpace, + index: uint, + param_bounds: &ty::ParamBounds, + param_substs: &Substs, + obligations: &mut VecPerParamSpace) +{ + let param_ty = *param_substs.types.get(space, index); + + for builtin_bound in param_bounds.builtin_bounds.iter() { + obligations.push( + space, + obligation_for_builtin_bound(tcx, + cause, + builtin_bound, + recursion_depth, + param_ty)); + } + + for bound_trait_ref in param_bounds.trait_bounds.iter() { + let bound_trait_ref = bound_trait_ref.subst(tcx, param_substs); + obligations.push( + space, + Obligation { cause: cause, + recursion_depth: recursion_depth, + trait_ref: bound_trait_ref }); + } +} + +pub fn obligation_for_builtin_bound( + tcx: &ty::ctxt, + cause: ObligationCause, + builtin_bound: ty::BuiltinBound, + recursion_depth: uint, + param_ty: ty::t) + -> Obligation +{ + match tcx.lang_items.from_builtin_kind(builtin_bound) { + Ok(def_id) => { + Obligation { + cause: cause, + recursion_depth: recursion_depth, + trait_ref: Rc::new(ty::TraitRef { + def_id: def_id, + substs: Substs::empty().with_self_ty(param_ty), + }), + } + } + Err(e) => { + tcx.sess.span_bug(cause.span, e.as_slice()); + } + } +} + +pub fn search_trait_and_supertraits_from_bound(tcx: &ty::ctxt, + caller_bound: Rc, + test: |ast::DefId| -> bool) + -> Option +{ + /*! + * Starting from a caller obligation `caller_bound` (which has + * coordinates `space`/`i` in the list of caller obligations), + * search through the trait and supertraits to find one where + * `test(d)` is true, where `d` is the def-id of the + * trait/supertrait. If any is found, return `Some(p)` where `p` + * is the path to that trait/supertrait. Else `None`. + */ + + for (bound_index, bound) in + transitive_bounds(tcx, &[caller_bound]).enumerate() + { + if test(bound.def_id) { + let vtable_param = VtableParam { bound: bound }; + return Some(vtable_param); + } + } + + return None; +} + +impl Repr for super::Obligation { + fn repr(&self, tcx: &ty::ctxt) -> String { + format!("Obligation(trait_ref={},depth={})", + self.trait_ref.repr(tcx), + self.recursion_depth) + } +} + +impl Repr for super::Vtable { + fn repr(&self, tcx: &ty::ctxt) -> String { + match *self { + super::VtableImpl(ref v) => + v.repr(tcx), + + super::VtableUnboxedClosure(ref d) => + format!("VtableUnboxedClosure({})", + d.repr(tcx)), + + super::VtableParam(ref v) => + format!("VtableParam({})", v.repr(tcx)), + + super::VtableBuiltin => + format!("Builtin"), + } + } +} + +impl Repr for super::VtableImpl { + fn repr(&self, tcx: &ty::ctxt) -> String { + format!("VtableImpl(impl_def_id={}, substs={}, nested={})", + self.impl_def_id.repr(tcx), + self.substs.repr(tcx), + self.nested.repr(tcx)) + } +} + +impl Repr for super::VtableParam { + fn repr(&self, tcx: &ty::ctxt) -> String { + format!("VtableParam(bound={})", + self.bound.repr(tcx)) + } +} + +impl Repr for super::SelectionError { + fn repr(&self, tcx: &ty::ctxt) -> String { + match *self { + super::Unimplemented => + format!("Unimplemented"), + + super::Overflow => + format!("Overflow"), + + super::OutputTypeParameterMismatch(ref t, ref e) => + format!("OutputTypeParameterMismatch({}, {})", + t.repr(tcx), + e.repr(tcx)), + } + } +} + +impl Repr for super::FulfillmentError { + fn repr(&self, tcx: &ty::ctxt) -> String { + format!("FulfillmentError({},{})", + self.obligation.repr(tcx), + self.code.repr(tcx)) + } +} + +impl Repr for super::FulfillmentErrorCode { + fn repr(&self, tcx: &ty::ctxt) -> String { + match *self { + super::SelectionError(ref o) => o.repr(tcx), + super::Ambiguity => format!("Ambiguity") + } + } +} + +impl fmt::Show for super::FulfillmentErrorCode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + super::SelectionError(ref e) => write!(f, "{}", e), + super::Ambiguity => write!(f, "Ambiguity") + } + } +} + +impl Repr for ty::type_err { + fn repr(&self, tcx: &ty::ctxt) -> String { + ty::type_err_to_str(tcx, self) + } +} + diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index bf35e25635aa2..643c52e5d52ba 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1089,7 +1089,13 @@ pub struct RegionVid { pub enum InferTy { TyVar(TyVid), IntVar(IntVid), - FloatVar(FloatVid) + FloatVar(FloatVid), + SkolemizedTy(uint), + + // FIXME -- once integral fallback is impl'd, we should remove + // this type. It's only needed to prevent spurious errors for + // integers whose type winds up never being constrained. + SkolemizedIntTy(uint), } #[deriving(Clone, Encodable, Decodable, Eq, Hash, Show)] @@ -1152,6 +1158,8 @@ impl fmt::Show for InferTy { TyVar(ref v) => v.fmt(f), IntVar(ref v) => v.fmt(f), FloatVar(ref v) => v.fmt(f), + SkolemizedTy(v) => write!(f, "SkolemizedTy({})", v), + SkolemizedIntTy(v) => write!(f, "SkolemizedIntTy({})", v), } } } @@ -1207,6 +1215,12 @@ impl Generics { } } +impl TraitRef { + pub fn self_ty(&self) -> ty::t { + self.substs.self_ty().unwrap() + } +} + /// When type checking, we use the `ParameterEnvironment` to track /// details about the type/lifetime parameters that are in scope. /// It primarily stores the bounds information. @@ -1235,6 +1249,14 @@ pub struct ParameterEnvironment { /// may specify stronger requirements). This field indicates the /// region of the callee. pub implicit_region_bound: ty::Region, + + /// Obligations that the caller must satisfy. This is basically + /// the set of bounds on the in-scope type parameters, translated + /// into Obligations. + /// + /// Note: This effectively *duplicates* the `bounds` array for + /// now. + pub caller_obligations: VecPerParamSpace, } impl ParameterEnvironment { @@ -1249,6 +1271,7 @@ impl ParameterEnvironment { let method_generics = &method_ty.generics; construct_parameter_environment( cx, + method.span, method_generics, method.pe_body().id) } @@ -1272,6 +1295,7 @@ impl ParameterEnvironment { let method_generics = &method_ty.generics; construct_parameter_environment( cx, + method.span, method_generics, method.pe_body().id) } @@ -1287,6 +1311,7 @@ impl ParameterEnvironment { let fn_pty = ty::lookup_item_type(cx, fn_def_id); construct_parameter_environment(cx, + item.span, &fn_pty.generics, body.id) } @@ -1296,7 +1321,8 @@ impl ParameterEnvironment { ast::ItemStatic(..) => { let def_id = ast_util::local_def(id); let pty = ty::lookup_item_type(cx, def_id); - construct_parameter_environment(cx, &pty.generics, id) + construct_parameter_environment(cx, item.span, + &pty.generics, id) } _ => { cx.sess.span_bug(item.span, @@ -1328,7 +1354,14 @@ pub struct Polytype { /// As `Polytype` but for a trait ref. pub struct TraitDef { + /// Generic type definitions. Note that `Self` is listed in here + /// as having a single bound, the trait itself (e.g., in the trait + /// `Eq`, there is a single bound `Self : Eq`). This is so that + /// default methods get to assume that the `Self` parameters + /// implements the trait. pub generics: Generics, + + /// The "supertrait" bounds. pub bounds: ParamBounds, pub trait_ref: Rc, } @@ -1345,6 +1378,7 @@ pub type type_cache = RefCell>; pub type node_type_table = RefCell>; /// Records information about each unboxed closure. +#[deriving(Clone)] pub struct UnboxedClosure { /// The type of the unboxed closure. pub closure_type: ClosureTy, @@ -1352,7 +1386,7 @@ pub struct UnboxedClosure { pub kind: UnboxedClosureKind, } -#[deriving(PartialEq, Eq)] +#[deriving(Clone, PartialEq, Eq)] pub enum UnboxedClosureKind { FnUnboxedClosureKind, FnMutUnboxedClosureKind, @@ -1523,7 +1557,7 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t { &ty_enum(_, ref substs) | &ty_struct(_, ref substs) => { flags |= sflags(substs); } - &ty_trait(box ty::TyTrait { ref substs, ref bounds, .. }) => { + &ty_trait(box TyTrait { ref substs, ref bounds, .. }) => { flags |= sflags(substs); flags |= flags_for_bounds(bounds); } @@ -2394,6 +2428,7 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents { } // Scalar and unique types are sendable, and durable + ty_infer(ty::SkolemizedIntTy(_)) | ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) | ty_bare_fn(_) | ty::ty_char => { TC::None @@ -2414,7 +2449,7 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents { } } - ty_trait(box ty::TyTrait { bounds, .. }) => { + ty_trait(box TyTrait { bounds, .. }) => { object_contents(cx, bounds) | TC::ReachesFfiUnsafe | TC::Nonsized } @@ -2926,6 +2961,14 @@ pub fn type_is_integral(ty: t) -> bool { } } +pub fn type_is_skolemized(ty: t) -> bool { + match get(ty).sty { + ty_infer(SkolemizedTy(_)) => true, + ty_infer(SkolemizedIntTy(_)) => true, + _ => false + } +} + pub fn type_is_uint(ty: t) -> bool { match get(ty).sty { ty_infer(IntVar(_)) | ty_uint(ast::TyU) => true, @@ -3760,6 +3803,8 @@ pub fn ty_sort_string(cx: &ctxt, t: t) -> String { ty_infer(TyVar(_)) => "inferred type".to_string(), ty_infer(IntVar(_)) => "integral variable".to_string(), ty_infer(FloatVar(_)) => "floating-point variable".to_string(), + ty_infer(SkolemizedTy(_)) => "skolemized type".to_string(), + ty_infer(SkolemizedIntTy(_)) => "skolemized integral type".to_string(), ty_param(ref p) => { if p.space == subst::SelfSpace { "Self".to_string() @@ -4683,7 +4728,7 @@ pub fn normalize_ty(cx: &ctxt, t: t) -> t { struct TypeNormalizer<'a, 'tcx: 'a>(&'a ctxt<'tcx>); impl<'a, 'tcx> TypeFolder<'tcx> for TypeNormalizer<'a, 'tcx> { - fn tcx<'a>(&'a self) -> &'a ctxt<'tcx> { let TypeNormalizer(c) = *self; c } + fn tcx(&self) -> &ctxt<'tcx> { let TypeNormalizer(c) = *self; c } fn fold_ty(&mut self, t: ty::t) -> ty::t { match self.tcx().normalized_cache.borrow().find_copy(&t) { @@ -4783,42 +4828,11 @@ pub fn eval_repeat_count(tcx: &ctxt, count_expr: &ast::Expr) -> uint { pub fn each_bound_trait_and_supertraits(tcx: &ctxt, bounds: &[Rc], f: |Rc| -> bool) - -> bool { - for bound_trait_ref in bounds.iter() { - let mut supertrait_set = HashMap::new(); - let mut trait_refs = Vec::new(); - let mut i = 0; - - // Seed the worklist with the trait from the bound - supertrait_set.insert(bound_trait_ref.def_id, ()); - trait_refs.push(bound_trait_ref.clone()); - - // Add the given trait ty to the hash map - while i < trait_refs.len() { - debug!("each_bound_trait_and_supertraits(i={:?}, trait_ref={})", - i, trait_refs.get(i).repr(tcx)); - - if !f(trait_refs.get(i).clone()) { - return false; - } - - // Add supertraits to supertrait_set - let trait_ref = trait_refs.get(i).clone(); - let trait_def = lookup_trait_def(tcx, trait_ref.def_id); - for supertrait_ref in trait_def.bounds.trait_bounds.iter() { - let supertrait_ref = supertrait_ref.subst(tcx, &trait_ref.substs); - debug!("each_bound_trait_and_supertraits(supertrait_ref={})", - supertrait_ref.repr(tcx)); - - let d_id = supertrait_ref.def_id; - if !supertrait_set.contains_key(&d_id) { - // FIXME(#5527) Could have same trait multiple times - supertrait_set.insert(d_id, ()); - trait_refs.push(supertrait_ref.clone()); - } - } - - i += 1; + -> bool +{ + for bound_trait_ref in traits::transitive_bounds(tcx, bounds) { + if !f(bound_trait_ref) { + return false; } } return true; @@ -5261,8 +5275,22 @@ impl Variance { } } +pub fn empty_parameter_environment() -> ParameterEnvironment { + /*! + * Construct a parameter environment suitable for static contexts + * or other contexts where there are no free type/lifetime + * parameters in scope. + */ + + ty::ParameterEnvironment { free_substs: Substs::empty(), + bounds: VecPerParamSpace::empty(), + caller_obligations: VecPerParamSpace::empty(), + implicit_region_bound: ty::ReEmpty } +} + pub fn construct_parameter_environment( tcx: &ctxt, + span: Span, generics: &ty::Generics, free_id: ast::NodeId) -> ParameterEnvironment @@ -5321,10 +5349,14 @@ pub fn construct_parameter_environment( free_substs.repr(tcx), bounds.repr(tcx)); + let obligations = traits::obligations_for_generics(tcx, traits::ObligationCause::misc(span), + generics, &free_substs); + return ty::ParameterEnvironment { free_substs: free_substs, bounds: bounds, implicit_region_bound: ty::ReScope(free_id), + caller_obligations: obligations, }; fn push_region_params(regions: &mut VecPerParamSpace, diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index bc53568694df6..861afee06049b 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -8,11 +8,38 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Generalized type folding mechanism. +/*! + * Generalized type folding mechanism. The setup is a bit convoluted + * but allows for convenient usage. Let T be an instance of some + * "foldable type" (one which implements `TypeFoldable`) and F be an + * instance of a "folder" (a type which implements `TypeFolder`). Then + * the setup is intended to be: + * + * T.fold_with(F) --calls--> F.fold_T(T) --calls--> super_fold_T(F, T) + * + * This way, when you define a new folder F, you can override + * `fold_T()` to customize the behavior, and invoke `super_fold_T()` + * to get the original behavior. Meanwhile, to actually fold + * something, you can just write `T.fold_with(F)`, which is + * convenient. (Note that `fold_with` will also transparently handle + * things like a `Vec` where T is foldable and so on.) + * + * In this ideal setup, the only function that actually *does* + * anything is `super_fold_T`, which traverses the type `T`. Moreover, + * `super_fold_T` should only ever call `T.fold_with()`. + * + * In some cases, we follow a degenerate pattern where we do not have + * a `fold_T` nor `super_fold_T` method. Instead, `T.fold_with` + * traverses the structure directly. This is suboptimal because the + * behavior cannot be overriden, but it's much less work to implement. + * If you ever *do* need an override that doesn't exist, it's not hard + * to convert the degenerate pattern into the proper thing. + */ use middle::subst; use middle::subst::VecPerParamSpace; use middle::ty; +use middle::traits; use middle::typeck; use std::rc::Rc; use syntax::ast; @@ -97,6 +124,10 @@ pub trait TypeFolder<'tcx> { fn fold_item_substs(&mut self, i: ty::ItemSubsts) -> ty::ItemSubsts { super_fold_item_substs(self, i) } + + fn fold_obligation(&mut self, o: &traits::Obligation) -> traits::Obligation { + super_fold_obligation(self, o) + } } /////////////////////////////////////////////////////////////////////////// @@ -110,6 +141,12 @@ pub trait TypeFolder<'tcx> { // can easily refactor the folding into the TypeFolder trait as // needed. +impl TypeFoldable for () { + fn fold_with<'tcx, F:TypeFolder<'tcx>>(&self, _: &mut F) -> () { + () + } +} + impl TypeFoldable for Option { fn fold_with<'tcx, F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Option { self.as_ref().map(|t| t.fold_with(folder)) @@ -296,13 +333,54 @@ impl TypeFoldable for ty::UnsizeKind { match *self { ty::UnsizeLength(len) => ty::UnsizeLength(len), ty::UnsizeStruct(box ref k, n) => ty::UnsizeStruct(box k.fold_with(folder), n), - ty::UnsizeVtable(bounds, def_id, ref substs) => { - ty::UnsizeVtable(bounds.fold_with(folder), def_id, substs.fold_with(folder)) + ty::UnsizeVtable(ty::TyTrait{bounds, def_id, substs: ref substs}, self_ty) => { + ty::UnsizeVtable( + ty::TyTrait { + bounds: bounds.fold_with(folder), + def_id: def_id, + substs: substs.fold_with(folder) + }, + self_ty.fold_with(folder)) } } } } +impl TypeFoldable for traits::Obligation { + fn fold_with<'tcx, F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::Obligation { + folder.fold_obligation(self) + } +} + +impl TypeFoldable for traits::VtableImpl { + fn fold_with<'tcx, F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableImpl { + traits::VtableImpl { + impl_def_id: self.impl_def_id, + substs: self.substs.fold_with(folder), + nested: self.nested.fold_with(folder), + } + } +} + +impl TypeFoldable for traits::Vtable { + fn fold_with<'tcx, F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::Vtable { + match *self { + traits::VtableImpl(ref v) => traits::VtableImpl(v.fold_with(folder)), + traits::VtableUnboxedClosure(d) => traits::VtableUnboxedClosure(d), + traits::VtableParam(ref p) => traits::VtableParam(p.fold_with(folder)), + traits::VtableBuiltin => traits::VtableBuiltin, + } + } +} + +impl TypeFoldable for traits::VtableParam { + fn fold_with<'tcx, F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableParam { + traits::VtableParam { + bound: self.bound.fold_with(folder), + } + } +} + /////////////////////////////////////////////////////////////////////////// // "super" routines: these are the default implementations for TypeFolder. // @@ -482,6 +560,17 @@ pub fn super_fold_item_substs<'tcx, T: TypeFolder<'tcx>>(this: &mut T, } } +pub fn super_fold_obligation<'tcx, T:TypeFolder<'tcx>>(this: &mut T, + obligation: &traits::Obligation) + -> traits::Obligation +{ + traits::Obligation { + cause: obligation.cause, + recursion_depth: obligation.recursion_depth, + trait_ref: obligation.trait_ref.fold_with(this), + } +} + /////////////////////////////////////////////////////////////////////////// // Some sample folders diff --git a/src/librustc/middle/typeck/infer/error_reporting.rs b/src/librustc/middle/typeck/infer/error_reporting.rs index b5b4cc80faac1..4f663df58824a 100644 --- a/src/librustc/middle/typeck/infer/error_reporting.rs +++ b/src/librustc/middle/typeck/infer/error_reporting.rs @@ -363,6 +363,7 @@ impl<'a, 'tcx> ErrorReporting for InferCtxt<'a, 'tcx> { infer::ExprAssignable(_) => "mismatched types", infer::RelateTraitRefs(_) => "mismatched traits", infer::RelateSelfType(_) => "mismatched types", + infer::RelateOutputImplTypes(_) => "mismatched types", infer::MatchExpressionArm(_, _) => "match arms have incompatible types", infer::IfExpression(_) => "if and else have incompatible types", }; @@ -1465,7 +1466,11 @@ impl<'a, 'tcx> ErrorReportingHelpers for InferCtxt<'a, 'tcx> { format!("traits are compatible") } infer::RelateSelfType(_) => { - format!("type matches impl") + format!("self type matches impl self type") + } + infer::RelateOutputImplTypes(_) => { + format!("trait type parameters matches those \ + specified on the impl") } infer::MatchExpressionArm(_, _) => { format!("match arms have compatible types") diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs index f11584e9356c6..db90593b5b36b 100644 --- a/src/librustc/middle/typeck/infer/mod.rs +++ b/src/librustc/middle/typeck/infer/mod.rs @@ -26,6 +26,7 @@ use middle::subst::Substs; use middle::ty::{TyVid, IntVid, FloatVid, RegionVid}; use middle::ty; use middle::ty_fold; +use middle::ty_fold::TypeFoldable; use middle::ty_fold::TypeFolder; use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig; use middle::typeck::infer::coercion::Coerce; @@ -57,6 +58,7 @@ pub mod lattice; pub mod lub; pub mod region_inference; pub mod resolve; +mod skolemize; pub mod sub; pub mod test; pub mod type_variable; @@ -114,9 +116,12 @@ pub enum TypeOrigin { // Relating trait refs when resolving vtables RelateTraitRefs(Span), - // Relating trait refs when resolving vtables + // Relating self types when resolving vtables RelateSelfType(Span), + // Relating trait type parameters to those found in impl etc + RelateOutputImplTypes(Span), + // Computing common supertype in the arms of a match expression MatchExpressionArm(Span, Span), @@ -262,6 +267,7 @@ pub enum RegionVariableOrigin { BoundRegionInCoherence(ast::Name), } +#[deriving(Show)] pub enum fixup_err { unresolved_int_ty(IntVid), unresolved_float_ty(FloatVid), @@ -336,17 +342,12 @@ pub fn mk_subty(cx: &InferCtxt, origin: TypeOrigin, a: ty::t, b: ty::t) - -> ures { + -> ures +{ debug!("mk_subty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx)); - indent(|| { - cx.commit_if_ok(|| { - let trace = TypeTrace { - origin: origin, - values: Types(expected_found(a_is_expected, a, b)) - }; - cx.sub(a_is_expected, trace).tys(a, b) - }) - }).to_ures() + cx.commit_if_ok(|| { + cx.sub_types(a_is_expected, origin, a, b) + }) } pub fn can_mk_subty(cx: &InferCtxt, a: ty::t, b: ty::t) -> ures { @@ -356,8 +357,8 @@ pub fn can_mk_subty(cx: &InferCtxt, a: ty::t, b: ty::t) -> ures { origin: Misc(codemap::DUMMY_SP), values: Types(expected_found(true, a, b)) }; - cx.sub(true, trace).tys(a, b) - }).to_ures() + cx.sub(true, trace).tys(a, b).to_ures() + }) } pub fn can_mk_eqty(cx: &InferCtxt, a: ty::t, b: ty::t) -> ures { @@ -393,6 +394,14 @@ pub fn verify_param_bound(cx: &InferCtxt, cx.region_vars.verify_param_bound(origin, param_ty, a, bs); } + +pub fn skolemize(cx: &InferCtxt, a: T) -> T { + let mut skol = skolemize::TypeSkolemizer::new(cx); + let b = a.fold_with(&mut skol); + debug!("skol(a={}) -> {}", a.repr(cx.tcx), b.repr(cx.tcx)); + b +} + pub fn mk_eqty(cx: &InferCtxt, a_is_expected: bool, origin: TypeOrigin, @@ -401,14 +410,8 @@ pub fn mk_eqty(cx: &InferCtxt, -> ures { debug!("mk_eqty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx)); - cx.commit_if_ok(|| { - let trace = TypeTrace { - origin: origin, - values: Types(expected_found(a_is_expected, a, b)) - }; - try!(cx.equate(a_is_expected, trace).tys(a, b)); - Ok(()) - }) + cx.commit_if_ok( + || cx.eq_types(a_is_expected, origin, a, b)) } pub fn mk_sub_trait_refs(cx: &InferCtxt, @@ -416,25 +419,19 @@ pub fn mk_sub_trait_refs(cx: &InferCtxt, origin: TypeOrigin, a: Rc, b: Rc) - -> ures + -> ures { debug!("mk_sub_trait_refs({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx)); - indent(|| { - cx.commit_if_ok(|| { - let trace = TypeTrace { - origin: origin, - values: TraitRefs(expected_found(a_is_expected, a.clone(), b.clone())) - }; - let suber = cx.sub(a_is_expected, trace); - suber.trait_refs(&*a, &*b) - }) - }).to_ures() + cx.commit_if_ok( + || cx.sub_trait_refs(a_is_expected, origin, a.clone(), b.clone())) } fn expected_found(a_is_expected: bool, a: T, - b: T) -> ty::expected_found { + b: T) + -> ty::expected_found +{ if a_is_expected { ty::expected_found {expected: a, found: b} } else { @@ -629,7 +626,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } /// Execute `f` then unroll any bindings it creates - pub fn probe(&self, f: || -> Result) -> Result { + pub fn probe(&self, f: || -> R) -> R { debug!("probe()"); let snapshot = self.start_snapshot(); let r = f(); @@ -643,6 +640,54 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { { self.region_vars.add_given(sub, sup); } + + pub fn sub_types(&self, + a_is_expected: bool, + origin: TypeOrigin, + a: ty::t, + b: ty::t) + -> ures + { + debug!("sub_types({} <: {})", a.repr(self.tcx), b.repr(self.tcx)); + let trace = TypeTrace { + origin: origin, + values: Types(expected_found(a_is_expected, a, b)) + }; + self.sub(a_is_expected, trace).tys(a, b).to_ures() + } + + pub fn eq_types(&self, + a_is_expected: bool, + origin: TypeOrigin, + a: ty::t, + b: ty::t) + -> ures + { + let trace = TypeTrace { + origin: origin, + values: Types(expected_found(a_is_expected, a, b)) + }; + self.equate(a_is_expected, trace).tys(a, b).to_ures() + } + + pub fn sub_trait_refs(&self, + a_is_expected: bool, + origin: TypeOrigin, + a: Rc, + b: Rc) + -> ures + { + debug!("sub_trait_refs({} <: {})", + a.repr(self.tcx), + b.repr(self.tcx)); + let trace = TypeTrace { + origin: origin, + values: TraitRefs(expected_found(a_is_expected, + a.clone(), b.clone())) + }; + let suber = self.sub(a_is_expected, trace); + suber.trait_refs(&*a, &*b).to_ures() + } } impl<'a, 'tcx> InferCtxt<'a, 'tcx> { @@ -685,17 +730,40 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .collect() } - pub fn fresh_substs_for_type(&self, - span: Span, - generics: &ty::Generics) - -> subst::Substs + pub fn fresh_substs_for_generics(&self, + span: Span, + generics: &ty::Generics) + -> subst::Substs { /*! * Given a set of generics defined on a type or impl, returns * a substitution mapping each type/region parameter to a * fresh inference variable. */ - assert!(generics.types.len(subst::SelfSpace) == 0); + + let type_params = + generics.types.map( + |_| self.next_ty_var()); + let region_params = + generics.regions.map( + |d| self.next_region_var(EarlyBoundRegion(span, d.name))); + subst::Substs::new(type_params, region_params) + } + + pub fn fresh_substs_for_trait(&self, + span: Span, + generics: &ty::Generics, + self_ty: ty::t) + -> subst::Substs + { + /*! + * Given a set of generics defined on a trait, returns a + * substitution mapping each output type/region parameter to a + * fresh inference variable, and mapping the self type to + * `self_ty`. + */ + + assert!(generics.types.len(subst::SelfSpace) == 1); assert!(generics.types.len(subst::FnSpace) == 0); assert!(generics.regions.len(subst::SelfSpace) == 0); assert!(generics.regions.len(subst::FnSpace) == 0); @@ -704,7 +772,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let region_param_defs = generics.regions.get_slice(subst::TypeSpace); let regions = self.region_vars_for_defs(span, region_param_defs); let type_parameters = self.next_ty_vars(type_parameter_count); - subst::Substs::new_type(type_parameters, regions) + subst::Substs::new_trait(type_parameters, regions, self_ty) } pub fn fresh_bound_region(&self, binder_id: ast::NodeId) -> ty::Region { @@ -731,6 +799,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { trait_ref_to_string(self.tcx, &t) } + pub fn contains_unbound_type_variables(&self, typ: ty::t) -> ty::t { + match resolve_type(self, + None, + typ, resolve_nested_tvar | resolve_ivar) { + Ok(new_type) => new_type, + Err(_) => typ + } + } + pub fn resolve_type_vars_if_possible(&self, typ: ty::t) -> ty::t { match resolve_type(self, None, @@ -907,6 +984,7 @@ impl TypeOrigin { Misc(span) => span, RelateTraitRefs(span) => span, RelateSelfType(span) => span, + RelateOutputImplTypes(span) => span, MatchExpressionArm(match_span, _) => match_span, IfExpression(span) => span, } @@ -929,6 +1007,9 @@ impl Repr for TypeOrigin { RelateSelfType(a) => { format!("RelateSelfType({})", a.repr(tcx)) } + RelateOutputImplTypes(a) => { + format!("RelateOutputImplTypes({})", a.repr(tcx)) + } MatchExpressionArm(a, b) => { format!("MatchExpressionArm({}, {})", a.repr(tcx), b.repr(tcx)) } diff --git a/src/librustc/middle/typeck/infer/resolve.rs b/src/librustc/middle/typeck/infer/resolve.rs index 569206f6754f9..2c0b2dbe2ba79 100644 --- a/src/librustc/middle/typeck/infer/resolve.rs +++ b/src/librustc/middle/typeck/infer/resolve.rs @@ -46,7 +46,6 @@ // future). If you want to resolve everything but one type, you are // probably better off writing `resolve_all - resolve_ivar`. - use middle::ty::{FloatVar, FloatVid, IntVar, IntVid, RegionVid, TyVar, TyVid}; use middle::ty::{IntType, UintType}; use middle::ty; @@ -54,7 +53,6 @@ use middle::ty_fold; use middle::typeck::infer::{fixup_err, fres, InferCtxt}; use middle::typeck::infer::{unresolved_int_ty,unresolved_float_ty,unresolved_ty}; use syntax::codemap::Span; -use util::common::indent; use util::ppaux::{Repr, ty_to_string}; pub static resolve_nested_tvar: uint = 0b0000000001; @@ -94,7 +92,7 @@ pub fn resolver<'a, 'tcx>(infcx: &'a InferCtxt<'a, 'tcx>, } impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for ResolveState<'a, 'tcx> { - fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { + fn tcx(&self) -> &ty::ctxt<'tcx> { self.infcx.tcx } @@ -114,7 +112,8 @@ impl<'a, 'tcx> ResolveState<'a, 'tcx> { pub fn resolve_type_chk(&mut self, typ: ty::t) - -> fres { + -> fres + { self.err = None; debug!("Resolving {} (modes={:x})", @@ -126,14 +125,16 @@ impl<'a, 'tcx> ResolveState<'a, 'tcx> { let rty = self.resolve_type(typ); match self.err { - None => { - debug!("Resolved {} to {} (modes={:x})", - ty_to_string(self.infcx.tcx, typ), - ty_to_string(self.infcx.tcx, rty), - self.modes); - return Ok(rty); - } - Some(e) => return Err(e) + None => { + debug!("Resolved {} to {} (modes={:x})", + ty_to_string(self.infcx.tcx, typ), + ty_to_string(self.infcx.tcx, rty), + self.modes); + return Ok(rty); + } + Some(e) => { + return Err(e); + } } } @@ -141,7 +142,7 @@ impl<'a, 'tcx> ResolveState<'a, 'tcx> { orig: ty::Region) -> fres { self.err = None; - let resolved = indent(|| self.resolve_region(orig) ); + let resolved = self.resolve_region(orig); match self.err { None => Ok(resolved), Some(e) => Err(e) diff --git a/src/librustc/middle/typeck/infer/skolemize.rs b/src/librustc/middle/typeck/infer/skolemize.rs new file mode 100644 index 0000000000000..e1d48407f2e43 --- /dev/null +++ b/src/librustc/middle/typeck/infer/skolemize.rs @@ -0,0 +1,157 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! + * Skolemization is the process of replacing unknown variables with + * fresh types. The idea is that the type, after skolemization, + * contains no inference variables but instead contains either a value + * for each variable (if the variable had already fresh "arbitrary" + * types wherever a variable would have been. + * + * Skolemization is used wherever we want to test what the type + * inferencer knows "so far". The primary place it is used right now + * is in the trait matching algorithm, which needs to be able to test + * whether an `impl` self type matches some other type X -- *without* + * affecting `X`. That means if that if the type `X` is in fact an + * unbound type variable, we want the match to be regarded as + * ambiguous, because depending on what type that type variable is + * ultimately assigned, the match may or may not succeed. + * + * Note that you should be careful not to allow the output of + * skolemization to leak to the user in error messages or in any other + * form. Skolemization is only really useful as an internal detail. + * + * __An important detail concerning regions.__ The skolemizer also + * replaces *all* regions with 'static. The reason behind this is + * that, in general, we do not take region relationships into account + * when making type-overloaded decisions. This is important because of + * the design of the region inferencer, which is not based on + * unification but rather on accumulating and then solving a set of + * constraints. In contrast, the type inferencer assigns a value to + * each type variable only once, and it does so as soon as it can, so + * it is reasonable to ask what the type inferencer knows "so far". + */ + +use middle::ty; +use middle::ty_fold; +use middle::ty_fold::TypeFoldable; +use middle::ty_fold::TypeFolder; + +use super::InferCtxt; +use super::unify::InferCtxtMethodsForSimplyUnifiableTypes; +use super::unify::SimplyUnifiable; +use super::unify::UnifyKey; + +pub struct TypeSkolemizer<'a, 'tcx:'a> { + infcx: &'a InferCtxt<'a, 'tcx>, + skolemization_count: uint +} + +impl<'a, 'tcx> TypeSkolemizer<'a, 'tcx> { + pub fn new<'tcx>(infcx: &'a InferCtxt<'a, 'tcx>) -> TypeSkolemizer<'a, 'tcx> { + TypeSkolemizer { infcx: infcx, skolemization_count: 0 } + } + + fn probe_ty(&mut self, v: ty::TyVid) -> ty::t { + self.skolemize_if_none(self.infcx.type_variables.borrow().probe(v), ty::SkolemizedTy) + } + + fn probe_unifiable>>(&mut self, k: K) -> ty::t { + self.skolemize_if_none(self.infcx.probe_var(k), ty::SkolemizedIntTy) + } + + fn skolemize_if_none(&mut self, o: Option, + skolemizer: |uint| -> ty::InferTy) + -> ty::t { + match o { + Some(t) => t.fold_with(self), + None => { + let index = self.skolemization_count; + self.skolemization_count += 1; + ty::mk_infer(self.tcx(), skolemizer(index)) + } + } + } +} + +impl<'a, 'tcx> TypeFolder<'tcx> for TypeSkolemizer<'a, 'tcx> { + fn tcx<'b>(&'b self) -> &'b ty::ctxt<'tcx> { + self.infcx.tcx + } + + fn fold_region(&mut self, r: ty::Region) -> ty::Region { + match r { + ty::ReEarlyBound(..) | + ty::ReLateBound(..) => { + // leave bound regions alone + r + } + + ty::ReStatic | + ty::ReFree(_) | + ty::ReScope(_) | + ty::ReInfer(_) | + ty::ReEmpty => { + // replace all free regions with 'static + ty::ReStatic + } + } + } + + fn fold_ty(&mut self, t: ty::t) -> ty::t { + match ty::get(t).sty { + ty::ty_infer(ty::TyVar(v)) => { + self.probe_ty(v) + } + + ty::ty_infer(ty::IntVar(v)) => { + self.probe_unifiable(v) + } + + ty::ty_infer(ty::FloatVar(v)) => { + self.probe_unifiable(v) + } + + ty::ty_infer(ty::SkolemizedTy(_)) | + ty::ty_infer(ty::SkolemizedIntTy(_)) => { + self.tcx().sess.bug("Cannot skolemize a skolemized type"); + } + + ty::ty_open(..) => { + self.tcx().sess.bug("Cannot skolemize an open existential type"); + } + + ty::ty_nil | + ty::ty_bot | + ty::ty_bool | + ty::ty_char | + ty::ty_int(..) | + ty::ty_uint(..) | + ty::ty_float(..) | + ty::ty_enum(..) | + ty::ty_box(..) | + ty::ty_uniq(..) | + ty::ty_str | + ty::ty_err | + ty::ty_vec(..) | + ty::ty_ptr(..) | + ty::ty_rptr(..) | + ty::ty_bare_fn(..) | + ty::ty_closure(..) | + ty::ty_trait(..) | + ty::ty_struct(..) | + ty::ty_unboxed_closure(..) | + ty::ty_tup(..) | + ty::ty_param(..) => { + ty_fold::super_fold_ty(self, t) + } + } + } +} diff --git a/src/librustc/middle/typeck/infer/unify.rs b/src/librustc/middle/typeck/infer/unify.rs index 22d78340e9637..301582d55d6eb 100644 --- a/src/librustc/middle/typeck/infer/unify.rs +++ b/src/librustc/middle/typeck/infer/unify.rs @@ -258,6 +258,7 @@ impl sv::SnapshotVecDelegate,()> for Delegate { * relationship. */ pub trait SimplyUnifiable : Clone + PartialEq + Repr { + fn to_type(&self) -> ty::t; fn to_type_err(expected_found) -> ty::type_err; } @@ -286,6 +287,7 @@ pub trait InferCtxtMethodsForSimplyUnifiableTypes ures; + fn probe_var(&self, a_id: K) -> Option; } impl<'a,'tcx,V:SimplyUnifiable,K:UnifyKey>> @@ -370,6 +372,16 @@ impl<'a,'tcx,V:SimplyUnifiable,K:UnifyKey>> } } } + + fn probe_var(&self, a_id: K) -> Option { + let tcx = self.tcx; + let table = UnifyKey::unification_table(self); + let node_a = table.borrow_mut().get(tcx, a_id); + match node_a.value { + None => None, + Some(ref a_t) => Some(a_t.to_type()) + } + } } /////////////////////////////////////////////////////////////////////////// @@ -393,6 +405,13 @@ impl UnifyKey> for ty::IntVid { } impl SimplyUnifiable for IntVarValue { + fn to_type(&self) -> ty::t { + match *self { + ty::IntType(i) => ty::mk_mach_int(i), + ty::UintType(i) => ty::mk_mach_uint(i), + } + } + fn to_type_err(err: expected_found) -> ty::type_err { return ty::terr_int_mismatch(err); } @@ -422,6 +441,10 @@ impl UnifyValue for Option { } impl SimplyUnifiable for ast::FloatTy { + fn to_type(&self) -> ty::t { + ty::mk_mach_float(*self) + } + fn to_type_err(err: expected_found) -> ty::type_err { return ty::terr_float_mismatch(err); } From 6349a61231b8c0571cf3db97a68c7215e04a8791 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 12 Sep 2014 10:54:08 -0400 Subject: [PATCH 04/10] Port coherence to use the new trait matching code --- src/librustc/middle/dead.rs | 2 +- src/librustc/middle/traits/coherence.rs | 168 +++++++++ .../typeck/{coherence.rs => coherence/mod.rs} | 343 ++---------------- .../middle/typeck/coherence/orphan.rs | 75 ++++ .../middle/typeck/coherence/overlap.rs | 119 ++++++ src/librustdoc/clean/inline.rs | 2 +- 6 files changed, 400 insertions(+), 309 deletions(-) create mode 100644 src/librustc/middle/traits/coherence.rs rename src/librustc/middle/typeck/{coherence.rs => coherence/mod.rs} (61%) create mode 100644 src/librustc/middle/typeck/coherence/orphan.rs create mode 100644 src/librustc/middle/typeck/coherence/overlap.rs diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 46e3585912a7f..850c6ecffaaa1 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -470,7 +470,7 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { match self.tcx.inherent_impls.borrow().find(&local_def(id)) { None => (), Some(impl_list) => { - for impl_did in impl_list.borrow().iter() { + for impl_did in impl_list.iter() { for item_did in impl_items.get(impl_did).iter() { if self.live_symbols.contains(&item_did.def_id() .node) { diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs new file mode 100644 index 0000000000000..415eed380fc54 --- /dev/null +++ b/src/librustc/middle/traits/coherence.rs @@ -0,0 +1,168 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! See `doc.rs` for high-level documentation */ + +use super::DUMMY_CAUSE; +use super::{EvaluatedToMatch, EvaluatedToAmbiguity, EvaluatedToUnmatch}; +use super::{evaluate_impl}; +use super::util; + +use middle::subst; +use middle::subst::Subst; +use middle::ty; +use middle::typeck::infer::InferCtxt; +use syntax::ast; +use syntax::codemap::DUMMY_SP; +use util::nodemap::DefIdMap; +use util::ppaux::Repr; + +pub fn impl_can_satisfy(infcx: &InferCtxt, + impl1_def_id: ast::DefId, + impl2_def_id: ast::DefId) + -> bool +{ + // `impl1` provides an implementation of `Foo for Z`. + let impl1_substs = + util::fresh_substs_for_impl(infcx, DUMMY_SP, impl1_def_id); + let impl1_self_ty = + ty::impl_trait_ref(infcx.tcx, impl1_def_id).unwrap() + .self_ty() + .subst(infcx.tcx, &impl1_substs); + + // Determine whether `impl2` can provide an implementation for those + // same types. + let param_env = ty::empty_parameter_environment(); + let unboxed_closures = DefIdMap::new(); + match evaluate_impl(infcx, ¶m_env, &unboxed_closures, DUMMY_CAUSE, + impl2_def_id, impl1_self_ty) { + EvaluatedToMatch | EvaluatedToAmbiguity => true, + EvaluatedToUnmatch => false, + } +} + +pub fn impl_is_local(tcx: &ty::ctxt, + impl_def_id: ast::DefId) + -> bool +{ + debug!("impl_is_local({})", impl_def_id.repr(tcx)); + + // We only except this routine to be invoked on implementations + // of a trait, not inherent implementations. + let trait_ref = ty::impl_trait_ref(tcx, impl_def_id).unwrap(); + debug!("trait_ref={}", trait_ref.repr(tcx)); + + // If the trait is local to the crate, ok. + if trait_ref.def_id.krate == ast::LOCAL_CRATE { + debug!("trait {} is local to current crate", + trait_ref.def_id.repr(tcx)); + return true; + } + + // Otherwise, self type must be local to the crate. + let self_ty = ty::lookup_item_type(tcx, impl_def_id).ty; + return ty_is_local(tcx, self_ty); +} + +pub fn ty_is_local(tcx: &ty::ctxt, + ty: ty::t) + -> bool +{ + debug!("ty_is_local({})", ty.repr(tcx)); + + match ty::get(ty).sty { + ty::ty_nil | + ty::ty_bot | + ty::ty_bool | + ty::ty_char | + ty::ty_int(..) | + ty::ty_uint(..) | + ty::ty_float(..) | + ty::ty_str(..) => { + false + } + + ty::ty_unboxed_closure(..) => { + // This routine is invoked on types specified by users as + // part of an impl and hence an unboxed closure type + // cannot appear. + tcx.sess.bug("ty_is_local applied to unboxed closure type") + } + + ty::ty_bare_fn(..) | + ty::ty_closure(..) => { + false + } + + ty::ty_uniq(t) => { + let krate = tcx.lang_items.owned_box().map(|d| d.krate); + krate == Some(ast::LOCAL_CRATE) || ty_is_local(tcx, t) + } + + ty::ty_box(t) => { + let krate = tcx.lang_items.gc().map(|d| d.krate); + krate == Some(ast::LOCAL_CRATE) || ty_is_local(tcx, t) + } + + ty::ty_vec(t, _) | + ty::ty_ptr(ty::mt { ty: t, .. }) | + ty::ty_rptr(_, ty::mt { ty: t, .. }) => { + ty_is_local(tcx, t) + } + + ty::ty_tup(ref ts) => { + ts.iter().any(|&t| ty_is_local(tcx, t)) + } + + ty::ty_enum(def_id, ref substs) | + ty::ty_struct(def_id, ref substs) => { + def_id.krate == ast::LOCAL_CRATE || { + let variances = ty::item_variances(tcx, def_id); + subst::ParamSpace::all().iter().any(|&space| { + substs.types.get_slice(space).iter().enumerate().any( + |(i, &t)| { + match *variances.types.get(space, i) { + ty::Bivariant => { + // If Foo is bivariant with respect to + // T, then it doesn't matter whether T is + // local or not, because `Foo` for any + // U will be a subtype of T. + false + } + ty::Contravariant | + ty::Covariant | + ty::Invariant => { + ty_is_local(tcx, t) + } + } + }) + }) + } + } + + ty::ty_trait(ref tt) => { + tt.def_id.krate == ast::LOCAL_CRATE + } + + // Type parameters may be bound to types that are not local to + // the crate. + ty::ty_param(..) => { + false + } + + ty::ty_infer(..) | + ty::ty_open(..) | + ty::ty_err => { + tcx.sess.bug( + format!("ty_is_local invoked on unexpected type: {}", + ty.repr(tcx)).as_slice()) + } + } +} diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence/mod.rs similarity index 61% rename from src/librustc/middle/typeck/coherence.rs rename to src/librustc/middle/typeck/coherence/mod.rs index 8de17627e2825..76c5cab234f37 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -10,12 +10,13 @@ // Coherence phase // -// The job of the coherence phase of typechecking is to ensure that each trait -// has at most one implementation for each type. Then we build a mapping from -// each trait in the system to its implementations. +// The job of the coherence phase of typechecking is to ensure that +// each trait has at most one implementation for each type. This is +// done by the orphan and overlap modules. Then we build up various +// mappings. That mapping code resides here. -use metadata::csearch::{each_impl, get_impl_trait, each_implementation_for_trait}; +use metadata::csearch::{each_impl, get_impl_trait}; use metadata::csearch; use middle::subst; use middle::subst::{Substs}; @@ -35,27 +36,24 @@ use middle::typeck::CrateCtxt; use middle::typeck::infer::combine::Combine; use middle::typeck::infer::InferCtxt; use middle::typeck::infer::{new_infer_ctxt, resolve_ivar, resolve_type}; -use middle::typeck::infer; -use util::ppaux::Repr; -use middle::def::{DefStruct, DefTy}; +use std::collections::{HashSet}; +use std::cell::RefCell; +use std::rc::Rc; use syntax::ast::{Crate, DefId}; -use syntax::ast::{Item, ItemEnum, ItemImpl, ItemMod, ItemStruct}; -use syntax::ast::{LOCAL_CRATE, TraitRef, TyPath}; +use syntax::ast::{Item, ItemImpl}; +use syntax::ast::{LOCAL_CRATE, TraitRef}; use syntax::ast; use syntax::ast_map::NodeItem; use syntax::ast_map; use syntax::ast_util::{local_def}; -use syntax::codemap::{Span, DUMMY_SP}; +use syntax::codemap::{Span}; use syntax::parse::token; use syntax::visit; +use util::nodemap::{DefIdMap, FnvHashMap}; +use util::ppaux::Repr; -use std::collections::HashSet; -use std::cell::RefCell; -use std::rc::Rc; - -struct UniversalQuantificationResult { - monotype: t -} +mod orphan; +mod overlap; fn get_base_type(inference_context: &InferCtxt, span: Span, @@ -96,53 +94,6 @@ fn get_base_type(inference_context: &InferCtxt, } } -fn type_is_defined_in_local_crate(tcx: &ty::ctxt, original_type: t) -> bool { - /*! - * - * For coherence, when we have `impl Trait for Type`, we need to - * guarantee that `Type` is "local" to the - * crate. For our purposes, this means that it must contain - * some nominal type defined in this crate. - */ - - let mut found_nominal = false; - ty::walk_ty(original_type, |t| { - match get(t).sty { - ty_enum(def_id, _) | - ty_struct(def_id, _) | - ty_unboxed_closure(def_id, _) => { - if def_id.krate == ast::LOCAL_CRATE { - found_nominal = true; - } - } - ty_trait(box ty::TyTrait { def_id, .. }) => { - if def_id.krate == ast::LOCAL_CRATE { - found_nominal = true; - } - } - ty_uniq(..) => { - match tcx.lang_items.owned_box() { - Some(did) if did.krate == ast::LOCAL_CRATE => { - found_nominal = true; - } - _ => {} - } - } - ty_box(..) => { - match tcx.lang_items.gc() { - Some(did) if did.krate == ast::LOCAL_CRATE => { - found_nominal = true; - } - _ => {} - } - } - - _ => { } - } - }); - return found_nominal; -} - // Returns the def ID of the base type, if there is one. fn get_base_type_def_id(inference_context: &InferCtxt, span: Span, @@ -185,6 +136,7 @@ fn get_base_type_def_id(inference_context: &InferCtxt, struct CoherenceChecker<'a, 'tcx: 'a> { crate_context: &'a CrateCtxt<'a, 'tcx>, inference_context: InferCtxt<'a, 'tcx>, + inherent_impls: RefCell>>>>, } struct CoherenceCheckVisitor<'a, 'tcx: 'a> { @@ -214,57 +166,6 @@ impl<'a, 'tcx, 'v> visit::Visitor<'v> for CoherenceCheckVisitor<'a, 'tcx> { } } -struct PrivilegedScopeVisitor<'a, 'tcx: 'a> { - cc: &'a CoherenceChecker<'a, 'tcx> -} - -impl<'a, 'tcx, 'v> visit::Visitor<'v> for PrivilegedScopeVisitor<'a, 'tcx> { - fn visit_item(&mut self, item: &Item) { - - match item.node { - ItemMod(ref module_) => { - // Then visit the module items. - visit::walk_mod(self, module_); - } - ItemImpl(_, None, ref ast_ty, _) => { - if !self.cc.ast_type_is_defined_in_local_crate(&**ast_ty) { - // This is an error. - let session = &self.cc.crate_context.tcx.sess; - span_err!(session, item.span, E0116, - "cannot associate methods with a type outside the \ - crate the type is defined in; define and implement \ - a trait or new type instead"); - } - } - ItemImpl(_, Some(ref trait_ref), _, _) => { - let tcx = self.cc.crate_context.tcx; - // `for_ty` is `Type` in `impl Trait for Type` - let for_ty = ty::node_id_to_type(tcx, item.id); - if !type_is_defined_in_local_crate(tcx, for_ty) { - // This implementation is not in scope of its base - // type. This still might be OK if the trait is - // defined in the same crate. - - let trait_def_id = - self.cc.trait_ref_to_trait_def_id(trait_ref); - - if trait_def_id.krate != LOCAL_CRATE { - let session = &self.cc.crate_context.tcx.sess; - span_err!(session, item.span, E0117, - "cannot provide an extension implementation \ - where both trait and type are not defined in this crate"); - } - } - - visit::walk_item(self, item); - } - _ => { - visit::walk_item(self, item); - } - } - } -} - impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { fn check(&self, krate: &Crate) { // Check implementations and traits. This populates the tables @@ -273,11 +174,14 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { let mut visitor = CoherenceCheckVisitor { cc: self }; visit::walk_crate(&mut visitor, krate); - // Check that there are no overlapping trait instances - self.check_implementation_coherence(); - - // Check whether traits with base types are in privileged scopes. - self.check_privileged_scopes(krate); + // Copy over the inherent impls we gathered up during the walk into + // the tcx. + let mut tcx_inherent_impls = + self.crate_context.tcx.inherent_impls.borrow_mut(); + for (k, v) in self.inherent_impls.borrow().iter() { + tcx_inherent_impls.insert((*k).clone(), + Rc::new((*v.borrow()).clone())); + } // Bring in external crates. It's fine for this to happen after the // coherence checks, because we ensure by construction that no errors @@ -290,7 +194,8 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { self.populate_destructor_table(); } - fn check_implementation(&self, item: &Item, + fn check_implementation(&self, + item: &Item, associated_traits: &[TraitRef]) { let tcx = self.crate_context.tcx; let impl_did = local_def(item.id); @@ -299,25 +204,6 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { // If there are no traits, then this implementation must have a // base type. - if associated_traits.len() == 0 { - debug!("(checking implementation) no associated traits for item '{}'", - token::get_ident(item.ident)); - - match get_base_type_def_id(&self.inference_context, - item.span, - self_type.ty) { - None => { - let session = &self.crate_context.tcx.sess; - span_err!(session, item.span, E0118, - "no base type found for inherent implementation; \ - implement a trait or new type instead"); - } - Some(_) => { - // Nothing to do. - } - } - } - let impl_items = self.create_impl_from_item(item); for associated_trait in associated_traits.iter() { @@ -408,8 +294,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { } fn add_inherent_impl(&self, base_def_id: DefId, impl_def_id: DefId) { - let tcx = self.crate_context.tcx; - match tcx.inherent_impls.borrow().find(&base_def_id) { + match self.inherent_impls.borrow().find(&base_def_id) { Some(implementation_list) => { implementation_list.borrow_mut().push(impl_def_id); return; @@ -417,178 +302,24 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { None => {} } - tcx.inherent_impls.borrow_mut().insert(base_def_id, - Rc::new(RefCell::new(vec!(impl_def_id)))); + self.inherent_impls.borrow_mut().insert( + base_def_id, + Rc::new(RefCell::new(vec!(impl_def_id)))); } fn add_trait_impl(&self, base_def_id: DefId, impl_def_id: DefId) { + debug!("add_trait_impl: base_def_id={} impl_def_id={}", + base_def_id, impl_def_id); ty::record_trait_implementation(self.crate_context.tcx, base_def_id, impl_def_id); } - fn check_implementation_coherence(&self) { - for trait_id in self.crate_context.tcx.trait_impls.borrow().keys() { - self.check_implementation_coherence_of(*trait_id); - } - } - - fn check_implementation_coherence_of(&self, trait_def_id: DefId) { - // Unify pairs of polytypes. - self.iter_impls_of_trait_local(trait_def_id, |impl_a| { - let polytype_a = - self.get_self_type_for_implementation(impl_a); - - // "We have an impl of trait for type , - // and that impl is " - self.iter_impls_of_trait(trait_def_id, |impl_b| { - - // An impl is coherent with itself - if impl_a != impl_b { - let polytype_b = self.get_self_type_for_implementation( - impl_b); - - if self.polytypes_unify(polytype_a.clone(), polytype_b) { - let session = &self.crate_context.tcx.sess; - span_err!(session, self.span_of_impl(impl_a), E0119, - "conflicting implementations for trait `{}`", - ty::item_path_str(self.crate_context.tcx, trait_def_id)); - if impl_b.krate == LOCAL_CRATE { - span_note!(session, self.span_of_impl(impl_b), - "note conflicting implementation here"); - } else { - let crate_store = &self.crate_context.tcx.sess.cstore; - let cdata = crate_store.get_crate_data(impl_b.krate); - span_note!(session, self.span_of_impl(impl_a), - "conflicting implementation in crate `{}`", - cdata.name); - } - } - } - }) - }) - } - - fn iter_impls_of_trait(&self, trait_def_id: DefId, f: |DefId|) { - self.iter_impls_of_trait_local(trait_def_id, |x| f(x)); - - if trait_def_id.krate == LOCAL_CRATE { - return; - } - - let crate_store = &self.crate_context.tcx.sess.cstore; - csearch::each_implementation_for_trait(crate_store, trait_def_id, |impl_def_id| { - // Is this actually necessary? - let _ = lookup_item_type(self.crate_context.tcx, impl_def_id); - f(impl_def_id); - }); - } - - fn iter_impls_of_trait_local(&self, trait_def_id: DefId, f: |DefId|) { - match self.crate_context.tcx.trait_impls.borrow().find(&trait_def_id) { - Some(impls) => { - for &impl_did in impls.borrow().iter() { - f(impl_did); - } - } - None => { /* no impls? */ } - } - } - - fn polytypes_unify(&self, - polytype_a: Polytype, - polytype_b: Polytype) - -> bool { - let universally_quantified_a = - self.universally_quantify_polytype(polytype_a); - let universally_quantified_b = - self.universally_quantify_polytype(polytype_b); - - return self.can_unify_universally_quantified( - &universally_quantified_a, &universally_quantified_b) || - self.can_unify_universally_quantified( - &universally_quantified_b, &universally_quantified_a); - } - - // Converts a polytype to a monotype by replacing all parameters with - // type variables. Returns the monotype and the type variables created. - fn universally_quantify_polytype(&self, polytype: Polytype) - -> UniversalQuantificationResult - { - let substitutions = - self.inference_context.fresh_substs_for_type(DUMMY_SP, - &polytype.generics); - let monotype = polytype.ty.subst(self.crate_context.tcx, &substitutions); - - UniversalQuantificationResult { - monotype: monotype - } - } - - fn can_unify_universally_quantified<'a>(&self, - a: &'a UniversalQuantificationResult, - b: &'a UniversalQuantificationResult) - -> bool - { - infer::can_mk_subty(&self.inference_context, - a.monotype, - b.monotype).is_ok() - } - fn get_self_type_for_implementation(&self, impl_did: DefId) -> Polytype { self.crate_context.tcx.tcache.borrow().get_copy(&impl_did) } - // Privileged scope checking - fn check_privileged_scopes(&self, krate: &Crate) { - let mut visitor = PrivilegedScopeVisitor{ cc: self }; - visit::walk_crate(&mut visitor, krate); - } - - fn trait_ref_to_trait_def_id(&self, trait_ref: &TraitRef) -> DefId { - let def_map = &self.crate_context.tcx.def_map; - let trait_def = def_map.borrow().get_copy(&trait_ref.ref_id); - let trait_id = trait_def.def_id(); - return trait_id; - } - - /// For coherence, when we have `impl Type`, we need to guarantee that - /// `Type` is "local" to the crate. For our purposes, this means that it - /// must precisely name some nominal type defined in this crate. - fn ast_type_is_defined_in_local_crate(&self, original_type: &ast::Ty) -> bool { - match original_type.node { - TyPath(_, _, path_id) => { - match self.crate_context.tcx.def_map.borrow().get_copy(&path_id) { - DefTy(def_id) | DefStruct(def_id) => { - if def_id.krate != LOCAL_CRATE { - return false; - } - - // Make sure that this type precisely names a nominal - // type. - match self.crate_context.tcx.map.find(def_id.node) { - None => { - self.crate_context.tcx.sess.span_bug( - original_type.span, - "resolve didn't resolve this type?!"); - } - Some(NodeItem(item)) => { - match item.node { - ItemStruct(..) | ItemEnum(..) => true, - _ => false, - } - } - Some(_) => false, - } - } - _ => false - } - } - _ => false - } - } - // Converts an implementation in the AST to a vector of items. fn create_impl_from_item(&self, item: &Item) -> Vec { match item.node { @@ -623,11 +354,6 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { } } - fn span_of_impl(&self, impl_did: DefId) -> Span { - assert_eq!(impl_did.krate, LOCAL_CRATE); - self.crate_context.tcx.map.span(impl_did.node) - } - // External crate handling fn add_external_impl(&self, @@ -824,5 +550,8 @@ pub fn check_coherence(crate_context: &CrateCtxt) { CoherenceChecker { crate_context: crate_context, inference_context: new_infer_ctxt(crate_context.tcx), + inherent_impls: RefCell::new(FnvHashMap::new()), }.check(crate_context.tcx.map.krate()); + orphan::check(crate_context.tcx); + overlap::check(crate_context.tcx); } diff --git a/src/librustc/middle/typeck/coherence/orphan.rs b/src/librustc/middle/typeck/coherence/orphan.rs new file mode 100644 index 0000000000000..e7139e1229b23 --- /dev/null +++ b/src/librustc/middle/typeck/coherence/orphan.rs @@ -0,0 +1,75 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! + * Orphan checker: every impl either implements a trait defined in this + * crate or pertains to a type defined in this crate. + */ + +use middle::traits; +use middle::ty; +use syntax::ast::{Item, ItemImpl}; +use syntax::ast; +use syntax::ast_util; +use syntax::visit; +use util::ppaux::Repr; + +pub fn check(tcx: &ty::ctxt) { + let mut orphan = OrphanChecker { tcx: tcx }; + visit::walk_crate(&mut orphan, tcx.map.krate()); +} + +struct OrphanChecker<'cx, 'tcx:'cx> { + tcx: &'cx ty::ctxt<'tcx> +} + +impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> { + fn visit_item(&mut self, item: &'v ast::Item) { + let def_id = ast_util::local_def(item.id); + match item.node { + ast::ItemImpl(_, None, _, _) => { + // For inherent impls, self type must be a nominal type + // defined in this crate. + debug!("coherence2::orphan check: inherent impl {}", item.repr(self.tcx)); + let self_ty = ty::lookup_item_type(self.tcx, def_id).ty; + match ty::get(self_ty).sty { + ty::ty_enum(def_id, _) | + ty::ty_struct(def_id, _) => { + if def_id.krate != ast::LOCAL_CRATE { + span_err!(self.tcx.sess, item.span, E0116, + "cannot associate methods with a type outside the \ + crate the type is defined in; define and implement \ + a trait or new type instead"); + } + } + _ => { + span_err!(self.tcx.sess, item.span, E0118, + "no base type found for inherent implementation; \ + implement a trait or new type instead"); + } + } + } + ast::ItemImpl(_, Some(_), _, _) => { + // "Trait" impl + debug!("coherence2::orphan check: trait impl {}", item.repr(self.tcx)); + if traits::is_orphan_impl(self.tcx, def_id) { + span_err!(self.tcx.sess, item.span, E0117, + "cannot provide an extension implementation \ + where both trait and type are not defined in this crate"); + } + } + _ => { + // Not an impl + } + } + + visit::walk_item(self, item); + } +} diff --git a/src/librustc/middle/typeck/coherence/overlap.rs b/src/librustc/middle/typeck/coherence/overlap.rs new file mode 100644 index 0000000000000..48f71d95c429a --- /dev/null +++ b/src/librustc/middle/typeck/coherence/overlap.rs @@ -0,0 +1,119 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! + * Overlap: No two impls for the same trait are implemented for the + * same type. + */ + +use middle::traits; +use middle::ty; +use middle::typeck::infer::{new_infer_ctxt}; +use middle::typeck::infer; +use syntax::ast::{DefId}; +use syntax::ast::{LOCAL_CRATE}; +use syntax::ast; +use syntax::codemap::{Span}; +use util::ppaux::Repr; + +pub fn check(tcx: &ty::ctxt) { + let overlap = OverlapChecker { tcx: tcx }; + overlap.check_for_overlapping_impls(); +} + +struct OverlapChecker<'cx, 'tcx:'cx> { + tcx: &'cx ty::ctxt<'tcx> +} + +impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> { + fn check_for_overlapping_impls(&self) { + debug!("check_for_overlapping_impls"); + let trait_impls = self.tcx.trait_impls.borrow(); + for trait_def_id in trait_impls.keys() { + self.check_for_overlapping_impls_of_trait(*trait_def_id); + } + } + + fn check_for_overlapping_impls_of_trait(&self, + trait_def_id: ast::DefId) + { + debug!("check_for_overlapping_impls_of_trait(trait_def_id={})", + trait_def_id.repr(self.tcx)); + + // FIXME -- it seems like this method actually pushes + // duplicate impls onto the list + ty::populate_implementations_for_type_if_necessary(self.tcx, + trait_def_id); + + let mut impls = Vec::new(); + self.push_impls_of_trait(trait_def_id, &mut impls); + + for (i, &impl1_def_id) in impls.iter().enumerate() { + if impl1_def_id.krate != ast::LOCAL_CRATE { + // we don't need to check impls if both are external; + // that's the other crate's job. + continue; + } + + for &impl2_def_id in impls.slice_from(i+1).iter() { + self.check_if_impls_overlap(trait_def_id, + impl1_def_id, + impl2_def_id); + } + } + } + + fn check_if_impls_overlap(&self, + trait_def_id: ast::DefId, + impl1_def_id: ast::DefId, + impl2_def_id: ast::DefId) + { + assert_eq!(impl1_def_id.krate, ast::LOCAL_CRATE); + + debug!("check_if_impls_overlap({}, {}, {})", + trait_def_id.repr(self.tcx), + impl1_def_id.repr(self.tcx), + impl2_def_id.repr(self.tcx)); + + let infcx = infer::new_infer_ctxt(self.tcx); + if !traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id) { + return; + } + + span_err!(self.tcx.sess, self.span_of_impl(impl1_def_id), E0119, + "conflicting implementations for trait `{}`", + ty::item_path_str(self.tcx, trait_def_id)); + + if impl2_def_id.krate == ast::LOCAL_CRATE { + span_note!(self.tcx.sess, self.span_of_impl(impl2_def_id), + "note conflicting implementation here"); + } else { + let crate_store = &self.tcx.sess.cstore; + let cdata = crate_store.get_crate_data(impl2_def_id.krate); + span_note!(self.tcx.sess, self.span_of_impl(impl1_def_id), + "conflicting implementation in crate `{}`", + cdata.name); + } + } + + fn push_impls_of_trait(&self, + trait_def_id: ast::DefId, + out: &mut Vec) { + match self.tcx.trait_impls.borrow().find(&trait_def_id) { + Some(impls) => { out.push_all(impls.borrow().as_slice()); } + None => { /* no impls */ } + } + } + + fn span_of_impl(&self, impl_did: ast::DefId) -> Span { + assert_eq!(impl_did.krate, ast::LOCAL_CRATE); + self.tcx.map.span(impl_did.node) + } +} diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index e0afb80ad37f5..7272425761e02 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -226,7 +226,7 @@ fn build_impls(cx: &DocContext, tcx: &ty::ctxt, match tcx.inherent_impls.borrow().find(&did) { None => {} Some(i) => { - impls.extend(i.borrow().iter().map(|&did| { build_impl(cx, tcx, did) })); + impls.extend(i.iter().map(|&did| { build_impl(cx, tcx, did) })); } } From 088c94ae96aa139db6b6f0c5640c720ff107ee0f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 12 Sep 2014 11:42:58 -0400 Subject: [PATCH 05/10] trans -- stop tracking vtables precisely, instead recompute as needed. --- src/librustc/lint/builtin.rs | 10 +- src/librustc/metadata/common.rs | 3 +- src/librustc/metadata/encoder.rs | 28 +- src/librustc/middle/astencode.rs | 240 +++++++++--- src/librustc/middle/dead.rs | 10 +- src/librustc/middle/expr_use_visitor.rs | 8 +- src/librustc/middle/privacy.rs | 14 +- src/librustc/middle/save/mod.rs | 8 +- src/librustc/middle/subst.rs | 5 + src/librustc/middle/trans/base.rs | 4 +- src/librustc/middle/trans/callee.rs | 111 ++---- src/librustc/middle/trans/common.rs | 188 +++++----- src/librustc/middle/trans/context.rs | 13 +- src/librustc/middle/trans/expr.rs | 24 +- src/librustc/middle/trans/meth.rs | 367 ++++++++++--------- src/librustc/middle/trans/monomorphize.rs | 6 +- src/librustc/middle/ty.rs | 88 +++-- src/librustc/middle/ty_fold.rs | 25 ++ src/librustc/middle/typeck/infer/coercion.rs | 28 +- src/librustc/middle/typeck/infer/combine.rs | 53 +-- src/librustc/middle/typeck/mod.rs | 34 +- 21 files changed, 723 insertions(+), 544 deletions(-) diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 58c05bee44373..eed41edac9d6c 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -1470,17 +1470,17 @@ impl LintPass for Stability { def_id } typeck::MethodParam(typeck::MethodParam { - trait_id: trait_id, + trait_ref: ref trait_ref, method_num: index, .. - }) - | typeck::MethodObject(typeck::MethodObject { - trait_id: trait_id, + }) | + typeck::MethodObject(typeck::MethodObject { + trait_ref: ref trait_ref, method_num: index, .. }) => { match ty::trait_item(cx.tcx, - trait_id, + trait_ref.def_id, index) { ty::MethodTraitItem(method) => { method.def_id diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index ca2f47328db90..3ec91bf984052 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -140,9 +140,10 @@ pub enum astencode_tag { // Reserves 0x40 -- 0x5f tag_table_unboxed_closures = 0x54, tag_table_upvar_borrow_map = 0x55, tag_table_capture_modes = 0x56, + tag_table_object_cast_map = 0x57, } static first_astencode_tag: uint = tag_ast as uint; -static last_astencode_tag: uint = tag_table_capture_modes as uint; +static last_astencode_tag: uint = tag_table_object_cast_map as uint; impl astencode_tag { pub fn from_uint(value : uint) -> Option { let is_a_tag = first_astencode_tag <= value && value <= last_astencode_tag; diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 376cccc3f10fc..3ab50b0efd17c 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -20,9 +20,7 @@ use metadata::cstore; use metadata::decoder; use metadata::tyencode; use middle::ty::{lookup_item_type}; -use middle::astencode; use middle::ty; -use middle::typeck; use middle::stability; use middle; use util::nodemap::{NodeMap, NodeSet}; @@ -125,14 +123,6 @@ fn encode_trait_ref(rbml_w: &mut Encoder, rbml_w.end_tag(); } -fn encode_impl_vtables(rbml_w: &mut Encoder, - ecx: &EncodeContext, - vtables: &typeck::vtable_res) { - rbml_w.start_tag(tag_item_impl_vtables); - astencode::encode_vtable_res(ecx, rbml_w, vtables); - rbml_w.end_tag(); -} - // Item info table encoding fn encode_family(rbml_w: &mut Encoder, c: char) { rbml_w.start_tag(tag_items_data_item_family); @@ -191,6 +181,18 @@ pub fn write_type(ecx: &EncodeContext, tyencode::enc_ty(rbml_w.writer, ty_str_ctxt, typ); } +pub fn write_trait_ref(ecx: &EncodeContext, + rbml_w: &mut Encoder, + trait_ref: &ty::TraitRef) { + let ty_str_ctxt = &tyencode::ctxt { + diag: ecx.diag, + ds: def_to_string, + tcx: ecx.tcx, + abbrevs: &ecx.type_abbrevs + }; + tyencode::enc_trait_ref(rbml_w.writer, ty_str_ctxt, trait_ref); +} + pub fn write_region(ecx: &EncodeContext, rbml_w: &mut Encoder, r: ty::Region) { @@ -399,7 +401,7 @@ fn encode_reexported_static_base_methods(ecx: &EncodeContext, let impl_items = ecx.tcx.impl_items.borrow(); match ecx.tcx.inherent_impls.borrow().find(&exp.def_id) { Some(implementations) => { - for base_impl_did in implementations.borrow().iter() { + for base_impl_did in implementations.iter() { for &method_did in impl_items.get(base_impl_did).iter() { let impl_item = ty::impl_or_trait_item( ecx.tcx, @@ -946,7 +948,7 @@ fn encode_inherent_implementations(ecx: &EncodeContext, match ecx.tcx.inherent_impls.borrow().find(&def_id) { None => {} Some(implementations) => { - for &impl_def_id in implementations.borrow().iter() { + for &impl_def_id in implementations.iter() { rbml_w.start_tag(tag_items_data_item_inherent_impl); encode_def_id(rbml_w, impl_def_id); rbml_w.end_tag(); @@ -1203,8 +1205,6 @@ fn encode_info_for_item(ecx: &EncodeContext, let trait_ref = ty::node_id_to_trait_ref( tcx, ast_trait_ref.ref_id); encode_trait_ref(rbml_w, ecx, &*trait_ref, tag_item_trait_ref); - let impl_vtables = ty::lookup_impl_vtables(tcx, def_id); - encode_impl_vtables(rbml_w, ecx, &impl_vtables); } encode_path(rbml_w, path.clone()); encode_stability(rbml_w, stab); diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 2dab3c2b1da02..21d0292d2fe3a 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -43,6 +43,7 @@ use libc; use std::io::Seek; use std::mem; use std::gc::GC; +use std::rc::Rc; use rbml::io::SeekableMemWriter; use rbml::{reader, writer}; @@ -589,7 +590,7 @@ fn encode_method_callee(ecx: &e::EncodeContext, adjustment.encode(rbml_w) }); rbml_w.emit_struct_field("origin", 1u, |rbml_w| { - method.origin.encode(rbml_w) + Ok(rbml_w.emit_method_origin(ecx, &method.origin)) }); rbml_w.emit_struct_field("ty", 2u, |rbml_w| { Ok(rbml_w.emit_ty(ecx, method.ty)) @@ -610,9 +611,7 @@ impl<'a> read_method_callee_helper for reader::Decoder<'a> { }).unwrap(); Ok((adjustment, MethodCallee { origin: this.read_struct_field("origin", 1, |this| { - let method_origin: MethodOrigin = - Decodable::decode(this).unwrap(); - Ok(method_origin.tr(dcx)) + Ok(this.read_method_origin(dcx)) }).unwrap(), ty: this.read_struct_field("ty", 2, |this| { Ok(this.read_ty(dcx)) @@ -635,15 +634,16 @@ impl tr for MethodOrigin { typeck::MethodParam(ref mp) => { typeck::MethodParam( typeck::MethodParam { - trait_id: mp.trait_id.tr(dcx), - .. *mp + // def-id is already translated when we read it out + trait_ref: mp.trait_ref.clone(), + method_num: mp.method_num, } ) } typeck::MethodObject(ref mo) => { typeck::MethodObject( typeck::MethodObject { - trait_id: mo.trait_id.tr(dcx), + trait_ref: mo.trait_ref.clone(), .. *mo } ) @@ -655,22 +655,6 @@ impl tr for MethodOrigin { // ______________________________________________________________________ // Encoding and decoding vtable_res -fn encode_vtable_res_with_key(ecx: &e::EncodeContext, - rbml_w: &mut Encoder, - adjustment: typeck::ExprAdjustment, - dr: &typeck::vtable_res) { - use serialize::Encoder; - - rbml_w.emit_struct("VtableWithKey", 2, |rbml_w| { - rbml_w.emit_struct_field("adjustment", 0u, |rbml_w| { - adjustment.encode(rbml_w) - }); - rbml_w.emit_struct_field("vtable_res", 1u, |rbml_w| { - Ok(encode_vtable_res(ecx, rbml_w, dr)) - }) - }).unwrap() -} - pub fn encode_vtable_res(ecx: &e::EncodeContext, rbml_w: &mut Encoder, dr: &typeck::vtable_res) { @@ -913,11 +897,15 @@ trait rbml_writer_helpers { fn emit_closure_type(&mut self, ecx: &e::EncodeContext, closure_type: &ty::ClosureTy); + fn emit_method_origin(&mut self, + ecx: &e::EncodeContext, + method_origin: &typeck::MethodOrigin); fn emit_ty(&mut self, ecx: &e::EncodeContext, ty: ty::t); fn emit_tys(&mut self, ecx: &e::EncodeContext, tys: &[ty::t]); fn emit_type_param_def(&mut self, ecx: &e::EncodeContext, type_param_def: &ty::TypeParameterDef); + fn emit_trait_ref(&mut self, ecx: &e::EncodeContext, ty: &ty::TraitRef); fn emit_polytype(&mut self, ecx: &e::EncodeContext, pty: ty::Polytype); @@ -939,6 +927,63 @@ impl<'a> rbml_writer_helpers for Encoder<'a> { }); } + fn emit_method_origin(&mut self, + ecx: &e::EncodeContext, + method_origin: &typeck::MethodOrigin) + { + use serialize::Encoder; + + self.emit_enum("MethodOrigin", |this| { + match *method_origin { + typeck::MethodStatic(def_id) => { + this.emit_enum_variant("MethodStatic", 0, 1, |this| { + Ok(this.emit_def_id(def_id)) + }) + } + + typeck::MethodStaticUnboxedClosure(def_id) => { + this.emit_enum_variant("MethodStaticUnboxedClosure", 1, 1, |this| { + Ok(this.emit_def_id(def_id)) + }) + } + + typeck::MethodParam(ref p) => { + this.emit_enum_variant("MethodParam", 2, 1, |this| { + this.emit_struct("MethodParam", 2, |this| { + try!(this.emit_struct_field("trait_ref", 0, |this| { + Ok(this.emit_trait_ref(ecx, &*p.trait_ref)) + })); + try!(this.emit_struct_field("method_num", 0, |this| { + this.emit_uint(p.method_num) + })); + Ok(()) + }) + }) + } + + typeck::MethodObject(ref o) => { + this.emit_enum_variant("MethodObject", 3, 1, |this| { + this.emit_struct("MethodObject", 2, |this| { + try!(this.emit_struct_field("trait_ref", 0, |this| { + Ok(this.emit_trait_ref(ecx, &*o.trait_ref)) + })); + try!(this.emit_struct_field("object_trait_id", 0, |this| { + Ok(this.emit_def_id(o.object_trait_id)) + })); + try!(this.emit_struct_field("method_num", 0, |this| { + this.emit_uint(o.method_num) + })); + try!(this.emit_struct_field("real_index", 0, |this| { + this.emit_uint(o.real_index) + })); + Ok(()) + }) + }) + } + } + }); + } + fn emit_ty(&mut self, ecx: &e::EncodeContext, ty: ty::t) { self.emit_opaque(|this| Ok(e::write_type(ecx, this, ty))); } @@ -947,6 +992,12 @@ impl<'a> rbml_writer_helpers for Encoder<'a> { self.emit_from_vec(tys, |this, ty| Ok(this.emit_ty(ecx, *ty))); } + fn emit_trait_ref(&mut self, + ecx: &e::EncodeContext, + trait_ref: &ty::TraitRef) { + self.emit_opaque(|this| Ok(e::write_trait_ref(ecx, this, trait_ref))); + } + fn emit_type_param_def(&mut self, ecx: &e::EncodeContext, type_param_def: &ty::TypeParameterDef) { @@ -1103,12 +1154,16 @@ impl<'a> rbml_writer_helpers for Encoder<'a> { this.emit_enum_variant_arg(1, |this| idx.encode(this)) }) } - ty::UnsizeVtable(ref b, def_id, ref substs) => { - this.emit_enum_variant("UnsizeVtable", 2, 3, |this| { + ty::UnsizeVtable(ty::TyTrait { def_id: def_id, + bounds: ref b, + substs: ref substs }, + self_ty) => { + this.emit_enum_variant("UnsizeVtable", 2, 4, |this| { this.emit_enum_variant_arg( 0, |this| Ok(this.emit_existential_bounds(ecx, b))); this.emit_enum_variant_arg(1, |this| def_id.encode(this)); - this.emit_enum_variant_arg(2, |this| Ok(this.emit_substs(ecx, substs))) + this.emit_enum_variant_arg(2, |this| Ok(this.emit_ty(ecx, self_ty))); + this.emit_enum_variant_arg(3, |this| Ok(this.emit_substs(ecx, substs))) }) } } @@ -1282,11 +1337,11 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, }) } - for &dr in tcx.vtable_map.borrow().find(&method_call).iter() { - rbml_w.tag(c::tag_table_vtable_map, |rbml_w| { + for &trait_ref in tcx.object_cast_map.borrow().find(&id).iter() { + rbml_w.tag(c::tag_table_object_cast_map, |rbml_w| { rbml_w.id(id); rbml_w.tag(c::tag_table_val, |rbml_w| { - encode_vtable_res_with_key(ecx, rbml_w, method_call.adjustment, dr); + rbml_w.emit_trait_ref(ecx, &**trait_ref); }) }) } @@ -1303,15 +1358,6 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, }) }) } - - for &dr in tcx.vtable_map.borrow().find(&method_call).iter() { - rbml_w.tag(c::tag_table_vtable_map, |rbml_w| { - rbml_w.id(id); - rbml_w.tag(c::tag_table_val, |rbml_w| { - encode_vtable_res_with_key(ecx, rbml_w, method_call.adjustment, dr); - }) - }) - } } ty::AutoDerefRef(ref adj) => { assert!(!ty::adjust_is_object(adjustment)); @@ -1326,16 +1372,6 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, }) }) } - - for &dr in tcx.vtable_map.borrow().find(&method_call).iter() { - rbml_w.tag(c::tag_table_vtable_map, |rbml_w| { - rbml_w.id(id); - rbml_w.tag(c::tag_table_val, |rbml_w| { - encode_vtable_res_with_key(ecx, rbml_w, - method_call.adjustment, dr); - }) - }) - } } } _ => { @@ -1378,8 +1414,10 @@ impl<'a> doc_decoder_helpers for rbml::Doc<'a> { } trait rbml_decoder_decoder_helpers { + fn read_method_origin(&mut self, dcx: &DecodeContext) -> typeck::MethodOrigin; fn read_ty(&mut self, dcx: &DecodeContext) -> ty::t; fn read_tys(&mut self, dcx: &DecodeContext) -> Vec; + fn read_trait_ref(&mut self, dcx: &DecodeContext) -> Rc; fn read_type_param_def(&mut self, dcx: &DecodeContext) -> ty::TypeParameterDef; fn read_polytype(&mut self, dcx: &DecodeContext) @@ -1447,6 +1485,77 @@ impl<'a> rbml_decoder_decoder_helpers for reader::Decoder<'a> { }).unwrap() } + fn read_method_origin(&mut self, dcx: &DecodeContext) + -> typeck::MethodOrigin + { + self.read_enum("MethodOrigin", |this| { + let variants = ["MethodStatic", "MethodStaticUnboxedClosure", + "MethodParam", "MethodObject"]; + this.read_enum_variant(variants, |this, i| { + Ok(match i { + 0 => { + let def_id = this.read_def_id(dcx); + typeck::MethodStatic(def_id) + } + + 1 => { + let def_id = this.read_def_id(dcx); + typeck::MethodStaticUnboxedClosure(def_id) + } + + 2 => { + this.read_struct("MethodParam", 2, |this| { + Ok(typeck::MethodParam( + typeck::MethodParam { + trait_ref: { + this.read_struct_field("trait_ref", 0, |this| { + Ok(this.read_trait_ref(dcx)) + }).unwrap() + }, + method_num: { + this.read_struct_field("method_num", 1, |this| { + this.read_uint() + }).unwrap() + } + })) + }).unwrap() + } + + 3 => { + this.read_struct("MethodObject", 2, |this| { + Ok(typeck::MethodObject( + typeck::MethodObject { + trait_ref: { + this.read_struct_field("trait_ref", 0, |this| { + Ok(this.read_trait_ref(dcx)) + }).unwrap() + }, + object_trait_id: { + this.read_struct_field("object_trait_id", 1, |this| { + Ok(this.read_def_id(dcx)) + }).unwrap() + }, + method_num: { + this.read_struct_field("method_num", 2, |this| { + this.read_uint() + }).unwrap() + }, + real_index: { + this.read_struct_field("real_index", 3, |this| { + this.read_uint() + }).unwrap() + }, + })) + }).unwrap() + } + + _ => fail!("..") + }) + }) + }).unwrap() + } + + fn read_ty(&mut self, dcx: &DecodeContext) -> ty::t { // Note: regions types embed local node ids. In principle, we // should translate these node ids into the new decode @@ -1479,6 +1588,18 @@ impl<'a> rbml_decoder_decoder_helpers for reader::Decoder<'a> { self.read_to_vec(|this| Ok(this.read_ty(dcx))).unwrap().move_iter().collect() } + fn read_trait_ref(&mut self, dcx: &DecodeContext) -> Rc { + Rc::new(self.read_opaque(|this, doc| { + let ty = tydecode::parse_trait_ref_data( + doc.data, + dcx.cdata.cnum, + doc.start, + dcx.tcx, + |s, a| this.convert_def_id(dcx, s, a)); + Ok(ty) + }).unwrap()) + } + fn read_type_param_def(&mut self, dcx: &DecodeContext) -> ty::TypeParameterDef { self.read_opaque(|this, doc| { @@ -1667,10 +1788,14 @@ impl<'a> rbml_decoder_decoder_helpers for reader::Decoder<'a> { 0, |this| Ok(this.read_existential_bounds(dcx))).unwrap(); let def_id: ast::DefId = this.read_enum_variant_arg(1, |this| Decodable::decode(this)).unwrap(); - let substs = this.read_enum_variant_arg(2, + let self_ty = + this.read_enum_variant_arg(2, |this| Ok(this.read_ty(dcx))).unwrap(); + let substs = this.read_enum_variant_arg(3, |this| Ok(this.read_substs(dcx))).unwrap(); - - ty::UnsizeVtable(b, def_id.tr(dcx), substs) + let ty_trait = ty::TyTrait { def_id: def_id.tr(dcx), + bounds: b, + substs: substs }; + ty::UnsizeVtable(ty_trait, self_ty) } _ => fail!("bad enum variant for ty::UnsizeKind") }) @@ -1828,15 +1953,10 @@ fn decode_side_tables(dcx: &DecodeContext, }; dcx.tcx.method_map.borrow_mut().insert(method_call, method); } - c::tag_table_vtable_map => { - let (adjustment, vtable_res) = - val_dsr.read_vtable_res_with_key(dcx.tcx, - dcx.cdata); - let vtable_key = MethodCall { - expr_id: id, - adjustment: adjustment - }; - dcx.tcx.vtable_map.borrow_mut().insert(vtable_key, vtable_res); + c::tag_table_object_cast_map => { + let trait_ref = val_dsr.read_trait_ref(dcx); + dcx.tcx.object_cast_map.borrow_mut() + .insert(id, trait_ref); } c::tag_table_adjustments => { let adj: ty::AutoAdjustment = val_dsr.read_auto_adjustment(dcx); diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 850c6ecffaaa1..f13c6bc3336fc 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -102,17 +102,17 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { } typeck::MethodStaticUnboxedClosure(_) => {} typeck::MethodParam(typeck::MethodParam { - trait_id: trait_id, + trait_ref: ref trait_ref, method_num: index, .. - }) - | typeck::MethodObject(typeck::MethodObject { - trait_id: trait_id, + }) | + typeck::MethodObject(typeck::MethodObject { + trait_ref: ref trait_ref, method_num: index, .. }) => { let trait_item = ty::trait_item(self.tcx, - trait_id, + trait_ref.def_id, index); match trait_item { ty::MethodTraitItem(method) => { diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 1e79ea68eebac..d6c11caefe84b 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -174,11 +174,9 @@ impl OverloadedCallType { MethodStaticUnboxedClosure(def_id) => { OverloadedCallType::from_unboxed_closure(tcx, def_id) } - MethodParam(ref method_param) => { - OverloadedCallType::from_trait_id(tcx, method_param.trait_id) - } - MethodObject(ref method_object) => { - OverloadedCallType::from_trait_id(tcx, method_object.trait_id) + MethodParam(MethodParam { trait_ref: ref trait_ref, .. }) | + MethodObject(MethodObject { trait_ref: ref trait_ref, .. }) => { + OverloadedCallType::from_trait_id(tcx, trait_ref.def_id) } } } diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index feacbf84f6739..56c785d3c2592 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -782,19 +782,19 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { } // Checks that a method is in scope. - fn check_method(&mut self, span: Span, origin: MethodOrigin, + fn check_method(&mut self, span: Span, origin: &MethodOrigin, ident: ast::Ident) { - match origin { + match *origin { MethodStatic(method_id) => { self.check_static_method(span, method_id, ident) } MethodStaticUnboxedClosure(_) => {} // Trait methods are always all public. The only controlling factor // is whether the trait itself is accessible or not. - MethodParam(MethodParam { trait_id: trait_id, .. }) | - MethodObject(MethodObject { trait_id: trait_id, .. }) => { - self.report_error(self.ensure_public(span, trait_id, None, - "source trait")); + MethodParam(MethodParam { trait_ref: ref trait_ref, .. }) | + MethodObject(MethodObject { trait_ref: ref trait_ref, .. }) => { + self.report_error(self.ensure_public(span, trait_ref.def_id, + None, "source trait")); } } } @@ -835,7 +835,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { } Some(method) => { debug!("(privacy checking) checking impl method"); - self.check_method(expr.span, method.origin, ident.node); + self.check_method(expr.span, &method.origin, ident.node); } } } diff --git a/src/librustc/middle/save/mod.rs b/src/librustc/middle/save/mod.rs index 04e04efd93c26..5859e5ceeeeb1 100644 --- a/src/librustc/middle/save/mod.rs +++ b/src/librustc/middle/save/mod.rs @@ -908,10 +908,10 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { }; (Some(def_id), decl_id) } - typeck::MethodParam(mp) => { + typeck::MethodParam(ref mp) => { // method invoked on a type parameter let trait_item = ty::trait_item(&self.analysis.ty_cx, - mp.trait_id, + mp.trait_ref.def_id, mp.method_num); match trait_item { ty::MethodTraitItem(method) => { @@ -919,10 +919,10 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { } } }, - typeck::MethodObject(mo) => { + typeck::MethodObject(ref mo) => { // method invoked on a trait instance let trait_item = ty::trait_item(&self.analysis.ty_cx, - mo.trait_id, + mo.trait_ref.def_id, mo.method_num); match trait_item { ty::MethodTraitItem(method) => { diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index 23f53d9b4ab80..d7e6fd18ed563 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -164,6 +164,11 @@ impl Substs { s } + pub fn erase_regions(self) -> Substs { + let Substs { types: types, regions: _ } = self; + Substs { types: types, regions: ErasedRegions } + } + pub fn regions<'a>(&'a self) -> &'a VecPerParamSpace { /*! * Since ErasedRegions are only to be used in trans, most of diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index e86df86511870..0230668b15aec 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -75,7 +75,6 @@ use middle::trans::type_of; use middle::trans::type_of::*; use middle::trans::value::Value; use middle::ty; -use middle::typeck; use util::common::indenter; use util::ppaux::{Repr, ty_to_string}; use util::sha2::Sha256; @@ -547,8 +546,7 @@ pub fn get_res_dtor(ccx: &CrateContext, // Since we're in trans we don't care for any region parameters let ref substs = subst::Substs::erased(substs.types.clone()); - let vtables = typeck::check::vtable::trans_resolve_method(ccx.tcx(), did.node, substs); - let (val, _) = monomorphize::monomorphic_fn(ccx, did, substs, vtables, None); + let (val, _) = monomorphize::monomorphic_fn(ccx, did, substs, None); val } else if did.krate == ast::LOCAL_CRATE { diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index 878d95773ada5..ef98a73430264 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -25,7 +25,7 @@ use llvm; use metadata::csearch; use middle::def; use middle::subst; -use middle::subst::{Subst, VecPerParamSpace}; +use middle::subst::{Subst}; use middle::trans::adt; use middle::trans::base; use middle::trans::base::*; @@ -47,7 +47,6 @@ use middle::trans::monomorphize; use middle::trans::type_::Type; use middle::trans::type_of; use middle::ty; -use middle::typeck; use middle::typeck::coherence::make_substs_for_receiver_types; use middle::typeck::MethodCall; use util::ppaux::Repr; @@ -227,61 +226,27 @@ pub fn trans_fn_ref(bcx: Block, def_id: ast::DefId, node: ExprOrMethodCall) -> V let _icx = push_ctxt("trans_fn_ref"); let substs = node_id_substs(bcx, node); - let vtable_key = match node { - ExprId(id) => MethodCall::expr(id), - MethodCall(method_call) => method_call - }; - let vtables = node_vtables(bcx, vtable_key); - debug!("trans_fn_ref(def_id={}, node={:?}, substs={}, vtables={})", + debug!("trans_fn_ref(def_id={}, node={:?}, substs={})", def_id.repr(bcx.tcx()), node, - substs.repr(bcx.tcx()), - vtables.repr(bcx.tcx())); - trans_fn_ref_with_vtables(bcx, def_id, node, substs, vtables) + substs.repr(bcx.tcx())); + trans_fn_ref_with_substs(bcx, def_id, node, substs) } -fn trans_fn_ref_with_vtables_to_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - def_id: ast::DefId, - ref_id: ast::NodeId, - substs: subst::Substs, - vtables: typeck::vtable_res) - -> Callee<'blk, 'tcx> { +fn trans_fn_ref_with_substs_to_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + def_id: ast::DefId, + ref_id: ast::NodeId, + substs: subst::Substs) + -> Callee<'blk, 'tcx> { Callee { bcx: bcx, - data: Fn(trans_fn_ref_with_vtables(bcx, - def_id, - ExprId(ref_id), - substs, - vtables)), + data: Fn(trans_fn_ref_with_substs(bcx, + def_id, + ExprId(ref_id), + substs)), } } -fn resolve_default_method_vtables(bcx: Block, - impl_id: ast::DefId, - substs: &subst::Substs, - impl_vtables: typeck::vtable_res) - -> typeck::vtable_res -{ - // Get the vtables that the impl implements the trait at - let impl_res = ty::lookup_impl_vtables(bcx.tcx(), impl_id); - - // Build up a param_substs that we are going to resolve the - // trait_vtables under. - let param_substs = param_substs { - substs: (*substs).clone(), - vtables: impl_vtables.clone() - }; - - let mut param_vtables = resolve_vtables_under_param_substs( - bcx.tcx(), ¶m_substs, &impl_res); - - // Now we pull any vtables for parameters on the actual method. - param_vtables.push_all(subst::FnSpace, - impl_vtables.get_slice(subst::FnSpace)); - - param_vtables -} - /// Translates the adapter that deconstructs a `Box` object into /// `Trait` so that a by-value self method can be called. pub fn trans_unboxing_shim(bcx: Block, @@ -408,12 +373,11 @@ pub fn trans_unboxing_shim(bcx: Block, llfn } -pub fn trans_fn_ref_with_vtables( +pub fn trans_fn_ref_with_substs( bcx: Block, // def_id: ast::DefId, // def id of fn node: ExprOrMethodCall, // node id of use of fn; may be zero if N/A - substs: subst::Substs, // values for fn's ty params - vtables: typeck::vtable_res) // vtables for the call + substs: subst::Substs) // vtables for the call -> ValueRef { /*! @@ -428,20 +392,18 @@ pub fn trans_fn_ref_with_vtables( * This parameter may be zero; but, if so, the resulting value may not * have the right type, so it must be cast before being used. * - `substs`: values for each of the fn/method's parameters - * - `vtables`: values for each bound on each of the type parameters */ - let _icx = push_ctxt("trans_fn_ref_with_vtables"); + let _icx = push_ctxt("trans_fn_ref_with_substs"); let ccx = bcx.ccx(); let tcx = bcx.tcx(); - debug!("trans_fn_ref_with_vtables(bcx={}, def_id={}, node={:?}, \ - substs={}, vtables={})", + debug!("trans_fn_ref_with_substs(bcx={}, def_id={}, node={:?}, \ + substs={})", bcx.to_str(), def_id.repr(tcx), node, - substs.repr(tcx), - vtables.repr(tcx)); + substs.repr(tcx)); assert!(substs.types.all(|t| !ty::type_needs_infer(*t))); @@ -456,9 +418,8 @@ pub fn trans_fn_ref_with_vtables( // We need to do a bunch of special handling for default methods. // We need to modify the def_id and our substs in order to monomorphize // the function. - let (is_default, def_id, substs, vtables) = - match ty::provided_source(tcx, def_id) { - None => (false, def_id, substs, vtables), + let (is_default, def_id, substs) = match ty::provided_source(tcx, def_id) { + None => (false, def_id, substs), Some(source_id) => { // There are two relevant substitutions when compiling // default methods. First, there is the substitution for @@ -491,23 +452,11 @@ pub fn trans_fn_ref_with_vtables( debug!("trans_fn_with_vtables - default method: \ substs = {}, trait_subst = {}, \ - first_subst = {}, new_subst = {}, \ - vtables = {}", + first_subst = {}, new_subst = {}", substs.repr(tcx), trait_ref.substs.repr(tcx), - first_subst.repr(tcx), new_substs.repr(tcx), - vtables.repr(tcx)); - - let param_vtables = - resolve_default_method_vtables(bcx, - impl_id, - &substs, - vtables); - - debug!("trans_fn_with_vtables - default method: \ - param_vtables = {}", - param_vtables.repr(tcx)); + first_subst.repr(tcx), new_substs.repr(tcx)); - (true, source_id, new_substs, param_vtables) + (true, source_id, new_substs) } } } @@ -556,8 +505,7 @@ pub fn trans_fn_ref_with_vtables( }; let (val, must_cast) = - monomorphize::monomorphic_fn(ccx, def_id, &substs, - vtables, opt_ref_id); + monomorphize::monomorphic_fn(ccx, def_id, &substs, opt_ref_id); let mut val = val; if must_cast && node != ExprId(0) { // Monotype of the REFERENCE to the function (type params @@ -678,11 +626,10 @@ pub fn trans_lang_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, None, fty, |bcx, _| { - trans_fn_ref_with_vtables_to_callee(bcx, - did, - 0, - subst::Substs::empty(), - VecPerParamSpace::empty()) + trans_fn_ref_with_substs_to_callee(bcx, + did, + 0, + subst::Substs::empty()) }, ArgVals(args), dest) diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index bbb9ba4bbb685..60ae26439b483 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -29,8 +29,11 @@ use middle::trans::datum; use middle::trans::debuginfo; use middle::trans::type_::Type; use middle::trans::type_of; +use middle::traits; use middle::ty; +use middle::ty_fold; use middle::typeck; +use middle::typeck::infer; use util::ppaux::Repr; use util::nodemap::{DefIdMap, NodeMap}; @@ -39,6 +42,7 @@ use std::collections::HashMap; use libc::{c_uint, c_longlong, c_ulonglong, c_char}; use std::c_str::ToCStr; use std::cell::{Cell, RefCell}; +use std::rc::Rc; use std::vec::Vec; use syntax::ast::Ident; use syntax::ast; @@ -188,14 +192,12 @@ pub type ExternMap = HashMap; // will only be set in the case of default methods. pub struct param_substs { pub substs: subst::Substs, - pub vtables: typeck::vtable_res, } impl param_substs { pub fn empty() -> param_substs { param_substs { substs: subst::Substs::trans_empty(), - vtables: subst::VecPerParamSpace::empty(), } } @@ -204,15 +206,9 @@ impl param_substs { } } -fn param_substs_to_string(this: ¶m_substs, tcx: &ty::ctxt) -> String { - format!("param_substs(substs={},vtables={})", - this.substs.repr(tcx), - this.vtables.repr(tcx)) -} - impl Repr for param_substs { fn repr(&self, tcx: &ty::ctxt) -> String { - param_substs_to_string(self, tcx) + self.substs.repr(tcx) } } @@ -766,6 +762,98 @@ pub fn expr_ty_adjusted(bcx: Block, ex: &ast::Expr) -> ty::t { monomorphize_type(bcx, ty::expr_ty_adjusted(bcx.tcx(), ex)) } +pub fn fulfill_obligation(ccx: &CrateContext, + span: Span, + trait_ref: Rc) + -> traits::Vtable<()> +{ + /*! + * Attempts to resolve an obligation. The result is a shallow + * vtable resolution -- meaning that we do not (necessarily) resolve + * all nested obligations on the impl. Note that type check should + * guarantee to us that all nested obligations *could be* resolved + * if we wanted to. + */ + + let tcx = ccx.tcx(); + + // Remove any references to regions; this helps improve caching. + let trait_ref = ty_fold::erase_regions(tcx, trait_ref); + + // First check the cache. + match ccx.trait_cache().borrow().find(&trait_ref) { + Some(vtable) => { + info!("Cache hit: {}", trait_ref.repr(ccx.tcx())); + return (*vtable).clone(); + } + None => { } + } + + ty::populate_implementations_for_trait_if_necessary(tcx, trait_ref.def_id); + let infcx = infer::new_infer_ctxt(tcx); + + // Parameter environment is used to give details about type parameters, + // but since we are in trans, everything is fully monomorphized. + let param_env = ty::empty_parameter_environment(); + let unboxed_closures = tcx.unboxed_closures.borrow(); + + // Do the initial selection for the obligation. This yields the + // shallow result we are looking for -- that is, what specific impl. + let selcx = traits::SelectionContext::new(&infcx, ¶m_env, + &*unboxed_closures); + let obligation = traits::Obligation::misc(span, trait_ref.clone()); + let selection = match selcx.select(&obligation) { + Ok(Some(selection)) => selection, + Ok(None) => { + tcx.sess.span_bug( + span, + format!("Encountered ambiguity selecting `{}` during trans", + trait_ref.repr(tcx)).as_slice()) + } + Err(e) => { + tcx.sess.span_bug( + span, + format!("Encountered error `{}` selecting `{}` during trans", + e.repr(tcx), + trait_ref.repr(tcx)).as_slice()) + } + }; + + // Currently, we use a fulfillment context to completely resolve + // all nested obligations. This is because they can inform the + // inference of the impl's type parameters. However, in principle, + // we only need to do this until the impl's type parameters are + // fully bound. It could be a slight optimization to stop + // iterating early. + let mut fulfill_cx = traits::FulfillmentContext::new(); + let vtable = selection.map_move_nested(|obligation| { + fulfill_cx.register_obligation(tcx, obligation); + }); + match fulfill_cx.select_all_or_error(&infcx, ¶m_env, &*unboxed_closures) { + Ok(()) => { } + Err(e) => { + tcx.sess.span_bug( + span, + format!("Encountered errors `{}` fulfilling `{}` during trans", + e.repr(tcx), + trait_ref.repr(tcx)).as_slice()); + } + } + + // Use skolemize to simultaneously replace all type variables with + // their bindings and replace all regions with 'static. This is + // sort of overkill because we do not expect there to be any + // unbound type variables, hence no skolemized types should ever + // be inserted. + let vtable = infer::skolemize(&infcx, vtable); + + info!("Cache miss: {}", trait_ref.repr(ccx.tcx())); + ccx.trait_cache().borrow_mut().insert(trait_ref, + vtable.clone()); + + vtable +} + // Key used to lookup values supplied for type parameters in an expr. #[deriving(PartialEq)] pub enum ExprOrMethodCall { @@ -778,7 +866,8 @@ pub enum ExprOrMethodCall { pub fn node_id_substs(bcx: Block, node: ExprOrMethodCall) - -> subst::Substs { + -> subst::Substs +{ let tcx = bcx.tcx(); let substs = match node { @@ -798,87 +887,10 @@ pub fn node_id_substs(bcx: Block, substs.repr(bcx.tcx())).as_slice()); } + let substs = substs.erase_regions(); substs.substp(tcx, bcx.fcx.param_substs) } -pub fn node_vtables(bcx: Block, id: typeck::MethodCall) - -> typeck::vtable_res { - bcx.tcx().vtable_map.borrow().find(&id).map(|vts| { - resolve_vtables_in_fn_ctxt(bcx.fcx, vts) - }).unwrap_or_else(|| subst::VecPerParamSpace::empty()) -} - -// Apply the typaram substitutions in the FunctionContext to some -// vtables. This should eliminate any vtable_params. -pub fn resolve_vtables_in_fn_ctxt(fcx: &FunctionContext, - vts: &typeck::vtable_res) - -> typeck::vtable_res { - resolve_vtables_under_param_substs(fcx.ccx.tcx(), - fcx.param_substs, - vts) -} - -pub fn resolve_vtables_under_param_substs(tcx: &ty::ctxt, - param_substs: ¶m_substs, - vts: &typeck::vtable_res) - -> typeck::vtable_res -{ - vts.map(|ds| { - resolve_param_vtables_under_param_substs(tcx, - param_substs, - ds) - }) -} - -pub fn resolve_param_vtables_under_param_substs(tcx: &ty::ctxt, - param_substs: ¶m_substs, - ds: &typeck::vtable_param_res) - -> typeck::vtable_param_res -{ - ds.iter().map(|d| { - resolve_vtable_under_param_substs(tcx, - param_substs, - d) - }).collect() -} - - - -pub fn resolve_vtable_under_param_substs(tcx: &ty::ctxt, - param_substs: ¶m_substs, - vt: &typeck::vtable_origin) - -> typeck::vtable_origin -{ - match *vt { - typeck::vtable_static(trait_id, ref vtable_substs, ref sub) => { - let vtable_substs = vtable_substs.substp(tcx, param_substs); - typeck::vtable_static( - trait_id, - vtable_substs, - resolve_vtables_under_param_substs(tcx, param_substs, sub)) - } - typeck::vtable_param(n_param, n_bound) => { - find_vtable(tcx, param_substs, n_param, n_bound) - } - typeck::vtable_unboxed_closure(def_id) => { - typeck::vtable_unboxed_closure(def_id) - } - typeck::vtable_error => typeck::vtable_error - } -} - -pub fn find_vtable(tcx: &ty::ctxt, - ps: ¶m_substs, - n_param: typeck::param_index, - n_bound: uint) - -> typeck::vtable_origin { - debug!("find_vtable(n_param={:?}, n_bound={}, ps={})", - n_param, n_bound, ps.repr(tcx)); - - let param_bounds = ps.vtables.get(n_param.space, n_param.index); - param_bounds.get(n_bound).clone() -} - pub fn langcall(bcx: Block, span: Option, msg: &str, diff --git a/src/librustc/middle/trans/context.rs b/src/librustc/middle/trans/context.rs index 3b4b50c7e85ac..093849b47ad98 100644 --- a/src/librustc/middle/trans/context.rs +++ b/src/librustc/middle/trans/context.rs @@ -16,6 +16,7 @@ use llvm::{TargetData}; use llvm::mk_target_data; use metadata::common::LinkMeta; use middle::resolve; +use middle::traits; use middle::trans::adt; use middle::trans::base; use middle::trans::builder::Builder; @@ -103,7 +104,7 @@ pub struct LocalCrateContext { monomorphized: RefCell>, monomorphizing: RefCell>, /// Cache generated vtables - vtables: RefCell>, + vtables: RefCell), ValueRef>>, /// Cache of constant strings, const_cstr_cache: RefCell>, @@ -150,6 +151,9 @@ pub struct LocalCrateContext { /// This is used to perform some basic load-balancing to keep all LLVM /// contexts around the same size. n_llvm_insns: Cell, + + trait_cache: RefCell, + traits::Vtable<()>>>, } pub struct CrateContext<'a, 'tcx: 'a> { @@ -426,6 +430,7 @@ impl LocalCrateContext { eh_personality: RefCell::new(None), intrinsics: RefCell::new(HashMap::new()), n_llvm_insns: Cell::new(0u), + trait_cache: RefCell::new(HashMap::new()), }; local_ccx.int_type = Type::int(&local_ccx.dummy_ccx(shared)); @@ -617,7 +622,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local.monomorphizing } - pub fn vtables<'a>(&'a self) -> &'a RefCell> { + pub fn vtables<'a>(&'a self) -> &'a RefCell), ValueRef>> { &self.local.vtables } @@ -713,6 +718,10 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { pub fn count_llvm_insn(&self) { self.local.n_llvm_insns.set(self.local.n_llvm_insns.get() + 1); } + + pub fn trait_cache(&self) -> &RefCell, traits::Vtable<()>>> { + &self.local.trait_cache + } } fn declare_intrinsic(ccx: &CrateContext, key: & &'static str) -> Option { diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 8a6f3dd6ffab6..af57d49d9d815 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -41,6 +41,7 @@ use middle::def; use middle::lang_items::MallocFnLangItem; use middle::mem_categorization::Typer; use middle::subst; +use middle::subst::Subst; use middle::trans::_match; use middle::trans::adt; use middle::trans::asm; @@ -78,6 +79,7 @@ use syntax::ast; use syntax::codemap; use syntax::print::pprust::{expr_to_string}; use syntax::ptr::P; +use std::rc::Rc; // Destinations @@ -319,10 +321,18 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, _ => bcx.sess().bug(format!("UnsizeStruct with bad sty: {}", bcx.ty_to_string(unsized_ty)).as_slice()) }, - &ty::UnsizeVtable(..) => + &ty::UnsizeVtable(ty::TyTrait { def_id: def_id, substs: ref substs, .. }, _) => { + let substs = substs.with_self_ty(unsized_ty); + let trait_ref = + Rc::new(ty::TraitRef { def_id: def_id, + substs: substs }); + let trait_ref = + trait_ref.subst(bcx.tcx(), &bcx.fcx.param_substs.substs); + let box_ty = mk_ty(unsized_ty); PointerCast(bcx, - meth::vtable_ptr(bcx, id, mk_ty(unsized_ty)), + meth::get_vtable(bcx, box_ty, trait_ref), Type::vtable_ptr(bcx.ccx())) + } } } @@ -1052,8 +1062,16 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ast::ExprCast(ref val, _) => { // DPS output mode means this is a trait cast: if ty::type_is_trait(node_id_type(bcx, expr.id)) { + let trait_ref = + bcx.tcx().object_cast_map.borrow() + .find(&expr.id) + .map(|t| (*t).clone()) + .unwrap(); + let trait_ref = + trait_ref.subst(bcx.tcx(), &bcx.fcx.param_substs.substs); let datum = unpack_datum!(bcx, trans(bcx, &**val)); - meth::trans_trait_cast(bcx, datum, expr.id, dest) + meth::trans_trait_cast(bcx, datum, expr.id, + trait_ref, dest) } else { bcx.tcx().sess.span_bug(expr.span, "expr_cast of non-trait"); diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index 4202c2deff6fc..a87557a26cc67 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -13,8 +13,10 @@ use back::abi; use llvm; use llvm::ValueRef; use metadata::csearch; +use middle::subst::{Subst,Substs}; use middle::subst::VecPerParamSpace; use middle::subst; +use middle::traits; use middle::trans::base::*; use middle::trans::build::*; use middle::trans::callee::*; @@ -26,20 +28,20 @@ use middle::trans::expr::{SaveIn, Ignore}; use middle::trans::expr; use middle::trans::glue; use middle::trans::machine; -use middle::trans::monomorphize; use middle::trans::type_::Type; use middle::trans::type_of::*; use middle::ty; use middle::typeck; use middle::typeck::MethodCall; -use util::common::indenter; use util::ppaux::Repr; use std::c_str::ToCStr; +use std::rc::Rc; use syntax::abi::{Rust, RustCall}; use syntax::parse::token; use syntax::{ast, ast_map, attr, visit}; use syntax::ast_util::PostExpansionMethod; +use syntax::codemap::DUMMY_SP; // drop_glue pointer, size, align. static VTABLE_OFFSET: uint = 3; @@ -109,18 +111,12 @@ pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, -> Callee<'blk, 'tcx> { let _icx = push_ctxt("meth::trans_method_callee"); - let (origin, method_ty) = match bcx.tcx().method_map - .borrow().find(&method_call) { - Some(method) => { - debug!("trans_method_callee({:?}, method={})", - method_call, method.repr(bcx.tcx())); - (method.origin, method.ty) - } - None => { - bcx.sess().span_bug(bcx.tcx().map.span(method_call.expr_id), - "method call expr wasn't in method map") - } - }; + let (origin, method_ty) = + bcx.tcx().method_map + .borrow() + .find(&method_call) + .map(|method| (method.origin.clone(), method.ty)) + .unwrap(); match origin { typeck::MethodStatic(did) | @@ -132,19 +128,21 @@ pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, MethodCall(method_call))), } } + typeck::MethodParam(typeck::MethodParam { - trait_id: trait_id, - method_num: off, - param_num: p, - bound_num: b + trait_ref: ref trait_ref, + method_num: method_num }) => { - ty::populate_implementations_for_trait_if_necessary( - bcx.tcx(), - trait_id); - - let vtbl = find_vtable(bcx.tcx(), bcx.fcx.param_substs, p, b); - trans_monomorphized_callee(bcx, method_call, - trait_id, off, vtbl) + let trait_ref = + Rc::new(trait_ref.subst(bcx.tcx(), + &bcx.fcx.param_substs.substs)); + let span = bcx.tcx().map.span(method_call.expr_id); + let origin = fulfill_obligation(bcx.ccx(), + span, + (*trait_ref).clone()); + debug!("origin = {}", origin.repr(bcx.tcx())); + trans_monomorphized_callee(bcx, method_call, trait_ref.def_id, + method_num, origin) } typeck::MethodObject(ref mt) => { @@ -169,7 +167,8 @@ pub fn trans_static_method_callee(bcx: Block, method_id: ast::DefId, trait_id: ast::DefId, expr_id: ast::NodeId) - -> ValueRef { + -> ValueRef +{ let _icx = push_ctxt("meth::trans_static_method_callee"); let ccx = bcx.ccx(); @@ -178,9 +177,6 @@ pub fn trans_static_method_callee(bcx: Block, method_id, ty::item_path_str(bcx.tcx(), trait_id), expr_id); - let _indenter = indenter(); - - ty::populate_implementations_for_trait_if_necessary(bcx.tcx(), trait_id); let mname = if method_id.krate == ast::LOCAL_CRATE { match bcx.tcx().map.get(method_id.node) { @@ -196,38 +192,91 @@ pub fn trans_static_method_callee(bcx: Block, } else { csearch::get_item_path(bcx.tcx(), method_id).last().unwrap().name() }; - debug!("trans_static_method_callee: method_id={:?}, expr_id={:?}, \ + debug!("trans_static_method_callee: method_id={}, expr_id={}, \ name={}", method_id, expr_id, token::get_name(mname)); - let vtable_key = MethodCall::expr(expr_id); - let vtbls = resolve_vtables_in_fn_ctxt( - bcx.fcx, - ccx.tcx().vtable_map.borrow().get(&vtable_key)); - - match *vtbls.get_self().unwrap().get(0) { - typeck::vtable_static(impl_did, ref rcvr_substs, ref rcvr_origins) => { - assert!(rcvr_substs.types.all(|t| !ty::type_needs_infer(*t))); + // Find the substitutions for the fn itself. This includes + // type parameters that belong to the trait but also some that + // belong to the method: + let rcvr_substs = node_id_substs(bcx, ExprId(expr_id)); + let (rcvr_type, rcvr_self, rcvr_method) = rcvr_substs.types.split(); + + // Lookup the precise impl being called. To do that, we need to + // create a trait reference identifying the self type and other + // input type parameters. To create that trait reference, we have + // to pick apart the type parameters to identify just those that + // pertain to the trait. This is easiest to explain by example: + // + // trait Convert { + // fn from(n: U) -> Option; + // } + // ... + // let f = as Convert>::from::(...) + // + // Here, in this call, which I've written with explicit UFCS + // notation, the set of type parameters will be: + // + // rcvr_type: [] <-- nothing declared on the trait itself + // rcvr_self: [Vec] <-- the self type + // rcvr_method: [String] <-- method type parameter + // + // So we create a trait reference using the first two, + // basically corresponding to ` as Convert>`. + // The remaining type parameters (`rcvr_method`) will be used below. + let trait_substs = + Substs::erased(VecPerParamSpace::new(rcvr_type, + rcvr_self, + Vec::new())); + debug!("trait_substs={}", trait_substs.repr(bcx.tcx())); + let trait_ref = Rc::new(ty::TraitRef { def_id: trait_id, + substs: trait_substs }); + let vtbl = fulfill_obligation(bcx.ccx(), + DUMMY_SP, + trait_ref); + + // Now that we know which impl is being used, we can dispatch to + // the actual function: + match vtbl { + traits::VtableImpl(traits::VtableImpl { + impl_def_id: impl_did, + substs: impl_substs, + nested: _ }) => + { + assert!(impl_substs.types.all(|t| !ty::type_needs_infer(*t))); + + // Create the substitutions that are in scope. This combines + // the type parameters from the impl with those declared earlier. + // To see what I mean, consider a possible impl: + // + // impl Convert for Vec { + // fn from(n: U) { ... } + // } + // + // Recall that we matched ` as Convert>`. Trait + // resolution will have given us a substitution + // containing `impl_substs=[[T=int],[],[]]` (the type + // parameters defined on the impl). We combine + // that with the `rcvr_method` from before, which tells us + // the type parameters from the *method*, to yield + // `callee_substs=[[T=int],[],[U=String]]`. + let (impl_type, impl_self, _) = impl_substs.types.split(); + let callee_substs = + Substs::erased(VecPerParamSpace::new(impl_type, + impl_self, + rcvr_method)); let mth_id = method_with_name(ccx, impl_did, mname); - let (callee_substs, callee_origins) = - combine_impl_and_methods_tps( - bcx, ExprId(expr_id), - (*rcvr_substs).clone(), (*rcvr_origins).clone()); - - let llfn = trans_fn_ref_with_vtables(bcx, mth_id, ExprId(expr_id), - callee_substs, - callee_origins); + let llfn = trans_fn_ref_with_substs(bcx, mth_id, ExprId(expr_id), + callee_substs); let callee_ty = node_id_type(bcx, expr_id); let llty = type_of_fn_from_ty(ccx, callee_ty).ptr_to(); PointerCast(bcx, llfn, llty) } - typeck::vtable_unboxed_closure(_) => { - bcx.tcx().sess.bug("can't call a closure vtable in a static way"); - } _ => { - fail!("vtable_param left in monomorphized \ - function's vtable substs"); + bcx.tcx().sess.bug( + format!("static call to invalid vtable: {}", + vtbl.repr(bcx.tcx())).as_slice()); } } } @@ -265,33 +314,33 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, method_call: MethodCall, trait_id: ast::DefId, n_method: uint, - vtbl: typeck::vtable_origin) + vtable: traits::Vtable<()>) -> Callee<'blk, 'tcx> { let _icx = push_ctxt("meth::trans_monomorphized_callee"); - match vtbl { - typeck::vtable_static(impl_did, rcvr_substs, rcvr_origins) => { - let ccx = bcx.ccx(); - let mname = match ty::trait_item(ccx.tcx(), trait_id, n_method) { - ty::MethodTraitItem(method) => method.ident, - }; - let mth_id = method_with_name(bcx.ccx(), impl_did, mname.name); - - // create a concatenated set of substitutions which includes - // those from the impl and those from the method: - let (callee_substs, callee_origins) = - combine_impl_and_methods_tps( - bcx, MethodCall(method_call), rcvr_substs, rcvr_origins); - - // translate the function - let llfn = trans_fn_ref_with_vtables(bcx, - mth_id, - MethodCall(method_call), - callee_substs, - callee_origins); - - Callee { bcx: bcx, data: Fn(llfn) } - } - typeck::vtable_unboxed_closure(closure_def_id) => { + match vtable { + traits::VtableImpl(vtable_impl) => { + let ccx = bcx.ccx(); + let impl_did = vtable_impl.impl_def_id; + let mname = match ty::trait_item(ccx.tcx(), trait_id, n_method) { + ty::MethodTraitItem(method) => method.ident, + }; + let mth_id = method_with_name(bcx.ccx(), impl_did, mname.name); + + // create a concatenated set of substitutions which includes + // those from the impl and those from the method: + let callee_substs = + combine_impl_and_methods_tps( + bcx, MethodCall(method_call), vtable_impl.substs); + + // translate the function + let llfn = trans_fn_ref_with_substs(bcx, + mth_id, + MethodCall(method_call), + callee_substs); + + Callee { bcx: bcx, data: Fn(llfn) } + } + traits::VtableUnboxedClosure(closure_def_id) => { // The static region and type parameters are lies, but we're in // trans so it doesn't matter. // @@ -300,33 +349,27 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, bcx, closure_def_id); - let llfn = trans_fn_ref_with_vtables(bcx, - closure_def_id, - MethodCall(method_call), - callee_substs, - VecPerParamSpace::empty()); - - Callee { - bcx: bcx, - data: Fn(llfn), - } - } - typeck::vtable_param(..) => { - bcx.tcx().sess.bug( - "vtable_param left in monomorphized function's vtable substs"); - } - typeck::vtable_error => { - bcx.tcx().sess.bug( - "vtable_error left in monomorphized function's vtable substs"); - } + let llfn = trans_fn_ref_with_substs(bcx, + closure_def_id, + MethodCall(method_call), + callee_substs); + + Callee { + bcx: bcx, + data: Fn(llfn), + } + } + _ => { + bcx.tcx().sess.bug( + "vtable_param left in monomorphized function's vtable substs"); + } } } fn combine_impl_and_methods_tps(bcx: Block, node: ExprOrMethodCall, - rcvr_substs: subst::Substs, - rcvr_origins: typeck::vtable_res) - -> (subst::Substs, typeck::vtable_res) + rcvr_substs: subst::Substs) + -> subst::Substs { /*! * Creates a concatenated set of substitutions which includes @@ -347,33 +390,20 @@ fn combine_impl_and_methods_tps(bcx: Block, let ccx = bcx.ccx(); - let vtable_key = match node { - ExprId(id) => MethodCall::expr(id), - MethodCall(method_call) => method_call - }; let node_substs = node_id_substs(bcx, node); - let node_vtables = node_vtables(bcx, vtable_key); - debug!("rcvr_substs={:?}", rcvr_substs.repr(ccx.tcx())); - debug!("node_substs={:?}", node_substs.repr(ccx.tcx())); + debug!("rcvr_substs={}", rcvr_substs.repr(ccx.tcx())); + debug!("node_substs={}", node_substs.repr(ccx.tcx())); // Break apart the type parameters from the node and type // parameters from the receiver. let (_, _, node_method) = node_substs.types.split(); let (rcvr_type, rcvr_self, rcvr_method) = rcvr_substs.types.clone().split(); assert!(rcvr_method.is_empty()); - let ty_substs = subst::Substs { + subst::Substs { regions: subst::ErasedRegions, types: subst::VecPerParamSpace::new(rcvr_type, rcvr_self, node_method) - }; - - // Now do the same work for the vtables. - let (rcvr_type, rcvr_self, rcvr_method) = rcvr_origins.split(); - let (_, _, node_method) = node_vtables.split(); - assert!(rcvr_method.is_empty()); - let vtables = subst::VecPerParamSpace::new(rcvr_type, rcvr_self, node_method); - - (ty_substs, vtables) + } } fn trans_trait_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, @@ -493,43 +523,56 @@ fn get_callee_substitutions_for_unboxed_closure(bcx: Block, /// Creates a returns a dynamic vtable for the given type and vtable origin. /// This is used only for objects. -fn get_vtable(bcx: Block, - self_ty: ty::t, - origins: typeck::vtable_param_res) - -> ValueRef +/// +/// The `trait_ref` encodes the erased self type. Hence if we are +/// making an object `Foo` from a value of type `Foo`, then +/// `trait_ref` would map `T:Trait`, but `box_ty` would be +/// `Foo`. This `box_ty` is primarily used to encode the destructor. +/// This will hopefully change now that DST is underway. +pub fn get_vtable(bcx: Block, + box_ty: ty::t, + trait_ref: Rc) + -> ValueRef { - debug!("get_vtable(self_ty={}, origins={})", - self_ty.repr(bcx.tcx()), - origins.repr(bcx.tcx())); + debug!("get_vtable(box_ty={}, trait_ref={})", + box_ty.repr(bcx.tcx()), + trait_ref.repr(bcx.tcx())); + let tcx = bcx.tcx(); let ccx = bcx.ccx(); let _icx = push_ctxt("meth::get_vtable"); // Check the cache. - let hash_id = (self_ty, monomorphize::make_vtable_id(ccx, origins.get(0))); - match ccx.vtables().borrow().find(&hash_id) { + let cache_key = (box_ty, trait_ref.clone()); + match ccx.vtables().borrow().find(&cache_key) { Some(&val) => { return val } None => { } } - // Not in the cache. Actually build it. - let methods = origins.move_iter().flat_map(|origin| { - match origin { - typeck::vtable_static(id, substs, sub_vtables) => { - emit_vtable_methods(bcx, id, substs, sub_vtables).move_iter() + // Not in the cache. Build it. + let methods = traits::supertraits(tcx, trait_ref.clone()).flat_map(|trait_ref| { + let vtable = fulfill_obligation(bcx.ccx(), + DUMMY_SP, + trait_ref.clone()); + match vtable { + traits::VtableImpl( + traits::VtableImpl { + impl_def_id: id, + substs: substs, + nested: _ }) => { + emit_vtable_methods(bcx, id, substs).move_iter() } - typeck::vtable_unboxed_closure(closure_def_id) => { + traits::VtableUnboxedClosure(closure_def_id) => { let callee_substs = get_callee_substitutions_for_unboxed_closure( bcx, closure_def_id); - let mut llfn = trans_fn_ref_with_vtables( + let mut llfn = trans_fn_ref_with_substs( bcx, closure_def_id, ExprId(0), - callee_substs.clone(), - VecPerParamSpace::empty()); + callee_substs.clone()); { let unboxed_closures = bcx.tcx() @@ -585,21 +628,27 @@ fn get_vtable(bcx: Block, (vec!(llfn)).move_iter() } - _ => ccx.sess().bug("get_vtable: expected a static origin"), + traits::VtableBuiltin | + traits::VtableParam(..) => { + bcx.sess().bug( + format!("resolved vtable for {} to bad vtable {} in trans", + trait_ref.repr(bcx.tcx()), + vtable.repr(bcx.tcx())).as_slice()); + } } }); - let size_ty = sizing_type_of(ccx, self_ty); + let size_ty = sizing_type_of(ccx, trait_ref.self_ty()); let size = machine::llsize_of_alloc(ccx, size_ty); let ll_size = C_uint(ccx, size as uint); - let align = align_of(ccx, self_ty); + let align = align_of(ccx, trait_ref.self_ty()); let ll_align = C_uint(ccx, align as uint); // Generate a destructor for the vtable. - let drop_glue = glue::get_drop_glue(ccx, self_ty); + let drop_glue = glue::get_drop_glue(ccx, box_ty); let vtable = make_vtable(ccx, drop_glue, ll_size, ll_align, methods); - ccx.vtables().borrow_mut().insert(hash_id, vtable); + ccx.vtables().borrow_mut().insert(cache_key, vtable); vtable } @@ -630,8 +679,7 @@ pub fn make_vtable>(ccx: &CrateContext, fn emit_vtable_methods(bcx: Block, impl_id: ast::DefId, - substs: subst::Substs, - vtables: typeck::vtable_res) + substs: subst::Substs) -> Vec { let ccx = bcx.ccx(); let tcx = ccx.tcx(); @@ -664,12 +712,11 @@ fn emit_vtable_methods(bcx: Block, token::get_ident(ident)); C_null(Type::nil(ccx).ptr_to()) } else { - let mut fn_ref = trans_fn_ref_with_vtables( + let mut fn_ref = trans_fn_ref_with_substs( bcx, m_id, ExprId(0), - substs.clone(), - vtables.clone()); + substs.clone()); if m.explicit_self == ty::ByValueExplicitSelfCategory { fn_ref = trans_unboxing_shim(bcx, fn_ref, @@ -684,29 +731,10 @@ fn emit_vtable_methods(bcx: Block, }).collect() } -pub fn vtable_ptr(bcx: Block, - id: ast::NodeId, - self_ty: ty::t) -> ValueRef { - let ccx = bcx.ccx(); - let origins = { - let vtable_map = ccx.tcx().vtable_map.borrow(); - // This trait cast might be because of implicit coercion - let adjs = ccx.tcx().adjustments.borrow(); - let adjust = adjs.find(&id); - let method_call = if adjust.is_some() && ty::adjust_is_object(adjust.unwrap()) { - MethodCall::autoobject(id) - } else { - MethodCall::expr(id) - }; - let vres = vtable_map.get(&method_call).get_self().unwrap(); - resolve_param_vtables_under_param_substs(ccx.tcx(), bcx.fcx.param_substs, vres) - }; - get_vtable(bcx, self_ty, origins) -} - pub fn trans_trait_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, datum: Datum, id: ast::NodeId, + trait_ref: Rc, dest: expr::Dest) -> Block<'blk, 'tcx> { /*! @@ -717,17 +745,20 @@ pub fn trans_trait_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, */ let mut bcx = bcx; - let _icx = push_ctxt("meth::trans_cast"); + let _icx = push_ctxt("meth::trans_trait_cast"); let lldest = match dest { Ignore => { - return datum.clean(bcx, "trait_cast", id); + return datum.clean(bcx, "trait_trait_cast", id); } SaveIn(dest) => dest }; - let v_ty = datum.ty; - let llbox_ty = type_of(bcx.ccx(), v_ty); + debug!("trans_trait_cast: trait_ref={}", + trait_ref.repr(bcx.tcx())); + + let datum_ty = datum.ty; + let llbox_ty = type_of(bcx.ccx(), datum_ty); // Store the pointer into the first half of pair. let llboxdest = GEPi(bcx, lldest, [0u, abi::trt_field_box]); @@ -735,7 +766,7 @@ pub fn trans_trait_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, bcx = datum.store_to(bcx, llboxdest); // Store the vtable into the second half of pair. - let vtable = vtable_ptr(bcx, id, v_ty); + let vtable = get_vtable(bcx, datum_ty, trait_ref); let llvtabledest = GEPi(bcx, lldest, [0u, abi::trt_field_vtable]); let llvtabledest = PointerCast(bcx, llvtabledest, val_ty(vtable).ptr_to()); Store(bcx, vtable, llvtabledest); diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs index 57004922ef7d1..00e9d9f0e39b6 100644 --- a/src/librustc/middle/trans/monomorphize.rs +++ b/src/librustc/middle/trans/monomorphize.rs @@ -34,17 +34,14 @@ use std::hash::{sip, Hash}; pub fn monomorphic_fn(ccx: &CrateContext, fn_id: ast::DefId, real_substs: &subst::Substs, - vtables: typeck::vtable_res, ref_id: Option) -> (ValueRef, bool) { debug!("monomorphic_fn(\ fn_id={}, \ real_substs={}, \ - vtables={}, \ ref_id={:?})", fn_id.repr(ccx.tcx()), real_substs.repr(ccx.tcx()), - vtables.repr(ccx.tcx()), ref_id); assert!(real_substs.types.all(|t| { @@ -69,7 +66,6 @@ pub fn monomorphic_fn(ccx: &CrateContext, let psubsts = param_substs { substs: (*real_substs).clone(), - vtables: vtables, }; debug!("monomorphic_fn(\ @@ -286,7 +282,7 @@ pub fn monomorphic_fn(ccx: &CrateContext, (lldecl, true) } -// Used to identify cached monomorphized functions and vtables +// Used to identify cached monomorphized functions #[deriving(PartialEq, Eq, Hash)] pub struct MonoParamId { pub subst: ty::t, diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 643c52e5d52ba..c26505fdc6578 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -28,6 +28,7 @@ use middle::resolve_lifetime; use middle::stability; use middle::subst::{Subst, Substs, VecPerParamSpace}; use middle::subst; +use middle::traits; use middle::ty; use middle::typeck; use middle::ty_fold; @@ -272,9 +273,7 @@ pub enum UnsizeKind { // An unsize coercion applied to the tail field of a struct. // The uint is the index of the type parameter which is unsized. UnsizeStruct(Box, uint), - UnsizeVtable(ty::ExistentialBounds, - ast::DefId, /* Trait ID */ - subst::Substs /* Trait substitutions */) + UnsizeVtable(TyTrait, /* the self type of the trait */ ty::t) } #[deriving(Clone)] @@ -365,13 +364,13 @@ pub fn type_of_adjust(cx: &ctxt, adj: &AutoAdjustment) -> Option { fn type_of_autoref(cx: &ctxt, autoref: &AutoRef) -> Option { match autoref { &AutoUnsize(ref k) => match k { - &UnsizeVtable(bounds, def_id, ref substs) => { + &UnsizeVtable(TyTrait { def_id, substs: ref substs, bounds }, _) => { Some(mk_trait(cx, def_id, substs.clone(), bounds)) } _ => None }, &AutoUnsizeUniq(ref k) => match k { - &UnsizeVtable(bounds, def_id, ref substs) => { + &UnsizeVtable(TyTrait { def_id, substs: ref substs, bounds }, _) => { Some(mk_uniq(cx, mk_trait(cx, def_id, substs.clone(), bounds))) } _ => None @@ -458,6 +457,10 @@ pub struct ctxt<'tcx> { pub trait_refs: RefCell>>, pub trait_defs: RefCell>>, + /// Maps from node-id of a trait object cast (like `foo as + /// Box`) to the trait reference. + pub object_cast_map: typeck::ObjectCastMap, + pub map: ast_map::Map<'tcx>, pub intrinsic_defs: RefCell>, pub freevars: RefCell, @@ -499,7 +502,7 @@ pub struct ctxt<'tcx> { /// Maps a DefId of a type to a list of its inherent impls. /// Contains implementations of methods that are inherent to a type. /// Methods in these implementations don't need to be exported. - pub inherent_impls: RefCell>>>>, + pub inherent_impls: RefCell>>>, /// Maps a DefId of an impl to a list of its items. /// Note that this contains all of the impls that we know about, @@ -516,9 +519,6 @@ pub struct ctxt<'tcx> { /// about. pub used_mut_nodes: RefCell, - /// vtable resolution information for impl declarations - pub impl_vtables: typeck::impl_vtable_map, - /// The set of external nominal types whose implementations have been read. /// This is used for lazy resolution of methods. pub populated_external_types: RefCell, @@ -536,7 +536,6 @@ pub struct ctxt<'tcx> { pub extern_const_variants: RefCell>, pub method_map: typeck::MethodMap, - pub vtable_map: typeck::vtable_map, pub dependency_formats: RefCell, @@ -1435,6 +1434,7 @@ pub fn mk_ctxt<'tcx>(s: Session, item_substs: RefCell::new(NodeMap::new()), trait_refs: RefCell::new(NodeMap::new()), trait_defs: RefCell::new(DefIdMap::new()), + object_cast_map: RefCell::new(NodeMap::new()), map: map, intrinsic_defs: RefCell::new(DefIdMap::new()), freevars: RefCell::new(freevars), @@ -1463,14 +1463,12 @@ pub fn mk_ctxt<'tcx>(s: Session, impl_items: RefCell::new(DefIdMap::new()), used_unsafe: RefCell::new(NodeSet::new()), used_mut_nodes: RefCell::new(NodeSet::new()), - impl_vtables: RefCell::new(DefIdMap::new()), populated_external_types: RefCell::new(DefIdSet::new()), populated_external_traits: RefCell::new(DefIdSet::new()), upvar_borrow_map: RefCell::new(HashMap::new()), extern_const_statics: RefCell::new(DefIdMap::new()), extern_const_variants: RefCell::new(DefIdMap::new()), method_map: RefCell::new(FnvHashMap::new()), - vtable_map: RefCell::new(FnvHashMap::new()), dependency_formats: RefCell::new(HashMap::new()), unboxed_closures: RefCell::new(DefIdMap::new()), node_lint_levels: RefCell::new(HashMap::new()), @@ -2944,13 +2942,17 @@ pub fn is_type_representable(cx: &ctxt, sp: Span, ty: t) -> Representability { } pub fn type_is_trait(ty: t) -> bool { + type_trait_info(ty).is_some() +} + +pub fn type_trait_info(ty: t) -> Option<&'static TyTrait> { match get(ty).sty { ty_uniq(ty) | ty_rptr(_, mt { ty, ..}) | ty_ptr(mt { ty, ..}) => match get(ty).sty { - ty_trait(..) => true, - _ => false + ty_trait(ref t) => Some(&**t), + _ => None }, - ty_trait(..) => true, - _ => false + ty_trait(ref t) => Some(&**t), + _ => None } } @@ -3491,7 +3493,7 @@ pub fn unsize_ty(cx: &ctxt, format!("UnsizeStruct with bad sty: {}", ty_to_string(cx, ty)).as_slice()) }, - &UnsizeVtable(bounds, def_id, ref substs) => { + &UnsizeVtable(TyTrait { def_id, substs: ref substs, bounds }, _) => { mk_trait(cx, def_id, substs.clone(), bounds) } } @@ -3511,10 +3513,10 @@ impl AutoRef { } pub fn method_call_type_param_defs<'tcx, T>(typer: &T, - origin: typeck::MethodOrigin) + origin: &typeck::MethodOrigin) -> VecPerParamSpace where T: mc::Typer<'tcx> { - match origin { + match *origin { typeck::MethodStatic(did) => { ty::lookup_item_type(typer.tcx(), did).generics.types.clone() } @@ -3529,16 +3531,16 @@ pub fn method_call_type_param_defs<'tcx, T>(typer: &T, lookup_trait_def(typer.tcx(), def_id).generics.types.clone() } typeck::MethodParam(typeck::MethodParam{ - trait_id: trt_id, + trait_ref: ref trait_ref, method_num: n_mth, .. }) | typeck::MethodObject(typeck::MethodObject{ - trait_id: trt_id, + trait_ref: ref trait_ref, method_num: n_mth, .. }) => { - match ty::trait_item(typer.tcx(), trt_id, n_mth) { + match ty::trait_item(typer.tcx(), trait_ref.def_id, n_mth) { ty::MethodTraitItem(method) => method.generics.types.clone(), } } @@ -4407,14 +4409,6 @@ pub fn lookup_item_type(cx: &ctxt, || csearch::get_type(cx, did)) } -pub fn lookup_impl_vtables(cx: &ctxt, - did: ast::DefId) - -> typeck::vtable_res { - lookup_locally_or_in_crate_store( - "impl_vtables", did, &mut *cx.impl_vtables.borrow_mut(), - || csearch::get_impl_vtables(cx, did) ) -} - /// Given the did of a trait, returns its canonical trait ref. pub fn lookup_trait_def(cx: &ctxt, did: ast::DefId) -> Rc { let mut trait_defs = cx.trait_defs.borrow_mut(); @@ -4958,6 +4952,7 @@ pub fn populate_implementations_for_type_if_necessary(tcx: &ctxt, return } + let mut inherent_impls = Vec::new(); csearch::each_implementation_for_type(&tcx.sess.cstore, type_id, |impl_def_id| { let impl_items = csearch::get_impl_items(&tcx.sess.cstore, @@ -4989,18 +4984,11 @@ pub fn populate_implementations_for_type_if_necessary(tcx: &ctxt, // If this is an inherent implementation, record it. if associated_traits.is_none() { - match tcx.inherent_impls.borrow().find(&type_id) { - Some(implementation_list) => { - implementation_list.borrow_mut().push(impl_def_id); - return; - } - None => {} - } - tcx.inherent_impls.borrow_mut().insert(type_id, - Rc::new(RefCell::new(vec!(impl_def_id)))); + inherent_impls.push(impl_def_id); } }); + tcx.inherent_impls.borrow_mut().insert(type_id, Rc::new(inherent_impls)); tcx.populated_external_types.borrow_mut().insert(type_id); } @@ -5232,7 +5220,7 @@ pub fn hash_crate_independent(tcx: &ctxt, t: t, svh: &Svh) -> u64 { } } } - ty_trait(box ty::TyTrait { def_id: d, bounds, .. }) => { + ty_trait(box TyTrait { def_id: d, bounds, .. }) => { byte!(17); did(&mut state, d); hash!(bounds); @@ -5430,6 +5418,26 @@ impl BorrowKind { } } + pub fn to_mutbl_lossy(self) -> ast::Mutability { + /*! + * Returns a mutability `m` such that an `&m T` pointer could + * be used to obtain this borrow kind. Because borrow kinds + * are richer than mutabilities, we sometimes have to pick a + * mutability that is stornger than necessary so that it at + * least *would permit* the borrow in question. + */ + + match self { + MutBorrow => ast::MutMutable, + ImmBorrow => ast::MutImmutable, + + // We have no type correponding to a unique imm borrow, so + // use `&mut`. It gives all the capabilities of an `&uniq` + // and hence is a safe "over approximation". + UniqueImmBorrow => ast::MutMutable, + } + } + pub fn to_user_str(&self) -> &'static str { match *self { MutBorrow => "mutable", diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 861afee06049b..549f0daef8112 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -680,3 +680,28 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx> { } } } + +/////////////////////////////////////////////////////////////////////////// +// Region eraser +// +// Replaces all free regions with 'static. Useful in trans. + +pub struct RegionEraser<'a, 'tcx: 'a> { + tcx: &'a ty::ctxt<'tcx>, +} + +pub fn erase_regions(tcx: &ty::ctxt, t: T) -> T { + let mut eraser = RegionEraser { tcx: tcx }; + t.fold_with(&mut eraser) +} + +impl<'a, 'tcx> TypeFolder<'tcx> for RegionEraser<'a, 'tcx> { + fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { self.tcx } + + fn fold_region(&mut self, r: ty::Region) -> ty::Region { + match r { + ty::ReLateBound(..) | ty::ReEarlyBound(..) => r, + _ => ty::ReStatic + } + } +} diff --git a/src/librustc/middle/typeck/infer/coercion.rs b/src/librustc/middle/typeck/infer/coercion.rs index 44141f25418e4..c66d10138d8bb 100644 --- a/src/librustc/middle/typeck/infer/coercion.rs +++ b/src/librustc/middle/typeck/infer/coercion.rs @@ -370,7 +370,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } (&ty::ty_uniq(t_a), &ty::ty_uniq(t_b)) => { self.unpack_actual_value(t_a, |sty_a| { - match self.unsize_ty(sty_a, t_b) { + match self.unsize_ty(t_a, sty_a, t_b) { Some((ty, kind)) => { let ty = ty::mk_uniq(self.get_ref().infcx.tcx, ty); try!(self.get_ref().infcx.try(|| sub.tys(ty, b))); @@ -393,6 +393,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // performed to unsize it. // E.g., `[T, ..n]` -> `([T], UnsizeLength(n))` fn unsize_ty(&self, + ty_a: ty::t, sty_a: &ty::sty, ty_b: ty::t) -> Option<(ty::t, ty::UnsizeKind)> { @@ -412,9 +413,10 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { def_id, substs.clone(), bounds); - Some((ty, ty::UnsizeVtable(bounds, - def_id, - substs.clone()))) + Some((ty, ty::UnsizeVtable(ty::TyTrait { def_id: def_id, + bounds: bounds, + substs: substs.clone() }, + ty_a))) } (&ty::ty_struct(did_a, ref substs_a), &ty::ty_struct(did_b, ref substs_b)) if did_a == did_b => { @@ -432,7 +434,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { if self.get_ref().infcx.try(|| sub.tys(*tp_a, *tp_b)).is_ok() { continue; } - match self.unpack_actual_value(*tp_a, |tp| self.unsize_ty(tp, *tp_b)) { + match + self.unpack_actual_value( + *tp_a, + |tp| self.unsize_ty(*tp_a, tp, *tp_b)) + { Some((new_tp, k)) => { // Check that the whole types match. let mut new_substs = substs_a.clone(); @@ -471,14 +477,14 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { { let tcx = self.get_ref().infcx.tcx; - debug!("coerce_borrowed_object(a={}, sty_a={:?}, b={})", + debug!("coerce_borrowed_object(a={}, sty_a={:?}, b={}, b_mutbl={})", a.repr(tcx), sty_a, - b.repr(tcx)); + b.repr(tcx), b_mutbl); let coercion = Coercion(self.get_ref().trace.clone()); let r_a = self.get_ref().infcx.next_region_var(coercion); - self.coerce_object(a, sty_a, b, + self.coerce_object(a, sty_a, b, b_mutbl, |tr| ty::mk_rptr(tcx, r_a, ty::mt{ mutbl: b_mutbl, ty: tr }), || AutoPtr(r_a, b_mutbl, None)) } @@ -491,11 +497,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { { let tcx = self.get_ref().infcx.tcx; - debug!("coerce_unsafe_object(a={}, sty_a={:?}, b={})", + debug!("coerce_unsafe_object(a={}, sty_a={:?}, b={}, b_mutbl={})", a.repr(tcx), sty_a, - b.repr(tcx)); + b.repr(tcx), b_mutbl); - self.coerce_object(a, sty_a, b, + self.coerce_object(a, sty_a, b, b_mutbl, |tr| ty::mk_ptr(tcx, ty::mt{ mutbl: b_mutbl, ty: tr }), || AutoUnsafe(b_mutbl, None)) } diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index 17e7aa8ddc34c..4412b7d94d468 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -34,7 +34,7 @@ use middle::subst; -use middle::subst::Substs; +use middle::subst::{ErasedRegions, NonerasedRegions, Substs}; use middle::ty::{FloatVar, FnSig, IntVar, TyVar}; use middle::ty::{IntType, UintType}; use middle::ty::{BuiltinBounds}; @@ -113,29 +113,40 @@ pub trait Combine<'tcx> { let a_tps = a_subst.types.get_slice(space); let b_tps = b_subst.types.get_slice(space); let tps = try!(self.tps(space, a_tps, b_tps)); + substs.types.replace(space, tps); + } - let a_regions = a_subst.regions().get_slice(space); - let b_regions = b_subst.regions().get_slice(space); - - let mut invariance = Vec::new(); - let r_variances = match variances { - Some(ref variances) => variances.regions.get_slice(space), - None => { - for _ in a_regions.iter() { - invariance.push(ty::Invariant); - } - invariance.as_slice() - } - }; + match (&a_subst.regions, &b_subst.regions) { + (&ErasedRegions, _) | (_, &ErasedRegions) => { + substs.regions = ErasedRegions; + } - let regions = try!(relate_region_params(self, - item_def_id, - r_variances, - a_regions, - b_regions)); + (&NonerasedRegions(ref a), &NonerasedRegions(ref b)) => { + for &space in subst::ParamSpace::all().iter() { + let a_regions = a.get_slice(space); + let b_regions = b.get_slice(space); - substs.types.replace(space, tps); - substs.mut_regions().replace(space, regions); + let mut invariance = Vec::new(); + let r_variances = match variances { + Some(ref variances) => { + variances.regions.get_slice(space) + } + None => { + for _ in a_regions.iter() { + invariance.push(ty::Invariant); + } + invariance.as_slice() + } + }; + + let regions = try!(relate_region_params(self, + item_def_id, + r_variances, + a_regions, + b_regions)); + substs.mut_regions().replace(space, regions); + } + } } return Ok(substs); diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs index e59f1aa3ce4c1..7a913699280bc 100644 --- a/src/librustc/middle/typeck/mod.rs +++ b/src/librustc/middle/typeck/mod.rs @@ -71,9 +71,10 @@ use middle::ty; use util::common::time; use util::ppaux::Repr; use util::ppaux; -use util::nodemap::{DefIdMap, FnvHashMap}; +use util::nodemap::{NodeMap, FnvHashMap}; use std::cell::RefCell; +use std::rc::Rc; use syntax::codemap::Span; use syntax::print::pprust::*; use syntax::{ast, ast_map, abi}; @@ -92,7 +93,7 @@ pub struct param_index { pub index: uint } -#[deriving(Clone, Encodable, Decodable)] +#[deriving(Clone)] pub enum MethodOrigin { // fully statically resolved method MethodStatic(ast::DefId), @@ -110,27 +111,21 @@ pub enum MethodOrigin { // details for a method invoked with a receiver whose type is a type parameter // with a bounded trait. -#[deriving(Clone, Encodable, Decodable)] +#[deriving(Clone)] pub struct MethodParam { - // the trait containing the method to be invoked - pub trait_id: ast::DefId, + // the precise trait reference that occurs as a bound -- this may + // be a supertrait of what the user actually typed. + pub trait_ref: Rc, - // index of the method to be invoked amongst the trait's methods + // index of uint in the list of methods for the trait pub method_num: uint, - - // index of the type parameter (from those that are in scope) that is - // the type of the receiver - pub param_num: param_index, - - // index of the bound for this type parameter which specifies the trait - pub bound_num: uint, } // details for a method invoked with a receiver whose type is an object -#[deriving(Clone, Encodable, Decodable)] +#[deriving(Clone)] pub struct MethodObject { // the (super)trait containing the method to be invoked - pub trait_id: ast::DefId, + pub trait_ref: Rc, // the actual base trait id of the object pub object_trait_id: ast::DefId, @@ -154,7 +149,7 @@ pub struct MethodCallee { /** * With method calls, we store some extra information in - * side tables (i.e method_map, vtable_map). We use + * side tables (i.e method_map). We use * MethodCall as a key to index into these tables instead of * just directly using the expression's NodeId. The reason * for this being that we may apply adjustments (coercions) @@ -276,10 +271,9 @@ impl Repr for vtable_origin { } } -pub type vtable_map = RefCell>; - - -pub type impl_vtable_map = RefCell>; +// For every explicit cast into an object type, maps from the cast +// expr to the associated trait ref. +pub type ObjectCastMap = RefCell>>; pub struct CrateCtxt<'a, 'tcx: 'a> { // A mapping from method call sites to traits that have that method. From 688ddf79156aa01a2507412c9b766f48ef208b04 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 12 Sep 2014 11:47:33 -0400 Subject: [PATCH 06/10] typeck/kind -- stop using old trait framework. - Unify the "well-formedness" checking that typeck was already doing with what was taking place in kind. - Move requirements that things be sized into typeck. - I left the checking on upvars in kind, though I think it should eventually be refactored into regionck (which would perhaps be renamed). This reflects a general plan to convert typeck so that it registers obligations or other pending things for conditions it cannot check eventually. This makes it easier to identify all the conditions that apply to an AST expression, but can also influence inference in somec cases (e.g., `Send` implies `'static`, so I already had to promote a lot of the checking that `kind.rs` was doing into typeck, this branch just continues the process). --- src/librustc/middle/kind.rs | 483 +------- src/librustc/middle/ty.rs | 2 +- src/librustc/middle/typeck/check/_match.rs | 6 +- src/librustc/middle/typeck/check/method.rs | 91 +- src/librustc/middle/typeck/check/mod.rs | 519 +++++--- src/librustc/middle/typeck/check/regionck.rs | 35 +- src/librustc/middle/typeck/check/vtable.rs | 1077 ----------------- src/librustc/middle/typeck/check/vtable2.rs | 407 +++++++ src/librustc/middle/typeck/check/wf.rs | 365 ++++++ src/librustc/middle/typeck/check/writeback.rs | 51 +- src/librustc/middle/typeck/infer/coercion.rs | 35 +- 11 files changed, 1271 insertions(+), 1800 deletions(-) delete mode 100644 src/librustc/middle/typeck/check/vtable.rs create mode 100644 src/librustc/middle/typeck/check/vtable2.rs create mode 100644 src/librustc/middle/typeck/check/wf.rs diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index 33f7680d873c3..aeb0c155a3f48 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -10,50 +10,30 @@ use middle::freevars::freevar_entry; use middle::freevars; +use middle::mem_categorization::Typer; use middle::subst; -use middle::ty::ParameterEnvironment; use middle::ty; use middle::ty_fold::TypeFoldable; use middle::ty_fold; -use middle::typeck::check::vtable; -use middle::typeck::{MethodCall, NoAdjustment}; -use middle::typeck; -use util::ppaux::{Repr, ty_to_string}; +use util::ppaux::{ty_to_string}; use util::ppaux::UserString; -use std::collections::HashSet; use syntax::ast::*; -use syntax::ast_util; use syntax::attr; use syntax::codemap::Span; use syntax::print::pprust::{expr_to_string, ident_to_string}; use syntax::visit::Visitor; use syntax::visit; -// Kind analysis pass. -// -// There are several kinds defined by various operations. The most restrictive -// kind is noncopyable. The noncopyable kind can be extended with any number -// of the following attributes. -// -// Send: Things that can be sent on channels or included in spawned closures. It -// includes scalar types as well as classes and unique types containing only -// sendable types. -// 'static: Things that do not contain references. -// -// This pass ensures that type parameters are only instantiated with types -// whose kinds are equal or less general than the way the type parameter was -// annotated (with the `Send` bound). -// -// It also verifies that noncopyable kinds are not copied. Sendability is not -// applied, since none of our language primitives send. Instead, the sending -// primitives in the stdlib are explicitly annotated to only take sendable -// types. +// Kind analysis pass. This pass does some ad-hoc checks that are more +// convenient to do after type checking is complete and all checks are +// known. These are generally related to the builtin bounds `Copy` and +// `Sized`. Note that many of the builtin bound properties that used +// to be checked here are actually checked by trait checking these +// days. -pub struct Context<'a, 'tcx: 'a> { +pub struct Context<'a,'tcx:'a> { tcx: &'a ty::ctxt<'tcx>, - struct_and_enum_bounds_checked: HashSet, - parameter_environments: Vec, } impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> { @@ -77,17 +57,11 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> { fn visit_pat(&mut self, p: &Pat) { check_pat(self, p); } - - fn visit_local(&mut self, l: &Local) { - check_local(self, l); - } } pub fn check_crate(tcx: &ty::ctxt) { let mut ctx = Context { tcx: tcx, - struct_and_enum_bounds_checked: HashSet::new(), - parameter_environments: Vec::new(), }; visit::walk_crate(&mut ctx, tcx.map.krate()); tcx.sess.abort_if_errors(); @@ -135,27 +109,11 @@ fn check_impl_of_trait(cx: &mut Context, it: &Item, trait_ref: &TraitRef, self_t .find(&trait_ref.ref_id) .expect("trait ref not in def map!"); let trait_def_id = ast_trait_def.def_id(); - let trait_def = cx.tcx.trait_defs.borrow() - .find_copy(&trait_def_id) - .expect("trait def not in trait-defs map!"); - - // If this trait has builtin-kind supertraits, meet them. - let self_ty: ty::t = ty::node_id_to_type(cx.tcx, it.id); - debug!("checking impl with self type {}", ty::get(self_ty).sty); - check_builtin_bounds( - cx, self_ty, trait_def.bounds.builtin_bounds, - |missing| { - span_err!(cx.tcx.sess, self_type.span, E0142, - "the type `{}', which does not fulfill `{}`, \ - cannot implement this trait", - ty_to_string(cx.tcx, self_ty), missing.user_string(cx.tcx)); - span_note!(cx.tcx.sess, self_type.span, - "types implementing this trait must fulfill `{}`", - trait_def.bounds.user_string(cx.tcx)); - }); // If this is a destructor, check kinds. - if cx.tcx.lang_items.drop_trait() == Some(trait_def_id) { + if cx.tcx.lang_items.drop_trait() == Some(trait_def_id) && + !attr::contains_name(it.attrs.as_slice(), "unsafe_destructor") + { match self_type.node { TyPath(_, ref bounds, path_node_id) => { assert!(bounds.is_none()); @@ -172,133 +130,50 @@ fn check_impl_of_trait(cx: &mut Context, it: &Item, trait_ref: &TraitRef, self_t } fn check_item(cx: &mut Context, item: &Item) { - if !attr::contains_name(item.attrs.as_slice(), "unsafe_destructor") { - match item.node { - ItemImpl(_, ref trait_ref, ref self_type, _) => { - let parameter_environment = - ParameterEnvironment::for_item(cx.tcx, item.id); - cx.parameter_environments.push(parameter_environment); - - // Check bounds on the `self` type. - check_bounds_on_structs_or_enums_in_type_if_possible( - cx, - item.span, - ty::node_id_to_type(cx.tcx, item.id)); - - match trait_ref { - &Some(ref trait_ref) => { - check_impl_of_trait(cx, item, trait_ref, &**self_type); - - // Check bounds on the trait ref. - match ty::impl_trait_ref(cx.tcx, - ast_util::local_def(item.id)) { - None => {} - Some(trait_ref) => { - check_bounds_on_structs_or_enums_in_trait_ref( - cx, - item.span, - &*trait_ref); - - let trait_def = ty::lookup_trait_def(cx.tcx, trait_ref.def_id); - for (ty, type_param_def) in trait_ref.substs.types - .iter() - .zip(trait_def.generics - .types - .iter()) { - check_typaram_bounds(cx, item.span, *ty, type_param_def); - } - } - } - } - &None => {} - } - - drop(cx.parameter_environments.pop()); - } - ItemEnum(..) => { - let parameter_environment = - ParameterEnvironment::for_item(cx.tcx, item.id); - cx.parameter_environments.push(parameter_environment); - - let def_id = ast_util::local_def(item.id); - for variant in ty::enum_variants(cx.tcx, def_id).iter() { - for arg in variant.args.iter() { - check_bounds_on_structs_or_enums_in_type_if_possible( - cx, - item.span, - *arg) - } - } - - drop(cx.parameter_environments.pop()); - } - ItemStruct(..) => { - let parameter_environment = - ParameterEnvironment::for_item(cx.tcx, item.id); - cx.parameter_environments.push(parameter_environment); - - let def_id = ast_util::local_def(item.id); - for field in ty::lookup_struct_fields(cx.tcx, def_id).iter() { - check_bounds_on_structs_or_enums_in_type_if_possible( - cx, - item.span, - ty::node_id_to_type(cx.tcx, field.id.node)) - } - - drop(cx.parameter_environments.pop()); - - } - ItemStatic(..) => { - let parameter_environment = - ParameterEnvironment::for_item(cx.tcx, item.id); - cx.parameter_environments.push(parameter_environment); - - check_bounds_on_structs_or_enums_in_type_if_possible( - cx, - item.span, - ty::node_id_to_type(cx.tcx, item.id)); - - drop(cx.parameter_environments.pop()); - } - _ => {} + match item.node { + ItemImpl(_, Some(ref trait_ref), ref self_type, _) => { + check_impl_of_trait(cx, item, trait_ref, &**self_type); } + _ => {} } visit::walk_item(cx, item) } -fn check_local(cx: &mut Context, local: &Local) { - check_bounds_on_structs_or_enums_in_type_if_possible( - cx, - local.span, - ty::node_id_to_type(cx.tcx, local.id)); - - visit::walk_local(cx, local) -} - // Yields the appropriate function to check the kind of closed over // variables. `id` is the NodeId for some expression that creates the // closure. fn with_appropriate_checker(cx: &Context, id: NodeId, + fn_span: Span, b: |checker: |&Context, &freevar_entry||) { - fn check_for_uniq(cx: &Context, fv: &freevar_entry, bounds: ty::BuiltinBounds) { + fn check_for_uniq(cx: &Context, + fn_span: Span, + fv: &freevar_entry, + bounds: ty::BuiltinBounds) { // all captured data must be owned, regardless of whether it is // moved in or copied in. let id = fv.def.def_id().node; let var_t = ty::node_id_to_type(cx.tcx, id); - check_freevar_bounds(cx, fv.span, var_t, bounds, None); + check_freevar_bounds(cx, fn_span, fv.span, var_t, bounds, None); } - fn check_for_block(cx: &Context, fv: &freevar_entry, - bounds: ty::BuiltinBounds, region: ty::Region) { + fn check_for_block(cx: &Context, + fn_span: Span, + fn_id: NodeId, + fv: &freevar_entry, + bounds: ty::BuiltinBounds) { let id = fv.def.def_id().node; let var_t = ty::node_id_to_type(cx.tcx, id); - // FIXME(#3569): Figure out whether the implicit borrow is actually - // mutable. Currently we assume all upvars are referenced mutably. - let implicit_borrowed_type = ty::mk_mut_rptr(cx.tcx, region, var_t); - check_freevar_bounds(cx, fv.span, implicit_borrowed_type, + let upvar_id = ty::UpvarId { var_id: id, closure_expr_id: fn_id }; + let upvar_borrow = cx.tcx.upvar_borrow(upvar_id); + let implicit_borrowed_type = + ty::mk_rptr(cx.tcx, + upvar_borrow.region, + ty::mt { mutbl: upvar_borrow.kind.to_mutbl_lossy(), + ty: var_t }); + check_freevar_bounds(cx, fn_span, fv.span, implicit_borrowed_type, bounds, Some(var_t)); } @@ -315,12 +190,16 @@ fn with_appropriate_checker(cx: &Context, bounds: bounds, .. }) => { - b(|cx, fv| check_for_uniq(cx, fv, bounds.builtin_bounds)) + b(|cx, fv| check_for_uniq(cx, fn_span, fv, + bounds.builtin_bounds)) } ty::ty_closure(box ty::ClosureTy { - store: ty::RegionTraitStore(region, _), bounds, .. - }) => b(|cx, fv| check_for_block(cx, fv, bounds.builtin_bounds, region)), + store: ty::RegionTraitStore(..), bounds, .. + }) => { + b(|cx, fv| check_for_block(cx, fn_span, id, fv, + bounds.builtin_bounds)) + } ty::ty_bare_fn(_) => { b(check_for_bare) @@ -346,8 +225,8 @@ fn check_fn( sp: Span, fn_id: NodeId) { - // Check kinds on free variables: - with_appropriate_checker(cx, fn_id, |chk| { + // { - let ty = ty::node_id_to_type(cx.tcx, fn_id); - check_bounds_on_structs_or_enums_in_type_if_possible(cx, sp, ty); - visit::walk_fn(cx, fk, decl, body, sp) } visit::FkItemFn(..) | visit::FkMethod(..) => { - let parameter_environment = ParameterEnvironment::for_item(cx.tcx, - fn_id); - cx.parameter_environments.push(parameter_environment); - - let ty = ty::node_id_to_type(cx.tcx, fn_id); - check_bounds_on_structs_or_enums_in_type_if_possible(cx, sp, ty); - visit::walk_fn(cx, fk, decl, body, sp); - drop(cx.parameter_environments.pop()); } } } @@ -379,30 +247,7 @@ fn check_fn( pub fn check_expr(cx: &mut Context, e: &Expr) { debug!("kind::check_expr({})", expr_to_string(e)); - // Handle any kind bounds on type parameters - check_bounds_on_type_parameters(cx, e); - - // Check bounds on structures or enumerations in the type of the - // expression. - let expression_type = ty::expr_ty(cx.tcx, e); - check_bounds_on_structs_or_enums_in_type_if_possible(cx, - e.span, - expression_type); - match e.node { - ExprCast(ref source, _) => { - let source_ty = ty::expr_ty(cx.tcx, &**source); - let target_ty = ty::expr_ty(cx.tcx, e); - let method_call = MethodCall { - expr_id: e.id, - adjustment: NoAdjustment, - }; - check_trait_cast(cx, - source_ty, - target_ty, - source.span, - method_call); - } ExprRepeat(ref element, ref count_expr) => { let count = ty::eval_repeat_count(cx.tcx, &**count_expr); if count > 1 { @@ -427,174 +272,8 @@ pub fn check_expr(cx: &mut Context, e: &Expr) { _ => {} } - // Search for auto-adjustments to find trait coercions. - match cx.tcx.adjustments.borrow().find(&e.id) { - Some(adjustment) => { - match adjustment { - adj if ty::adjust_is_object(adj) => { - let source_ty = ty::expr_ty(cx.tcx, e); - let target_ty = ty::expr_ty_adjusted(cx.tcx, e); - let method_call = MethodCall { - expr_id: e.id, - adjustment: typeck::AutoObject, - }; - check_trait_cast(cx, - source_ty, - target_ty, - e.span, - method_call); - } - _ => {} - } - } - None => {} - } - visit::walk_expr(cx, e); } - -fn check_bounds_on_type_parameters(cx: &mut Context, e: &Expr) { - let method_map = cx.tcx.method_map.borrow(); - let method_call = typeck::MethodCall::expr(e.id); - let method = method_map.find(&method_call); - - // Find the values that were provided (if any) - let item_substs = cx.tcx.item_substs.borrow(); - let (types, is_object_call) = match method { - Some(method) => { - let is_object_call = match method.origin { - typeck::MethodObject(..) => true, - typeck::MethodStatic(..) | - typeck::MethodStaticUnboxedClosure(..) | - typeck::MethodParam(..) => false - }; - (&method.substs.types, is_object_call) - } - None => { - match item_substs.find(&e.id) { - None => { return; } - Some(s) => { (&s.substs.types, false) } - } - } - }; - - // Find the relevant type parameter definitions - let def_map = cx.tcx.def_map.borrow(); - let type_param_defs = match e.node { - ExprPath(_) => { - let did = def_map.get_copy(&e.id).def_id(); - ty::lookup_item_type(cx.tcx, did).generics.types.clone() - } - _ => { - // Type substitutions should only occur on paths and - // method calls, so this needs to be a method call. - - // Even though the callee_id may have been the id with - // node_type_substs, e.id is correct here. - match method { - Some(method) => { - ty::method_call_type_param_defs(cx.tcx, method.origin) - } - None => { - cx.tcx.sess.span_bug(e.span, - "non path/method call expr has type substs??"); - } - } - } - }; - - // Check that the value provided for each definition meets the - // kind requirements - for type_param_def in type_param_defs.iter() { - let ty = *types.get(type_param_def.space, type_param_def.index); - - // If this is a call to an object method (`foo.bar()` where - // `foo` has a type like `Trait`), then the self type is - // unknown (after all, this is a virtual call). In that case, - // we will have put a ty_err in the substitutions, and we can - // just skip over validating the bounds (because the bounds - // would have been enforced when the object instance was - // created). - if is_object_call && type_param_def.space == subst::SelfSpace { - assert_eq!(type_param_def.index, 0); - assert!(ty::type_is_error(ty)); - continue; - } - - debug!("type_param_def space={} index={} ty={}", - type_param_def.space, type_param_def.index, ty.repr(cx.tcx)); - check_typaram_bounds(cx, e.span, ty, type_param_def) - } - - // Check the vtable. - let vtable_map = cx.tcx.vtable_map.borrow(); - let vtable_res = match vtable_map.find(&method_call) { - None => return, - Some(vtable_res) => vtable_res, - }; - check_type_parameter_bounds_in_vtable_result(cx, e.span, vtable_res); -} - -fn check_type_parameter_bounds_in_vtable_result( - cx: &mut Context, - span: Span, - vtable_res: &typeck::vtable_res) { - for origins in vtable_res.iter() { - for origin in origins.iter() { - let (type_param_defs, substs) = match *origin { - typeck::vtable_static(def_id, ref tys, _) => { - let type_param_defs = - ty::lookup_item_type(cx.tcx, def_id).generics - .types - .clone(); - (type_param_defs, (*tys).clone()) - } - _ => { - // Nothing to do here. - continue - } - }; - for type_param_def in type_param_defs.iter() { - let typ = substs.types.get(type_param_def.space, - type_param_def.index); - check_typaram_bounds(cx, span, *typ, type_param_def) - } - } - } -} - -fn check_trait_cast(cx: &mut Context, - source_ty: ty::t, - target_ty: ty::t, - span: Span, - method_call: MethodCall) { - match ty::get(target_ty).sty { - ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ ty, .. }) => { - match ty::get(ty).sty { - ty::ty_trait(box ty::TyTrait { bounds, .. }) => { - match cx.tcx.vtable_map.borrow().find(&method_call) { - None => { - cx.tcx.sess.span_bug(span, - "trait cast not in vtable \ - map?!") - } - Some(vtable_res) => { - check_type_parameter_bounds_in_vtable_result( - cx, - span, - vtable_res) - } - }; - check_trait_cast_bounds(cx, span, source_ty, - bounds.builtin_bounds); - } - _ => {} - } - } - _ => {} - } -} - fn check_ty(cx: &mut Context, aty: &Ty) { match aty.node { TyPath(_, _, id) => { @@ -651,77 +330,7 @@ pub fn check_typaram_bounds(cx: &Context, }); } -fn check_bounds_on_structs_or_enums_in_type_if_possible(cx: &mut Context, - span: Span, - ty: ty::t) { - // If we aren't in a function, structure, or enumeration context, we don't - // have enough information to ensure that bounds on structures or - // enumerations are satisfied. So we don't perform the check. - if cx.parameter_environments.len() == 0 { - return - } - - // If we've already checked for this type, don't do it again. This - // massively speeds up kind checking. - if cx.struct_and_enum_bounds_checked.contains(&ty) { - return - } - cx.struct_and_enum_bounds_checked.insert(ty); - - ty::walk_ty(ty, |ty| { - match ty::get(ty).sty { - ty::ty_struct(type_id, ref substs) | - ty::ty_enum(type_id, ref substs) => { - let polytype = ty::lookup_item_type(cx.tcx, type_id); - - // Check builtin bounds. - for (ty, type_param_def) in substs.types - .iter() - .zip(polytype.generics - .types - .iter()) { - check_typaram_bounds(cx, span, *ty, type_param_def); - } - - // Check trait bounds. - let parameter_environment = - cx.parameter_environments.get(cx.parameter_environments - .len() - 1); - debug!( - "check_bounds_on_structs_or_enums_in_type_if_possible(): \ - checking {}", - ty.repr(cx.tcx)); - vtable::check_param_bounds(cx.tcx, - span, - parameter_environment, - &polytype.generics.types, - substs, - |missing| { - cx.tcx - .sess - .span_err(span, - format!("instantiating a type parameter with \ - an incompatible type `{}`, which \ - does not fulfill `{}`", - ty_to_string(cx.tcx, ty), - missing.user_string( - cx.tcx)).as_slice()); - }) - } - _ => {} - } - }); -} - -fn check_bounds_on_structs_or_enums_in_trait_ref(cx: &mut Context, - span: Span, - trait_ref: &ty::TraitRef) { - for ty in trait_ref.substs.types.iter() { - check_bounds_on_structs_or_enums_in_type_if_possible(cx, span, *ty) - } -} - -pub fn check_freevar_bounds(cx: &Context, sp: Span, ty: ty::t, +pub fn check_freevar_bounds(cx: &Context, fn_span: Span, sp: Span, ty: ty::t, bounds: ty::BuiltinBounds, referenced_ty: Option) { check_builtin_bounds(cx, ty, bounds, |missing| { @@ -741,7 +350,7 @@ pub fn check_freevar_bounds(cx: &Context, sp: Span, ty: ty::t, ty_to_string(cx.tcx, ty), missing.user_string(cx.tcx)); } } - span_note!(cx.tcx.sess, sp, + span_note!(cx.tcx.sess, fn_span, "this closure's environment must satisfy `{}`", bounds.user_string(cx.tcx)); }); diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index c26505fdc6578..d0b94cb3abb8b 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -5423,7 +5423,7 @@ impl BorrowKind { * Returns a mutability `m` such that an `&m T` pointer could * be used to obtain this borrow kind. Because borrow kinds * are richer than mutabilities, we sometimes have to pick a - * mutability that is stornger than necessary so that it at + * mutability that is stronger than necessary so that it at * least *would permit* the borrow in question. */ diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index 1602dfeaa280a..46aba94a5f12a 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -555,11 +555,9 @@ pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) { None); match tcx.def_map.borrow().find(&pat.id) { Some(def) => { - let item_type = ty::lookup_item_type(tcx, def.def_id()); - let substitutions = fcx.infcx().fresh_substs_for_type( - pat.span, &item_type.generics); + let struct_ty = fcx.instantiate_item_type(pat.span, def.def_id()); check_struct_pat(pcx, pat.span, fields.as_slice(), - etc, def.def_id(), &substitutions); + etc, def.def_id(), &struct_ty.substs); } None => { tcx.sess.span_bug(pat.span, diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index ecda5890fc5b4..074074c13ae90 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -82,6 +82,7 @@ obtained the type `Foo`, we would never match this method. use middle::subst; use middle::subst::Subst; +use middle::traits; use middle::ty::*; use middle::ty; use middle::typeck::astconv::AstConv; @@ -91,7 +92,6 @@ use middle::typeck::infer; use middle::typeck::MethodCallee; use middle::typeck::{MethodOrigin, MethodParam}; use middle::typeck::{MethodStatic, MethodStaticUnboxedClosure, MethodObject}; -use middle::typeck::{param_index}; use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig; use middle::typeck::TypeAndSubsts; use util::common::indenter; @@ -538,14 +538,12 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { return } - let vcx = self.fcx.vtable_context(); - // Get the tupled type of the arguments. let arguments_type = *closure_function_type.sig.inputs.get(0); let return_type = closure_function_type.sig.output; let closure_region = - vcx.infcx.next_region_var(infer::MiscVariable(self.span)); + self.fcx.infcx().next_region_var(infer::MiscVariable(self.span)); let unboxed_closure_type = ty::mk_unboxed_closure(self.tcx(), closure_did, closure_region); @@ -555,7 +553,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { rcvr_substs: subst::Substs::new_trait( vec![arguments_type, return_type], vec![], - *vcx.infcx.next_ty_vars(1).get(0)), + *self.fcx.infcx().next_ty_vars(1).get(0)), method_ty: method, origin: MethodStaticUnboxedClosure(closure_did), }); @@ -618,7 +616,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { self.push_inherent_candidates_from_bounds_inner( &[trait_ref.clone()], - |_this, new_trait_ref, m, method_num, _bound_num| { + |_this, new_trait_ref, m, method_num| { let vtable_index = get_method_index(tcx, &*new_trait_ref, trait_ref.clone(), method_num); @@ -633,7 +631,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { rcvr_substs: new_trait_ref.substs.clone(), method_ty: Rc::new(m), origin: MethodObject(MethodObject { - trait_id: new_trait_ref.def_id, + trait_ref: new_trait_ref, object_trait_id: did, method_num: method_num, real_index: vtable_index @@ -652,8 +650,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { rcvr_ty, param_ty.space, param_ty.idx, - restrict_to, - param_index { space: param_ty.space, index: param_ty.idx }); + restrict_to); } @@ -661,13 +658,12 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { self_ty: ty::t, space: subst::ParamSpace, index: uint, - restrict_to: Option, - param: param_index) { + restrict_to: Option) { let bounds = self.fcx.inh.param_env.bounds.get(space, index).trait_bounds .as_slice(); self.push_inherent_candidates_from_bounds_inner(bounds, - |this, trait_ref, m, method_num, bound_num| { + |this, trait_ref, m, method_num| { match restrict_to { Some(trait_did) => { if trait_did != trait_ref.def_id { @@ -701,10 +697,8 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { rcvr_substs: trait_ref.substs.clone(), method_ty: m, origin: MethodParam(MethodParam { - trait_id: trait_ref.def_id, + trait_ref: trait_ref, method_num: method_num, - param_num: param, - bound_num: bound_num, }) }) }) @@ -718,15 +712,16 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { mk_cand: |this: &mut LookupContext, tr: Rc, m: Rc, - method_num: uint, - bound_num: uint| - -> Option) { + method_num: uint| + -> Option) + { let tcx = self.tcx(); - let mut next_bound_idx = 0; // count only trait bounds - - ty::each_bound_trait_and_supertraits(tcx, bounds, |bound_trait_ref| { - let this_bound_idx = next_bound_idx; - next_bound_idx += 1; + let mut cache = HashSet::new(); + for bound_trait_ref in traits::transitive_bounds(tcx, bounds) { + // Already visited this trait, skip it. + if !cache.insert(bound_trait_ref.def_id) { + continue; + } let trait_items = ty::trait_items(tcx, bound_trait_ref.def_id); match trait_items.iter().position(|ti| { @@ -745,8 +740,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { match mk_cand(self, bound_trait_ref, method, - pos, - this_bound_idx) { + pos) { Some(cand) => { debug!("pushing inherent candidate for param: {}", cand.repr(self.tcx())); @@ -761,8 +755,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { // check next trait or bound } } - true - }); + } } @@ -773,7 +766,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { let impl_items = self.tcx().impl_items.borrow(); for impl_infos in self.tcx().inherent_impls.borrow().find(&did).iter() { - for impl_did in impl_infos.borrow().iter() { + for impl_did in impl_infos.iter() { let items = impl_items.get(impl_did); self.push_candidates_from_impl(*impl_did, items.as_slice(), @@ -825,11 +818,10 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { // determine the `self` of the impl with fresh // variables for each parameter: let span = self.self_expr.map_or(self.span, |e| e.span); - let vcx = self.fcx.vtable_context(); let TypeAndSubsts { substs: impl_substs, ty: impl_ty - } = impl_self_ty(&vcx, span, impl_did); + } = impl_self_ty(self.fcx, span, impl_did); let condition = match method.explicit_self { ByReferenceExplicitSelfCategory(_, mt) if mt == MutMutable => @@ -877,7 +869,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { adjustment {:?} for {}", adjustment, self.ty_to_string(self_ty)); match adjustment { Some((self_expr_id, adj)) => { - self.fcx.write_adjustment(self_expr_id, adj); + self.fcx.write_adjustment(self_expr_id, self.span, adj); } None => {} } @@ -1109,7 +1101,9 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { ty_err => None, - ty_infer(TyVar(_)) => { + ty_infer(TyVar(_)) | + ty_infer(SkolemizedTy(_)) | + ty_infer(SkolemizedIntTy(_)) => { self.bug(format!("unexpected type: {}", self.ty_to_string(self_ty)).as_slice()); } @@ -1150,6 +1144,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { Some(self_expr_id) => { self.fcx.write_adjustment( self_expr_id, + self.span, ty::AutoDerefRef(ty::AutoDerefRef { autoderefs: autoderefs, autoref: Some(kind(region, *mutbl)) @@ -1209,7 +1204,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { // return something so we don't get errors for every mutability return Some(MethodCallee { - origin: relevant_candidates.get(0).origin, + origin: relevant_candidates.get(0).origin.clone(), ty: ty::mk_err(), substs: subst::Substs::empty() }); @@ -1237,12 +1232,14 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { candidate_b.repr(self.tcx())); match (&candidate_a.origin, &candidate_b.origin) { (&MethodParam(ref p1), &MethodParam(ref p2)) => { - let same_trait = p1.trait_id == p2.trait_id; - let same_method = p1.method_num == p2.method_num; - let same_param = p1.param_num == p2.param_num; - // The bound number may be different because - // multiple bounds may lead to the same trait - // impl + let same_trait = + p1.trait_ref.def_id == p2.trait_ref.def_id; + let same_method = + p1.method_num == p2.method_num; + // it's ok to compare self-ty with `==` here because + // they are always a TyParam + let same_param = + p1.trait_ref.self_ty() == p2.trait_ref.self_ty(); same_trait && same_method && same_param } _ => false @@ -1369,13 +1366,13 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { } } - self.fcx.add_region_obligations_for_parameters( - self.span, + self.fcx.add_obligations_for_parameters( + traits::ObligationCause::misc(self.span), &all_substs, &candidate.method_ty.generics); MethodCallee { - origin: candidate.origin, + origin: candidate.origin.clone(), ty: fty, substs: all_substs } @@ -1452,10 +1449,10 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { MethodStaticUnboxedClosure(_) => bad = false, // FIXME: does this properly enforce this on everything now // that self has been merged in? -sully - MethodParam(MethodParam { trait_id: trait_id, .. }) | - MethodObject(MethodObject { trait_id: trait_id, .. }) => { + MethodParam(MethodParam { trait_ref: ref trait_ref, .. }) | + MethodObject(MethodObject { trait_ref: ref trait_ref, .. }) => { bad = self.tcx().destructor_for_type.borrow() - .contains_key(&trait_id); + .contains_key(&trait_ref.def_id); } } @@ -1602,10 +1599,10 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { self.report_static_candidate(idx, did) } MethodParam(ref mp) => { - self.report_param_candidate(idx, (*mp).trait_id) + self.report_param_candidate(idx, mp.trait_ref.def_id) } MethodObject(ref mo) => { - self.report_trait_candidate(idx, mo.trait_id) + self.report_trait_candidate(idx, mo.trait_ref.def_id) } } } diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 375fc75bf62f5..20fe8186adf40 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -87,6 +87,7 @@ use middle::pat_util::pat_id_map; use middle::pat_util; use middle::subst; use middle::subst::{Subst, Substs, VecPerParamSpace, ParamSpace}; +use middle::traits; use middle::ty::{FnSig, VariantInfo}; use middle::ty::{Polytype}; use middle::ty::{Disr, ParamTy, ParameterEnvironment}; @@ -102,15 +103,14 @@ use middle::typeck::check::method::{CheckTraitsAndInherentMethods}; use middle::typeck::check::method::{DontAutoderefReceiver}; use middle::typeck::check::method::{IgnoreStaticMethods, ReportStaticMethods}; use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig; -use middle::typeck::check::vtable::VtableContext; use middle::typeck::CrateCtxt; use middle::typeck::infer::{resolve_type, force_tvar}; use middle::typeck::infer; use middle::typeck::rscope::RegionScope; use middle::typeck::{lookup_def_ccx}; use middle::typeck::no_params; -use middle::typeck::{require_same_types, vtable_map}; -use middle::typeck::{MethodCall, MethodMap}; +use middle::typeck::{require_same_types}; +use middle::typeck::{MethodCall, MethodMap, ObjectCastMap}; use middle::typeck::{TypeAndSubsts}; use middle::typeck; use middle::lang_items::TypeIdLangItem; @@ -143,12 +143,13 @@ use syntax::visit::Visitor; use syntax; pub mod _match; -pub mod vtable; +pub mod vtable2; // New trait code pub mod writeback; pub mod regionmanip; pub mod regionck; pub mod demand; pub mod method; +pub mod wf; /// Fields that are part of a `FnCtxt` which are inherited by /// closures defined within the function. For example: @@ -170,9 +171,9 @@ pub struct Inherited<'a, 'tcx: 'a> { item_substs: RefCell>, adjustments: RefCell>, method_map: MethodMap, - vtable_map: vtable_map, upvar_borrow_map: RefCell, unboxed_closures: RefCell>, + object_cast_map: ObjectCastMap, // A mapping from each fn's id to its signature, with all bound // regions replaced with free ones. Unlike the other tables, this @@ -190,7 +191,7 @@ pub struct Inherited<'a, 'tcx: 'a> { // then in some expression `let x = Foo { ... }` it will // instantiate the type parameter `T` with a fresh type `$0`. At // the same time, it will record a region obligation of - // `$0:'static`. This will get checked later by regionck. (We + // `$0:'static`. This will get checked later by regionck. (We // can't generally check these things right away because we have // to wait until types are resolved.) // @@ -204,6 +205,9 @@ pub struct Inherited<'a, 'tcx: 'a> { // obligations (otherwise, it's easy to fail to walk to a // particular node-id). region_obligations: RefCell>>, + + // Tracks trait obligations incurred during this function body. + fulfillment_cx: RefCell, } struct RegionObligation { @@ -335,11 +339,12 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> { item_substs: RefCell::new(NodeMap::new()), adjustments: RefCell::new(NodeMap::new()), method_map: RefCell::new(FnvHashMap::new()), - vtable_map: RefCell::new(FnvHashMap::new()), + object_cast_map: RefCell::new(NodeMap::new()), upvar_borrow_map: RefCell::new(HashMap::new()), unboxed_closures: RefCell::new(DefIdMap::new()), fn_sig_map: RefCell::new(NodeMap::new()), region_obligations: RefCell::new(NodeMap::new()), + fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()), } } } @@ -369,20 +374,12 @@ fn static_inherited_fields<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>) free_substs: subst::Substs::empty(), bounds: subst::VecPerParamSpace::empty(), implicit_region_bound: ty::ReStatic, + caller_obligations: subst::VecPerParamSpace::empty(), }; Inherited::new(ccx.tcx, param_env) } struct CheckItemTypesVisitor<'a, 'tcx: 'a> { ccx: &'a CrateCtxt<'a, 'tcx> } -struct CheckTypeWellFormedVisitor<'a, 'tcx: 'a> { ccx: &'a CrateCtxt<'a, 'tcx> } - -impl<'a, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'a, 'tcx> { - fn visit_item(&mut self, i: &ast::Item) { - check_type_well_formed(self.ccx, i); - visit::walk_item(self, i); - } -} - impl<'a, 'tcx, 'v> Visitor<'v> for CheckItemTypesVisitor<'a, 'tcx> { fn visit_item(&mut self, i: &ast::Item) { @@ -404,8 +401,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckItemSizedTypesVisitor<'a, 'tcx> { pub fn check_item_types(ccx: &CrateCtxt) { let krate = ccx.tcx.map.krate(); - - let mut visit = CheckTypeWellFormedVisitor { ccx: ccx }; + let mut visit = wf::CheckTypeWellFormedVisitor::new(ccx); visit::walk_crate(&mut visit, krate); // If types are not well-formed, it leads to all manner of errors @@ -437,9 +433,10 @@ fn check_bare_fn(ccx: &CrateCtxt, let fcx = check_fn(ccx, fn_ty.fn_style, id, &fn_ty.sig, decl, id, body, &inh); - vtable::resolve_in_block(&fcx, body); + vtable2::select_all_fcx_obligations_or_error(&fcx); regionck::regionck_fn(&fcx, id, body); writeback::resolve_type_vars_in_fn(&fcx, decl, body); + vtable2::check_builtin_bound_obligations(&fcx); // must happen after writeback } _ => ccx.tcx.sess.impossible_case(body.span, "check_bare_fn: function type expected") @@ -451,19 +448,21 @@ struct GatherLocalsVisitor<'a, 'tcx: 'a> { } impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> { - fn assign(&mut self, nid: ast::NodeId, ty_opt: Option) { - match ty_opt { - None => { - // infer the variable's type - let var_id = self.fcx.infcx().next_ty_var_id(); - let var_ty = ty::mk_var(self.fcx.tcx(), var_id); - self.fcx.inh.locals.borrow_mut().insert(nid, var_ty); - } - Some(typ) => { - // take type that the user specified - self.fcx.inh.locals.borrow_mut().insert(nid, typ); - } + fn assign(&mut self, _span: Span, nid: ast::NodeId, ty_opt: Option) -> ty::t { + match ty_opt { + None => { + // infer the variable's type + let var_id = self.fcx.infcx().next_ty_var_id(); + let var_ty = ty::mk_var(self.fcx.tcx(), var_id); + self.fcx.inh.locals.borrow_mut().insert(nid, var_ty); + var_ty } + Some(typ) => { + // take type that the user specified + self.fcx.inh.locals.borrow_mut().insert(nid, typ); + typ + } + } } } @@ -474,7 +473,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for GatherLocalsVisitor<'a, 'tcx> { ast::TyInfer => None, _ => Some(self.fcx.to_ty(&*local.ty)) }; - self.assign(local.id, o_ty); + self.assign(local.span, local.id, o_ty); debug!("Local variable {} is assigned type {}", self.fcx.pat_to_string(&*local.pat), self.fcx.infcx().ty_to_string( @@ -484,19 +483,23 @@ impl<'a, 'tcx, 'v> Visitor<'v> for GatherLocalsVisitor<'a, 'tcx> { // Add pattern bindings. fn visit_pat(&mut self, p: &ast::Pat) { - match p.node { - ast::PatIdent(_, ref path1, _) - if pat_util::pat_is_binding(&self.fcx.ccx.tcx.def_map, p) => { - self.assign(p.id, None); - debug!("Pattern binding {} is assigned to {}", - token::get_ident(path1.node), - self.fcx.infcx().ty_to_string( - self.fcx.inh.locals.borrow().get_copy(&p.id))); - } - _ => {} - } - visit::walk_pat(self, p); - + match p.node { + ast::PatIdent(_, ref path1, _) + if pat_util::pat_is_binding(&self.fcx.ccx.tcx.def_map, p) => { + let var_ty = self.assign(p.span, p.id, None); + + self.fcx.require_type_is_sized(var_ty, p.span, + traits::VariableType(p.id)); + + debug!("Pattern binding {} is assigned to {} with type {}", + token::get_ident(path1.node), + self.fcx.infcx().ty_to_string( + self.fcx.inh.locals.borrow().get_copy(&p.id)), + var_ty.repr(self.fcx.tcx())); + } + _ => {} + } + visit::walk_pat(self, p); } fn visit_block(&mut self, b: &ast::Block) { @@ -592,11 +595,14 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, // Add formal parameters. for (arg_ty, input) in arg_tys.iter().zip(decl.inputs.iter()) { // Create type variables for each argument. - pat_util::pat_bindings(&tcx.def_map, - &*input.pat, - |_bm, pat_id, _sp, _path| { - visit.assign(pat_id, None); - }); + pat_util::pat_bindings( + &tcx.def_map, + &*input.pat, + |_bm, pat_id, sp, _path| { + let var_ty = visit.assign(sp, pat_id, None); + fcx.require_type_is_sized(var_ty, sp, + traits::VariableType(pat_id)); + }); // Check the pattern. let pcx = pat_ctxt { @@ -713,71 +719,6 @@ pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) { } } -fn check_type_well_formed(ccx: &CrateCtxt, item: &ast::Item) { - /*! - * Checks that the field types (in a struct def'n) or - * argument types (in an enum def'n) are well-formed, - * meaning that they do not require any constraints not - * declared in the struct definition itself. - * For example, this definition would be illegal: - * - * struct Ref<'a, T> { x: &'a T } - * - * because the type did not declare that `T:'a`. - * - * We do this check as a pre-pass before checking fn bodies - * because if these constraints are not included it frequently - * leads to confusing errors in fn bodies. So it's better to check - * the types first. - */ - - debug!("check_type_well_formed(it.id={}, it.ident={})", - item.id, - ty::item_path_str(ccx.tcx, local_def(item.id))); - - match item.node { - ast::ItemStruct(..) => { - check_type_defn(ccx, item, |fcx| { - ty::struct_fields(ccx.tcx, local_def(item.id), - &fcx.inh.param_env.free_substs) - .iter() - .map(|f| f.mt.ty) - .collect() - }); - } - ast::ItemEnum(..) => { - check_type_defn(ccx, item, |fcx| { - ty::substd_enum_variants(ccx.tcx, local_def(item.id), - &fcx.inh.param_env.free_substs) - .iter() - .flat_map(|variant| { - variant.args - .iter() - .map(|&arg_ty| arg_ty) - }) - .collect() - }); - } - _ => {} - } - - fn check_type_defn(ccx: &CrateCtxt, - item: &ast::Item, - lookup_fields: |&FnCtxt| -> Vec) - { - let item_def_id = local_def(item.id); - let polytype = ty::lookup_item_type(ccx.tcx, item_def_id); - let param_env = - ty::construct_parameter_environment(ccx.tcx, - &polytype.generics, - item.id); - let inh = Inherited::new(ccx.tcx, param_env); - let fcx = blank_fn_ctxt(ccx, &inh, polytype.ty, item.id); - let field_tys = lookup_fields(&fcx); - regionck::regionck_type_defn(&fcx, item.span, field_tys.as_slice()); - } -} - pub fn check_item_sized(ccx: &CrateCtxt, it: &ast::Item) { debug!("check_item(it.id={}, it.ident={})", it.id, @@ -836,7 +777,6 @@ pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) { ast_trait_ref, &*impl_trait_ref, impl_items.as_slice()); - vtable::resolve_impl(ccx.tcx, it, &impl_pty.generics, &*impl_trait_ref); } None => { } } @@ -1409,10 +1349,12 @@ fn compare_impl_method(tcx: &ty::ctxt, } fn check_cast(fcx: &FnCtxt, + cast_expr: &ast::Expr, e: &ast::Expr, - t: &ast::Ty, - id: ast::NodeId, - span: Span) { + t: &ast::Ty) { + let id = cast_expr.id; + let span = cast_expr.span; + // Find the type of `e`. Supply hints based on the type we are casting to, // if appropriate. let t_1 = fcx.to_ty(t); @@ -1443,6 +1385,7 @@ fn check_cast(fcx: &FnCtxt, if ty::type_is_trait(t_1) { // This will be looked up later on. + vtable2::check_object_cast(fcx, cast_expr, e, t_1); fcx.write_ty(id, t_1); return } @@ -1582,14 +1525,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn err_count_since_creation(&self) -> uint { self.ccx.tcx.sess.err_count() - self.err_count_on_creation } - - pub fn vtable_context<'a>(&'a self) -> VtableContext<'a, 'tcx> { - VtableContext { - infcx: self.infcx(), - param_env: &self.inh.param_env, - unboxed_closures: &self.inh.unboxed_closures, - } - } } impl<'a, 'tcx> RegionScope for infer::InferCtxt<'a, 'tcx> { @@ -1629,6 +1564,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.inh.node_types.borrow_mut().insert(node_id, ty); } + pub fn write_object_cast(&self, + key: ast::NodeId, + trait_ref: Rc) { + debug!("write_object_cast key={} trait_ref={}", + key, trait_ref.repr(self.tcx())); + self.inh.object_cast_map.borrow_mut().insert(key, trait_ref); + } + pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::ItemSubsts) { if !substs.substs.is_noop() { debug!("write_substs({}, {}) in fcx {}", @@ -1651,10 +1594,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn write_autoderef_adjustment(&self, node_id: ast::NodeId, + span: Span, derefs: uint) { if derefs == 0 { return; } self.write_adjustment( node_id, + span, ty::AutoDerefRef(ty::AutoDerefRef { autoderefs: derefs, autoref: None }) @@ -1663,11 +1608,109 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn write_adjustment(&self, node_id: ast::NodeId, + span: Span, adj: ty::AutoAdjustment) { debug!("write_adjustment(node_id={:?}, adj={:?})", node_id, adj); + + // Careful: adjustments can imply trait obligations if we are + // casting from a concrete type to an object type. I think + // it'd probably be nicer to move the logic that creates the + // obligation into the code that creates the adjustment, but + // that's a bit awkward, so instead we go digging and pull the + // obligation out here. + self.register_adjustment_obligations(span, &adj); self.inh.adjustments.borrow_mut().insert(node_id, adj); } + fn register_adjustment_obligations(&self, + span: Span, + adj: &ty::AutoAdjustment) { + match *adj { + ty::AutoAddEnv(..) => { } + ty::AutoDerefRef(ref d_r) => { + match d_r.autoref { + Some(ref a_r) => { + self.register_autoref_obligations(span, a_r); + } + None => {} + } + } + } + } + + fn register_autoref_obligations(&self, + span: Span, + autoref: &ty::AutoRef) { + match *autoref { + ty::AutoUnsize(ref unsize) => { + self.register_unsize_obligations(span, unsize); + } + ty::AutoPtr(_, _, None) | + ty::AutoUnsafe(_, None) => { + } + ty::AutoPtr(_, _, Some(ref a_r)) | + ty::AutoUnsafe(_, Some(ref a_r)) => { + self.register_autoref_obligations(span, &**a_r) + } + ty::AutoUnsizeUniq(ref unsize) => { + self.register_unsize_obligations(span, unsize); + } + } + } + + fn register_unsize_obligations(&self, + span: Span, + unsize: &ty::UnsizeKind) { + debug!("register_unsize_obligations: unsize={:?}", unsize); + + match *unsize { + ty::UnsizeLength(..) => {} + ty::UnsizeStruct(ref u, _) => { + self.register_unsize_obligations(span, &**u) + } + ty::UnsizeVtable(ref ty_trait, self_ty) => { + vtable2::register_object_cast_obligations(self, + span, + ty_trait, + self_ty); + } + } + } + + pub fn instantiate_item_type(&self, + span: Span, + def_id: ast::DefId) + -> TypeAndSubsts + { + /*! + * Returns the type of `def_id` with all generics replaced by + * by fresh type/region variables. Also returns the + * substitution from the type parameters on `def_id` to the + * fresh variables. Registers any trait obligations specified + * on `def_id` at the same time. + */ + + let polytype = + ty::lookup_item_type(self.tcx(), def_id); + let substs = + self.infcx().fresh_substs_for_generics( + span, + &polytype.generics); + self.add_obligations_for_parameters( + traits::ObligationCause::new( + span, + traits::ItemObligation(def_id)), + &substs, + &polytype.generics); + let monotype = + polytype.ty.subst(self.tcx(), &substs); + + TypeAndSubsts { + ty: monotype, + substs: substs + } + } + pub fn write_nil(&self, node_id: ast::NodeId) { self.write_ty(node_id, ty::mk_nil()); } @@ -1678,8 +1721,56 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.write_ty(node_id, ty::mk_err()); } + pub fn require_type_meets(&self, + ty: ty::t, + span: Span, + code: traits::ObligationCauseCode, + bound: ty::BuiltinBound) + { + self.register_obligation( + traits::obligation_for_builtin_bound( + self.tcx(), + traits::ObligationCause::new(span, code), + ty, + bound)); + } + + pub fn require_type_is_sized(&self, + ty: ty::t, + span: Span, + code: traits::ObligationCauseCode) + { + self.require_type_meets(ty, span, code, ty::BoundSized); + } + + pub fn require_expr_have_sized_type(&self, + expr: &ast::Expr, + code: traits::ObligationCauseCode) + { + self.require_type_is_sized(self.expr_ty(expr), expr.span, code); + } + + pub fn register_obligation(&self, + obligation: traits::Obligation) + { + debug!("register_obligation({})", + obligation.repr(self.tcx())); + + self.inh.fulfillment_cx + .borrow_mut() + .register_obligation(self.tcx(), obligation); + } + pub fn to_ty(&self, ast_t: &ast::Ty) -> ty::t { - ast_ty_to_ty(self, self.infcx(), ast_t) + let t = ast_ty_to_ty(self, self.infcx(), ast_t); + + let mut bounds_checker = wf::BoundsChecker::new(self, + ast_t.span, + self.body_id, + None); + bounds_checker.check_ty(t); + + t } pub fn pat_to_string(&self, pat: &ast::Pat) -> String { @@ -1761,7 +1852,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(None) => Ok(()), Err(ref e) => Err((*e)), Ok(Some(adjustment)) => { - self.write_adjustment(expr.id, adjustment); + self.write_adjustment(expr.id, expr.span, adjustment); Ok(()) } } @@ -1829,10 +1920,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { origin: origin }); } - pub fn add_region_obligations_for_parameters(&self, - span: Span, - substs: &Substs, - generics: &ty::Generics) + pub fn add_obligations_for_parameters(&self, + cause: traits::ObligationCause, + substs: &Substs, + generics: &ty::Generics) { /*! * Given a set of generic parameter definitions (`generics`) @@ -1853,10 +1944,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { * locally. */ - debug!("add_region_obligations_for_parameters(substs={}, generics={})", + debug!("add_obligations_for_parameters(substs={}, generics={})", substs.repr(self.tcx()), generics.repr(self.tcx())); + self.add_trait_obligations_for_generics(cause, substs, generics); + self.add_region_obligations_for_generics(cause, substs, generics); + } + + fn add_trait_obligations_for_generics(&self, + cause: traits::ObligationCause, + substs: &Substs, + generics: &ty::Generics) { + let obligations = + traits::obligations_for_generics(self.tcx(), + cause, + generics, + substs); + obligations.map_move(|o| self.register_obligation(o)); + } + + fn add_region_obligations_for_generics(&self, + cause: traits::ObligationCause, + substs: &Substs, + generics: &ty::Generics) + { assert_eq!(generics.types.iter().len(), substs.types.iter().len()); for (type_def, &type_param) in @@ -1867,8 +1979,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { idx: type_def.index, def_id: type_def.def_id }; let bounds = type_def.bounds.subst(self.tcx(), substs); - add_region_obligations_for_type_parameter( - self, span, param_ty, &bounds, type_param); + self.add_region_obligations_for_type_parameter( + cause.span, param_ty, &bounds, type_param); } assert_eq!(generics.regions.iter().len(), @@ -1878,42 +1990,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { substs.regions().iter()) { let bounds = region_def.bounds.subst(self.tcx(), substs); - add_region_obligations_for_region_parameter( - self, span, bounds.as_slice(), region_param); - } - - fn add_region_obligations_for_type_parameter( - fcx: &FnCtxt, - span: Span, - param_ty: ty::ParamTy, - param_bound: &ty::ParamBounds, - ty: ty::t) - { - // For each declared region bound `T:r`, `T` must outlive `r`. - let region_bounds = - ty::required_region_bounds( - fcx.tcx(), - param_bound.opt_region_bound.as_slice(), - param_bound.builtin_bounds, - param_bound.trait_bounds.as_slice()); - for &r in region_bounds.iter() { - let origin = infer::RelateParamBound(span, param_ty, ty); - fcx.register_region_obligation(origin, ty, r); - } + self.add_region_obligations_for_region_parameter( + cause.span, bounds.as_slice(), region_param); } + } - fn add_region_obligations_for_region_parameter( - fcx: &FnCtxt, - span: Span, - region_bounds: &[ty::Region], - region_param: ty::Region) - { - for &b in region_bounds.iter() { - // For each bound `region:b`, `b <= region` must hold - // (i.e., `region` must outlive `b`). - let origin = infer::RelateRegionParamBound(span); - fcx.mk_subr(origin, b, region_param); - } + fn add_region_obligations_for_type_parameter(&self, + span: Span, + param_ty: ty::ParamTy, + param_bound: &ty::ParamBounds, + ty: ty::t) + { + // For each declared region bound `T:r`, `T` must outlive `r`. + let region_bounds = + ty::required_region_bounds( + self.tcx(), + param_bound.opt_region_bound.as_slice(), + param_bound.builtin_bounds, + param_bound.trait_bounds.as_slice()); + for &r in region_bounds.iter() { + let origin = infer::RelateParamBound(span, param_ty, ty); + self.register_region_obligation(origin, ty, r); + } + } + + fn add_region_obligations_for_region_parameter(&self, + span: Span, + region_bounds: &[ty::Region], + region_param: ty::Region) + { + for &b in region_bounds.iter() { + // For each bound `region:b`, `b <= region` must hold + // (i.e., `region` must outlive `b`). + let origin = infer::RelateRegionParamBound(span); + self.mk_subr(origin, b, region_param); } } } @@ -2272,7 +2382,7 @@ fn check_method_argument_types(fcx: &FnCtxt, fn check_argument_types(fcx: &FnCtxt, sp: Span, fn_inputs: &[ty::t], - callee_expr: &ast::Expr, + _callee_expr: &ast::Expr, args: &[P], deref_args: DerefArgs, variadic: bool, @@ -2369,7 +2479,7 @@ fn check_argument_types(fcx: &FnCtxt, // an "opportunistic" vtable resolution of any trait // bounds on the call. if check_blocks { - vtable::early_resolve_expr(callee_expr, fcx, true); + vtable2::select_fcx_obligations_where_possible(fcx); } // For variadic functions, we don't have a declared type for all of @@ -2568,16 +2678,15 @@ fn check_expr_with_lvalue_pref(fcx: &FnCtxt, expr: &ast::Expr, check_expr_with_unifier(fcx, expr, NoExpectation, lvalue_pref, || ()) } - // determine the `self` type, using fresh variables for all variables // declared on the impl declaration e.g., `impl for ~[(A,B)]` // would return ($0, $1) where $0 and $1 are freshly instantiated type // variables. -pub fn impl_self_ty(vcx: &VtableContext, +pub fn impl_self_ty(fcx: &FnCtxt, span: Span, // (potential) receiver for this impl did: ast::DefId) -> TypeAndSubsts { - let tcx = vcx.tcx(); + let tcx = fcx.tcx(); let ity = ty::lookup_item_type(tcx, did); let (n_tps, rps, raw_ty) = @@ -2585,8 +2694,8 @@ pub fn impl_self_ty(vcx: &VtableContext, ity.generics.regions.get_slice(subst::TypeSpace), ity.ty); - let rps = vcx.infcx.region_vars_for_defs(span, rps); - let tps = vcx.infcx.next_ty_vars(n_tps); + let rps = fcx.inh.infcx.region_vars_for_defs(span, rps); + let tps = fcx.inh.infcx.next_ty_vars(n_tps); let substs = subst::Substs::new_type(tps, rps); let substd_ty = raw_ty.subst(tcx, &substs); @@ -3260,7 +3369,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt, match field_ty { Some(field_ty) => { fcx.write_ty(expr.id, field_ty); - fcx.write_autoderef_adjustment(base.id, autoderefs); + fcx.write_autoderef_adjustment(base.id, base.span, autoderefs); return; } None => {} @@ -3344,7 +3453,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt, match field_ty { Some(field_ty) => { fcx.write_ty(expr.id, field_ty); - fcx.write_autoderef_adjustment(base.id, autoderefs); + fcx.write_autoderef_adjustment(base.id, base.span, autoderefs); return; } None => {} @@ -3467,15 +3576,11 @@ fn check_expr_with_unifier(fcx: &FnCtxt, base_expr: Option<&ast::Expr>) { let tcx = fcx.ccx.tcx; - // Look up the number of type parameters and the raw type, and - // determine whether the class is region-parameterized. - let item_type = ty::lookup_item_type(tcx, class_id); - let raw_type = item_type.ty; - // Generate the struct type. - let substitutions = fcx.infcx().fresh_substs_for_type( - span, &item_type.generics); - let mut struct_type = raw_type.subst(tcx, &substitutions); + let TypeAndSubsts { + ty: mut struct_type, + substs: struct_substs + } = fcx.instantiate_item_type(span, class_id); // Look up and check the fields. let class_fields = ty::lookup_struct_fields(tcx, class_id); @@ -3484,7 +3589,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt, span, class_id, id, - substitutions, + struct_substs, class_fields.as_slice(), fields, base_expr.is_none()); @@ -3517,9 +3622,10 @@ fn check_expr_with_unifier(fcx: &FnCtxt, // Look up the number of type parameters and the raw type, and // determine whether the enum is region-parameterized. - let item_type = ty::lookup_item_type(tcx, enum_id); - let substitutions = fcx.infcx().fresh_substs_for_type(span, &item_type.generics); - let enum_type = item_type.ty.subst(tcx, &substitutions); + let TypeAndSubsts { + ty: enum_type, + substs: substitutions + } = fcx.instantiate_item_type(span, enum_id); // Look up and check the enum variant fields. let variant_fields = ty::lookup_struct_fields(tcx, variant_id); @@ -3619,6 +3725,8 @@ fn check_expr_with_unifier(fcx: &FnCtxt, span_err!(tcx.sess, lhs.span, E0067, "illegal left-hand side expression"); } + fcx.require_expr_have_sized_type(&**lhs, traits::AssignmentLhsSized); + // Overwrite result of check_binop...this preserves existing behavior // but seems quite dubious with regard to user-defined methods // and so forth. - Niko @@ -3833,6 +3941,8 @@ fn check_expr_with_unifier(fcx: &FnCtxt, check_expr_has_type(fcx, &**rhs, lhs_ty); let rhs_ty = fcx.expr_ty(&**rhs); + fcx.require_expr_have_sized_type(&**lhs, traits::AssignmentLhsSized); + if ty::type_is_error(lhs_ty) || ty::type_is_error(rhs_ty) { fcx.write_error(id); } else if ty::type_is_bot(lhs_ty) || ty::type_is_bot(rhs_ty) { @@ -3863,7 +3973,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt, ast::ExprForLoop(ref pat, ref head, ref block, _) => { check_expr(fcx, &**head); let typ = lookup_method_for_for_loop(fcx, &**head, expr.id); - vtable::early_resolve_expr(expr, fcx, true); + vtable2::select_fcx_obligations_where_possible(fcx); let pcx = pat_ctxt { fcx: fcx, @@ -3958,7 +4068,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt, } _ => {} } - check_cast(fcx, &**e, &**t, id, expr.span); + check_cast(fcx, expr, &**e, &**t); } ast::ExprVec(ref args) => { let uty = match expected { @@ -4015,6 +4125,16 @@ fn check_expr_with_unifier(fcx: &FnCtxt, } }; + if count > 1 { + // For [foo, ..n] where n > 1, `foo` must have + // Copy type: + fcx.require_type_meets( + t, + expr.span, + traits::RepeatVec, + ty::BoundCopy); + } + if ty::type_is_error(element_ty) { fcx.write_error(id); } else if ty::type_is_bot(element_ty) { @@ -4143,6 +4263,8 @@ fn check_expr_with_unifier(fcx: &FnCtxt, } } } + + fcx.require_expr_have_sized_type(expr, traits::StructInitializerSized); } ast::ExprField(ref base, ref field, ref tys) => { check_field(fcx, expr, lvalue_pref, &**base, field, tys.as_slice()); @@ -4167,7 +4289,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt, Some(ty) => { check_expr_has_type(fcx, &**idx, ty::mk_uint()); fcx.write_ty(id, ty); - fcx.write_autoderef_adjustment(base.id, autoderefs); + fcx.write_autoderef_adjustment(base.id, base.span, autoderefs); } None => { // This is an overloaded method. @@ -4520,8 +4642,10 @@ pub fn check_const_with_ty(fcx: &FnCtxt, check_expr_with_hint(fcx, e, declty); demand::coerce(fcx, e.span, declty, e); + vtable2::select_all_fcx_obligations_or_error(fcx); regionck::regionck_expr(fcx, e); writeback::resolve_type_vars_in_expr(fcx, e); + vtable2::check_builtin_bound_obligations(fcx); } /// Checks whether a type can be represented in memory. In particular, it @@ -5009,8 +5133,11 @@ pub fn instantiate_path(fcx: &FnCtxt, assert_eq!(substs.regions().len(space), region_defs.len(space)); } - fcx.add_region_obligations_for_parameters( - span, &substs, &polytype.generics); + fcx.add_obligations_for_parameters( + traits::ObligationCause::new(span, + traits::ItemObligation(def.def_id())), + &substs, + &polytype.generics); fcx.write_ty_substs(node_id, polytype.ty, ty::ItemSubsts { substs: substs, diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index 95b7e03e6d9aa..45ffddf3fe80e 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -155,18 +155,9 @@ pub fn regionck_expr(fcx: &FnCtxt, e: &ast::Expr) { fcx.infcx().resolve_regions_and_report_errors(); } -pub fn regionck_type_defn(fcx: &FnCtxt, - span: Span, - component_tys: &[ty::t]) { - let mut rcx = Rcx::new(fcx, 0); - for &component_ty in component_tys.iter() { - // Check that each type outlives the empty region. Since the - // empty region is a subregion of all others, this can't fail - // unless the type does not meet the well-formedness - // requirements. - type_must_outlive(&mut rcx, infer::RelateRegionParamBound(span), - component_ty, ty::ReEmpty); - } +pub fn regionck_item(fcx: &FnCtxt, item: &ast::Item) { + let mut rcx = Rcx::new(fcx, item.id); + rcx.visit_region_obligations(item.id); fcx.infcx().resolve_regions_and_report_errors(); } @@ -179,6 +170,26 @@ pub fn regionck_fn(fcx: &FnCtxt, id: ast::NodeId, blk: &ast::Block) { fcx.infcx().resolve_regions_and_report_errors(); } +pub fn regionck_ensure_component_tys_wf(fcx: &FnCtxt, + span: Span, + component_tys: &[ty::t]) { + /*! + * Checks that the types in `component_tys` are well-formed. + * This will add constraints into the region graph. + * Does *not* run `resolve_regions_and_report_errors` and so forth. + */ + + let mut rcx = Rcx::new(fcx, 0); + for &component_ty in component_tys.iter() { + // Check that each type outlives the empty region. Since the + // empty region is a subregion of all others, this can't fail + // unless the type does not meet the well-formedness + // requirements. + type_must_outlive(&mut rcx, infer::RelateRegionParamBound(span), + component_ty, ty::ReEmpty); + } +} + /////////////////////////////////////////////////////////////////////////// // INTERNALS diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs deleted file mode 100644 index 9a70cf574fc4d..0000000000000 --- a/src/librustc/middle/typeck/check/vtable.rs +++ /dev/null @@ -1,1077 +0,0 @@ -// Copyright 2012-2014 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - - -use middle::ty; -use middle::ty::{AutoDerefRef, ParamTy}; -use middle::ty_fold::TypeFolder; -use middle::typeck::astconv::AstConv; -use middle::typeck::check::{FnCtxt, impl_self_ty}; -use middle::typeck::check::{structurally_resolved_type}; -use middle::typeck::check::regionmanip; -use middle::typeck::check::writeback; -use middle::typeck::infer::fixup_err_to_string; -use middle::typeck::infer::{resolve_and_force_all_but_regions, resolve_type}; -use middle::typeck::infer; -use middle::typeck::{MethodCall, TypeAndSubsts}; -use middle::typeck::{param_index, vtable_error, vtable_origin, vtable_param}; -use middle::typeck::{vtable_param_res, vtable_res, vtable_static}; -use middle::typeck::{vtable_unboxed_closure}; -use middle::subst; -use middle::subst::{Subst, VecPerParamSpace}; -use util::common::indenter; -use util::nodemap::DefIdMap; -use util::ppaux; -use util::ppaux::Repr; - -use std::cell::RefCell; -use std::rc::Rc; -use std::collections::HashSet; -use syntax::ast; -use syntax::ast_util; -use syntax::codemap::Span; -use syntax::print::pprust::expr_to_string; -use syntax::visit; -use syntax::visit::Visitor; - -// vtable resolution looks for places where trait bounds are -// substituted in and figures out which vtable is used. There is some -// extra complication thrown in to support early "opportunistic" -// vtable resolution. This is a hacky mechanism that is invoked while -// typechecking function calls (after typechecking non-closure -// arguments and before typechecking closure arguments) in the hope of -// solving for the trait parameters from the impl. (For example, -// determining that if a parameter bounded by BaseIter is -// instantiated with Option, that A = int.) -// -// In early resolution mode, no vtables are recorded, and a number of -// errors are ignored. Early resolution only works if a type is -// *fully* resolved. (We could be less restrictive than that, but it -// would require much more care, and this seems to work decently in -// practice.) -// -// While resolution on a single type requires the type to be fully -// resolved, when resolving a substitution against a list of bounds, -// we do not require all of the types to be resolved in advance. -// Furthermore, we process substitutions in reverse order, which -// allows resolution on later parameters to give information on -// earlier params referenced by the typeclass bounds. -// It may be better to do something more clever, like processing fully -// resolved types first. - -/// A vtable context includes an inference context, a parameter environment, -/// and a list of unboxed closure types. -pub struct VtableContext<'a, 'tcx: 'a> { - pub infcx: &'a infer::InferCtxt<'a, 'tcx>, - pub param_env: &'a ty::ParameterEnvironment, - pub unboxed_closures: &'a RefCell>, -} - -impl<'a, 'tcx> VtableContext<'a, 'tcx> { - pub fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.infcx.tcx } -} - -fn lookup_vtables(vcx: &VtableContext, - span: Span, - type_param_defs: &VecPerParamSpace, - substs: &subst::Substs, - is_early: bool) - -> VecPerParamSpace { - debug!("lookup_vtables(\ - type_param_defs={}, \ - substs={}", - type_param_defs.repr(vcx.tcx()), - substs.repr(vcx.tcx())); - - // We do this backwards for reasons discussed above. - let result = type_param_defs.map_rev(|def| { - let ty = *substs.types.get(def.space, def.index); - lookup_vtables_for_param(vcx, span, Some(substs), - &def.bounds, ty, is_early) - }); - - debug!("lookup_vtables result(\ - type_param_defs={}, \ - substs={}, \ - result={})", - type_param_defs.repr(vcx.tcx()), - substs.repr(vcx.tcx()), - result.repr(vcx.tcx())); - - result -} - -fn lookup_vtables_for_param(vcx: &VtableContext, - span: Span, - // None for substs means the identity - substs: Option<&subst::Substs>, - type_param_bounds: &ty::ParamBounds, - ty: ty::t, - is_early: bool) - -> vtable_param_res { - let tcx = vcx.tcx(); - - debug!("lookup_vtables_for_param(ty={}, type_param_bounds={}, is_early={})", - ty.repr(vcx.tcx()), - type_param_bounds.repr(vcx.tcx()), - is_early); - - // ty is the value supplied for the type parameter A... - let mut param_result = Vec::new(); - - ty::each_bound_trait_and_supertraits(tcx, - type_param_bounds.trait_bounds - .as_slice(), - |trait_ref| { - // ...and here trait_ref is each bound that was declared on A, - // expressed in terms of the type parameters. - - debug!("matching ty={} trait_ref={}", - ty.repr(vcx.tcx()), - trait_ref.repr(vcx.tcx())); - - ty::populate_implementations_for_trait_if_necessary(tcx, - trait_ref.def_id); - - // Substitute the values of the type parameters that may - // appear in the bound. - let trait_ref = substs.as_ref().map_or(trait_ref.clone(), |substs| { - debug!("about to subst: {}, {}", - trait_ref.repr(tcx), substs.repr(tcx)); - trait_ref.subst(tcx, *substs) - }); - - debug!("after subst: {}", trait_ref.repr(tcx)); - - match lookup_vtable(vcx, span, ty, trait_ref.clone(), is_early) { - Some(vtable) => param_result.push(vtable), - None => { - vcx.tcx().sess.span_err(span, - format!("failed to find an implementation of \ - trait {} for {}", - vcx.infcx.trait_ref_to_string(&*trait_ref), - vcx.infcx.ty_to_string(ty)).as_slice()); - param_result.push(vtable_error) - } - } - true - }); - - debug!("lookup_vtables_for_param result(\ - type_param_bounds={}, \ - ty={}, \ - result={})", - type_param_bounds.repr(vcx.tcx()), - ty.repr(vcx.tcx()), - param_result.repr(vcx.tcx())); - - param_result -} - -fn relate_trait_refs(vcx: &VtableContext, - span: Span, - act_trait_ref: Rc, - exp_trait_ref: Rc) { - /*! - * - * Checks that an implementation of `act_trait_ref` is suitable - * for use where `exp_trait_ref` is required and reports an - * error otherwise. - */ - - match infer::mk_sub_trait_refs(vcx.infcx, - false, - infer::RelateTraitRefs(span), - act_trait_ref.clone(), - exp_trait_ref.clone()) { - Ok(()) => {} // Ok. - Err(ref err) => { - // There is an error, but we need to do some work to make - // the message good. - // Resolve any type vars in the trait refs - let r_act_trait_ref = - vcx.infcx.resolve_type_vars_in_trait_ref_if_possible(&*act_trait_ref); - let r_exp_trait_ref = - vcx.infcx.resolve_type_vars_in_trait_ref_if_possible(&*exp_trait_ref); - // Only print the message if there aren't any previous type errors - // inside the types. - if !ty::trait_ref_contains_error(&r_act_trait_ref) && - !ty::trait_ref_contains_error(&r_exp_trait_ref) - { - let tcx = vcx.tcx(); - span_err!(tcx.sess, span, E0095, "expected {}, found {} ({})", - ppaux::trait_ref_to_string(tcx, &r_exp_trait_ref), - ppaux::trait_ref_to_string(tcx, &r_act_trait_ref), - ty::type_err_to_str(tcx, err)); - } - } - } -} - -// Look up the vtable implementing the trait `trait_ref` at type `t` -fn lookup_vtable(vcx: &VtableContext, - span: Span, - ty: ty::t, - trait_ref: Rc, - is_early: bool) - -> Option -{ - debug!("lookup_vtable(ty={}, trait_ref={})", - ty.repr(vcx.tcx()), - trait_ref.repr(vcx.tcx())); - let _i = indenter(); - - let ty = match fixup_ty(vcx, span, ty, is_early) { - Some(ty) => ty, - None => { - // fixup_ty can only fail if this is early resolution - assert!(is_early); - // The type has unconstrained type variables in it, so we can't - // do early resolution on it. Return some completely bogus vtable - // information: we aren't storing it anyways. - return Some(vtable_error); - } - }; - - if ty::type_is_error(ty) { - return Some(vtable_error); - } - - // If the type is self or a param, we look at the trait/supertrait - // bounds to see if they include the trait we are looking for. - let vtable_opt = match ty::get(ty).sty { - ty::ty_param(ParamTy {space, idx: n, ..}) => { - let env_bounds = &vcx.param_env.bounds; - let type_param_bounds = &env_bounds.get(space, n).trait_bounds; - lookup_vtable_from_bounds(vcx, - span, - type_param_bounds.as_slice(), - param_index { - space: space, - index: n, - }, - trait_ref.clone()) - } - - // Default case just falls through - _ => None - }; - - if vtable_opt.is_some() { return vtable_opt; } - - // If we aren't a self type or param, or it was, but we didn't find it, - // do a search. - search_for_vtable(vcx, span, ty, trait_ref, is_early) -} - -// Given a list of bounds on a type, search those bounds to see if any -// of them are the vtable we are looking for. -fn lookup_vtable_from_bounds(vcx: &VtableContext, - span: Span, - bounds: &[Rc], - param: param_index, - trait_ref: Rc) - -> Option { - let tcx = vcx.tcx(); - - let mut n_bound = 0; - let mut ret = None; - ty::each_bound_trait_and_supertraits(tcx, bounds, |bound_trait_ref| { - debug!("checking bounds trait {}", - bound_trait_ref.repr(vcx.tcx())); - - if bound_trait_ref.def_id == trait_ref.def_id { - relate_trait_refs(vcx, span, bound_trait_ref, trait_ref.clone()); - let vtable = vtable_param(param, n_bound); - debug!("found param vtable: {:?}", - vtable); - ret = Some(vtable); - false - } else { - n_bound += 1; - true - } - }); - ret -} - -fn search_for_unboxed_closure_vtable(vcx: &VtableContext, - span: Span, - ty: ty::t, - trait_ref: Rc) - -> Option { - let tcx = vcx.tcx(); - let closure_def_id = match ty::get(ty).sty { - ty::ty_unboxed_closure(closure_def_id, _) => closure_def_id, - _ => return None, - }; - - let fn_traits = [ - (ty::FnUnboxedClosureKind, tcx.lang_items.fn_trait()), - (ty::FnMutUnboxedClosureKind, tcx.lang_items.fn_mut_trait()), - (ty::FnOnceUnboxedClosureKind, tcx.lang_items.fn_once_trait()), - ]; - for tuple in fn_traits.iter() { - let kind = match tuple { - &(kind, Some(ref fn_trait)) if *fn_trait == trait_ref.def_id => { - kind - } - _ => continue, - }; - - // Check to see whether the argument and return types match. - let unboxed_closures = tcx.unboxed_closures.borrow(); - let closure_type = match unboxed_closures.find(&closure_def_id) { - Some(closure) => { - if closure.kind != kind { - continue - } - closure.closure_type.clone() - } - None => { - // Try the inherited unboxed closure type map. - let unboxed_closures = vcx.unboxed_closures.borrow(); - match unboxed_closures.find(&closure_def_id) { - Some(closure) => { - if closure.kind != kind { - continue - } - closure.closure_type.clone() - } - None => { - tcx.sess.span_bug(span, - "didn't find unboxed closure type \ - in tcx map or inh map") - } - } - } - }; - - // FIXME(pcwalton): This is a bogus thing to do, but - // it'll do for now until we get the new trait-bound - // region skolemization working. - let (_, new_signature) = - regionmanip::replace_late_bound_regions_in_fn_sig( - tcx, - &closure_type.sig, - |br| { - vcx.infcx.next_region_var(infer::LateBoundRegion(span, - br)) - }); - - let arguments_tuple = *new_signature.inputs.get(0); - let corresponding_trait_ref = Rc::new(ty::TraitRef { - def_id: trait_ref.def_id, - substs: subst::Substs::new_trait( - vec![arguments_tuple, new_signature.output], - Vec::new(), - ty) - }); - - relate_trait_refs(vcx, span, corresponding_trait_ref, trait_ref); - return Some(vtable_unboxed_closure(closure_def_id)) - } - - None -} - -fn search_for_vtable(vcx: &VtableContext, - span: Span, - ty: ty::t, - trait_ref: Rc, - is_early: bool) - -> Option { - let tcx = vcx.tcx(); - - // First, check to see whether this is a call to the `call` method of an - // unboxed closure. If so, and the arguments match, we're done. - match search_for_unboxed_closure_vtable(vcx, - span, - ty, - trait_ref.clone()) { - Some(vtable_origin) => return Some(vtable_origin), - None => {} - } - - // Nope. Continue. - - let mut found = Vec::new(); - let mut impls_seen = HashSet::new(); - - // Load the implementations from external metadata if necessary. - ty::populate_implementations_for_trait_if_necessary(tcx, - trait_ref.def_id); - - let impls = match tcx.trait_impls.borrow().find_copy(&trait_ref.def_id) { - Some(impls) => impls, - None => { - return None; - } - }; - // impls is the list of all impls in scope for trait_ref. - for &impl_did in impls.borrow().iter() { - // im is one specific impl of trait_ref. - - // First, ensure we haven't processed this impl yet. - if impls_seen.contains(&impl_did) { - continue; - } - impls_seen.insert(impl_did); - - // ty::impl_traits gives us the trait im implements. - // - // If foo implements a trait t, and if t is the same trait as - // trait_ref, we need to unify it with trait_ref in order to - // get all the ty vars sorted out. - let r = ty::impl_trait_ref(tcx, impl_did); - let of_trait_ref = r.expect("trait_ref missing on trait impl"); - if of_trait_ref.def_id != trait_ref.def_id { continue; } - - // At this point, we know that of_trait_ref is the same trait - // as trait_ref, but possibly applied to different substs. - // - // Next, we check whether the "for" ty in the impl is - // compatible with the type that we're casting to a - // trait. That is, if im is: - // - // impl some_trait for self_ty { ... } - // - // we check whether self_ty is the type of the thing that - // we're trying to cast to some_trait. If not, then we try - // the next impl. - // - // FIXME: document a bit more what this means - let TypeAndSubsts { - substs: substs, - ty: for_ty - } = impl_self_ty(vcx, span, impl_did); - match infer::mk_eqty(vcx.infcx, - false, - infer::RelateSelfType(span), - ty, - for_ty) { - Err(_) => continue, - Ok(()) => () - } - - // Now, in the previous example, for_ty is bound to - // the type self_ty, and substs is bound to [T]. - debug!("The self ty is {} and its substs are {}", - for_ty.repr(tcx), - substs.types.repr(tcx)); - - // Next, we unify trait_ref -- the type that we want to cast - // to -- with of_trait_ref -- the trait that im implements. At - // this point, we require that they be unifiable with each - // other -- that's what relate_trait_refs does. - // - // For example, in the above example, of_trait_ref would be - // some_trait, so we would be unifying trait_ref (for - // some value of U) with some_trait. This would fail if T - // and U weren't compatible. - - let of_trait_ref = of_trait_ref.subst(tcx, &substs); - - debug!("(checking vtable) num 2 relating trait \ - ty {} to of_trait_ref {}", - vcx.infcx.trait_ref_to_string(&*trait_ref), - vcx.infcx.trait_ref_to_string(&*of_trait_ref)); - - relate_trait_refs(vcx, span, of_trait_ref, trait_ref.clone()); - - - // Recall that trait_ref -- the trait type we're casting to -- - // is the trait with id trait_ref.def_id applied to the substs - // trait_ref.substs. - - // Resolve any sub bounds. Note that there still may be free - // type variables in substs. This might still be OK: the - // process of looking up bounds might constrain some of them. - // - // This does not check built-in traits because those are handled - // later in the kind checking pass. - let im_generics = - ty::lookup_item_type(tcx, impl_did).generics; - let subres = lookup_vtables(vcx, - span, - &im_generics.types, - &substs, - is_early); - - // substs might contain type variables, so we call - // fixup_substs to resolve them. - let substs_f = match fixup_substs(vcx, span, - trait_ref.def_id, - substs, - is_early) { - Some(ref substs) => (*substs).clone(), - None => { - assert!(is_early); - // Bail out with a bogus answer - return Some(vtable_error); - } - }; - - debug!("The fixed-up substs are {} - \ - they will be unified with the bounds for \ - the target ty, {}", - substs_f.types.repr(tcx), - trait_ref.repr(tcx)); - - // Next, we unify the fixed-up substitutions for the impl self - // ty with the substitutions from the trait type that we're - // trying to cast to. connect_trait_tps requires these lists - // of types to unify pairwise. - // I am a little confused about this, since it seems to be - // very similar to the relate_trait_refs we already do, - // but problems crop up if it is removed, so... -sully - connect_trait_tps(vcx, span, &substs_f, trait_ref.clone(), impl_did); - - // Finally, we register that we found a matching impl, and - // record the def ID of the impl as well as the resolved list - // of type substitutions for the target trait. - found.push(vtable_static(impl_did, substs_f, subres)); - } - - match found.len() { - 0 => { return None } - 1 => return Some(found.get(0).clone()), - _ => { - if !is_early { - span_err!(vcx.tcx().sess, span, E0096, - "multiple applicable methods in scope"); - } - return Some(found.get(0).clone()); - } - } -} - - -fn fixup_substs(vcx: &VtableContext, - span: Span, - id: ast::DefId, - substs: subst::Substs, - is_early: bool) - -> Option { - let tcx = vcx.tcx(); - // use a dummy type just to package up the substs that need fixing up - let t = ty::mk_trait(tcx, - id, substs, - ty::region_existential_bound(ty::ReStatic)); - fixup_ty(vcx, span, t, is_early).map(|t_f| { - match ty::get(t_f).sty { - ty::ty_trait(ref inner) => inner.substs.clone(), - _ => fail!("t_f should be a trait") - } - }) -} - -fn fixup_ty(vcx: &VtableContext, - span: Span, - ty: ty::t, - is_early: bool) - -> Option { - let tcx = vcx.tcx(); - match resolve_type(vcx.infcx, Some(span), ty, resolve_and_force_all_but_regions) { - Ok(new_type) => Some(new_type), - Err(e) if !is_early => { - tcx.sess.span_err(span, - format!("cannot determine a type for this bounded type \ - parameter: {}", - fixup_err_to_string(e)).as_slice()); - Some(ty::mk_err()) - } - Err(_) => { - None - } - } -} - -fn connect_trait_tps(vcx: &VtableContext, - span: Span, - impl_substs: &subst::Substs, - trait_ref: Rc, - impl_did: ast::DefId) { - let tcx = vcx.tcx(); - - let impl_trait_ref = match ty::impl_trait_ref(tcx, impl_did) { - Some(t) => t, - None => vcx.tcx().sess.span_bug(span, - "connect_trait_tps invoked on a type impl") - }; - - let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs); - relate_trait_refs(vcx, span, impl_trait_ref, trait_ref); -} - -fn insert_vtables(fcx: &FnCtxt, vtable_key: MethodCall, vtables: vtable_res) { - debug!("insert_vtables(vtable_key={}, vtables={})", - vtable_key, vtables.repr(fcx.tcx())); - fcx.inh.vtable_map.borrow_mut().insert(vtable_key, vtables); -} - -pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) { - fn mutability_allowed(a_mutbl: ast::Mutability, - b_mutbl: ast::Mutability) -> bool { - a_mutbl == b_mutbl || - (a_mutbl == ast::MutMutable && b_mutbl == ast::MutImmutable) - } - - debug!("vtable: early_resolve_expr() ex with id {:?} (early: {}): {}", - ex.id, is_early, expr_to_string(ex)); - let _indent = indenter(); - - let cx = fcx.ccx; - let check_object_cast = |src_ty: ty::t, target_ty: ty::t| { - debug!("check_object_cast {} to {}", - fcx.infcx().ty_to_string(src_ty), - fcx.infcx().ty_to_string(target_ty)); - // Check that a cast is of correct types. - match (&ty::get(target_ty).sty, &ty::get(src_ty).sty) { - (&ty::ty_rptr(_, ty::mt{ty, mutbl}), &ty::ty_rptr(_, mt)) - | (&ty::ty_ptr(ty::mt{ty, mutbl}), &ty::ty_rptr(_, mt)) - if !mutability_allowed(mt.mutbl, mutbl) => { - match ty::get(ty).sty { - ty::ty_trait(..) => { - span_err!(fcx.tcx().sess, ex.span, E0097, "types differ in mutability"); - } - _ => {} - } - } - (&ty::ty_uniq(..), &ty::ty_uniq(..) ) - | (&ty::ty_ptr(..), &ty::ty_ptr(..) ) - | (&ty::ty_ptr(..), &ty::ty_rptr(..)) => {} - (&ty::ty_rptr(r_t, _), &ty::ty_rptr(r_s, _)) => { - infer::mk_subr(fcx.infcx(), - infer::RelateObjectBound(ex.span), - r_t, - r_s); - } - (&ty::ty_uniq(ty), _) => { - match ty::get(ty).sty { - ty::ty_trait(..) => { - span_err!(fcx.ccx.tcx.sess, ex.span, E0098, - "can only cast an boxed pointer to a boxed object, not a {}", - ty::ty_sort_string(fcx.tcx(), src_ty)); - } - _ => {} - } - - } - (&ty::ty_rptr(_, ty::mt{ty, ..}), _) => { - match ty::get(ty).sty { - ty::ty_trait(..) => { - span_err!(fcx.ccx.tcx.sess, ex.span, E0099, - "can only cast an &-pointer to an &-object, not a {}", - ty::ty_sort_string(fcx.tcx(), src_ty)); - } - _ => {} - } - } - (&ty::ty_ptr(ty::mt{ty, ..}), _) => { - match ty::get(ty).sty { - ty::ty_trait(..) => { - span_err!(fcx.ccx.tcx.sess, ex.span, E0160, - "can only cast an *-pointer or &-pointer to an *-object, not a {}", - ty::ty_sort_string(fcx.tcx(), src_ty)); - } - _ => {} - } - } - _ => {} - } - }; - let resolve_object_cast = |src_ty: ty::t, target_ty: ty::t, key: MethodCall| { - // Look up vtables for the type we're casting to, - // passing in the source and target type. The source - // must be a pointer type suitable to the object sigil, - // e.g.: `&x as &Trait` or `box x as Box` - // Bounds of type's contents are not checked here, but in kind.rs. - match ty::get(target_ty).sty { - ty::ty_trait(box ty::TyTrait { - def_id: target_def_id, substs: ref target_substs, .. - }) => { - let vcx = fcx.vtable_context(); - - // Take the type parameters from the object - // type, but set the Self type (which is - // unknown, for the object type) to be the type - // we are casting from. - let mut target_types = target_substs.types.clone(); - assert!(target_types.get_self().is_none()); - target_types.push(subst::SelfSpace, src_ty); - - let target_trait_ref = Rc::new(ty::TraitRef { - def_id: target_def_id, - substs: subst::Substs { - regions: target_substs.regions.clone(), - types: target_types - } - }); - - let param_bounds = ty::ParamBounds { - opt_region_bound: None, - builtin_bounds: ty::empty_builtin_bounds(), - trait_bounds: vec!(target_trait_ref) - }; - - let vtables = - lookup_vtables_for_param(&vcx, - ex.span, - None, - ¶m_bounds, - src_ty, - is_early); - - if !is_early { - let mut r = VecPerParamSpace::empty(); - r.push(subst::SelfSpace, vtables); - insert_vtables(fcx, key, r); - } - } - _ => {} - } - }; - match ex.node { - ast::ExprPath(..) => { - fcx.opt_node_ty_substs(ex.id, |item_substs| { - debug!("vtable resolution on parameter bounds for expr {}", - ex.repr(fcx.tcx())); - let def = cx.tcx.def_map.borrow().get_copy(&ex.id); - let did = def.def_id(); - let item_ty = ty::lookup_item_type(cx.tcx, did); - debug!("early resolve expr: def {:?} {:?}, {:?}, {}", ex.id, did, def, - fcx.infcx().ty_to_string(item_ty.ty)); - debug!("early_resolve_expr: looking up vtables for type params {}", - item_ty.generics.types.repr(fcx.tcx())); - let vcx = fcx.vtable_context(); - let vtbls = lookup_vtables(&vcx, ex.span, - &item_ty.generics.types, - &item_substs.substs, is_early); - if !is_early { - insert_vtables(fcx, MethodCall::expr(ex.id), vtbls); - } - }); - } - - // Must resolve bounds on methods with bounded params - ast::ExprBinary(_, _, _) | - ast::ExprUnary(_, _) | - ast::ExprAssignOp(_, _, _) | - ast::ExprIndex(_, _) | - ast::ExprMethodCall(_, _, _) | - ast::ExprForLoop(..) | - ast::ExprCall(..) => { - match fcx.inh.method_map.borrow().find(&MethodCall::expr(ex.id)) { - Some(method) => { - debug!("vtable resolution on parameter bounds for method call {}", - ex.repr(fcx.tcx())); - let type_param_defs = - ty::method_call_type_param_defs(fcx, method.origin); - let substs = fcx.method_ty_substs(ex.id); - let vcx = fcx.vtable_context(); - let vtbls = lookup_vtables(&vcx, ex.span, - &type_param_defs, - &substs, is_early); - if !is_early { - insert_vtables(fcx, MethodCall::expr(ex.id), vtbls); - } - } - None => {} - } - } - ast::ExprCast(ref src, _) => { - debug!("vtable resolution on expr {}", ex.repr(fcx.tcx())); - let target_ty = fcx.expr_ty(ex); - let src_ty = structurally_resolved_type(fcx, ex.span, - fcx.expr_ty(&**src)); - check_object_cast(src_ty, target_ty); - match (ty::deref(src_ty, false), ty::deref(target_ty, false)) { - (Some(s), Some(t)) => { - let key = MethodCall::expr(ex.id); - resolve_object_cast(s.ty, t.ty, key) - } - _ => {} - } - } - _ => () - } - - // Search for auto-adjustments to find trait coercions - match fcx.inh.adjustments.borrow().find(&ex.id) { - Some(adjustment) => { - match *adjustment { - _ if ty::adjust_is_object(adjustment) => { - let src_ty = structurally_resolved_type(fcx, ex.span, - fcx.expr_ty(ex)); - match ty::type_of_adjust(fcx.tcx(), adjustment) { - Some(target_ty) => { - check_object_cast(src_ty, target_ty) - } - None => {} - } - - match trait_cast_types(fcx, adjustment, src_ty, ex.span) { - Some((s, t)) => { - let key = MethodCall::autoobject(ex.id); - resolve_object_cast(s, t, key) - } - None => fail!("Couldn't extract types from adjustment") - } - } - AutoDerefRef(ref adj) => { - for autoderef in range(0, adj.autoderefs) { - let method_call = MethodCall::autoderef(ex.id, autoderef); - match fcx.inh.method_map.borrow().find(&method_call) { - Some(method) => { - debug!("vtable resolution on parameter bounds for autoderef {}", - ex.repr(fcx.tcx())); - let type_param_defs = - ty::method_call_type_param_defs(cx.tcx, method.origin); - let vcx = fcx.vtable_context(); - let vtbls = lookup_vtables(&vcx, ex.span, - &type_param_defs, - &method.substs, is_early); - if !is_early { - insert_vtables(fcx, method_call, vtbls); - } - } - None => {} - } - } - } - _ => {} - } - } - None => {} - } -} - -// When we coerce (possibly implicitly) from a concrete type to a trait type, this -// function returns the concrete type and trait. This might happen arbitrarily -// deep in the adjustment. This function will fail if the adjustment does not -// match the source type. -// This function will always return types if ty::adjust_is_object is true for the -// adjustment -fn trait_cast_types(fcx: &FnCtxt, - adj: &ty::AutoAdjustment, - src_ty: ty::t, - sp: Span) - -> Option<(ty::t, ty::t)> { - fn trait_cast_types_autoref(fcx: &FnCtxt, - autoref: &ty::AutoRef, - src_ty: ty::t, - sp: Span) - -> Option<(ty::t, ty::t)> { - fn trait_cast_types_unsize(fcx: &FnCtxt, - k: &ty::UnsizeKind, - src_ty: ty::t, - sp: Span) - -> Option<(ty::t, ty::t)> { - match k { - &ty::UnsizeVtable(bounds, def_id, ref substs) => { - Some((src_ty, ty::mk_trait(fcx.tcx(), def_id, substs.clone(), bounds))) - } - &ty::UnsizeStruct(box ref k, tp_index) => match ty::get(src_ty).sty { - ty::ty_struct(_, ref substs) => { - let ty_substs = substs.types.get_slice(subst::TypeSpace); - let field_ty = structurally_resolved_type(fcx, sp, ty_substs[tp_index]); - trait_cast_types_unsize(fcx, k, field_ty, sp) - } - _ => fail!("Failed to find a ty_struct to correspond with \ - UnsizeStruct whilst walking adjustment. Found {}", - ppaux::ty_to_string(fcx.tcx(), src_ty)) - }, - _ => None - } - } - - match autoref { - &ty::AutoUnsize(ref k) | - &ty::AutoUnsizeUniq(ref k) => trait_cast_types_unsize(fcx, k, src_ty, sp), - &ty::AutoPtr(_, _, Some(box ref autoref)) | - &ty::AutoUnsafe(_, Some(box ref autoref)) => { - trait_cast_types_autoref(fcx, autoref, src_ty, sp) - } - _ => None - } - } - - match adj { - &ty::AutoDerefRef(AutoDerefRef{autoref: Some(ref autoref), autoderefs}) => { - let mut derefed_type = src_ty; - for _ in range(0, autoderefs) { - derefed_type = ty::deref(derefed_type, true).unwrap().ty; - derefed_type = structurally_resolved_type(fcx, sp, derefed_type) - } - trait_cast_types_autoref(fcx, autoref, derefed_type, sp) - } - _ => None - } -} - -pub fn resolve_impl(tcx: &ty::ctxt, - impl_item: &ast::Item, - impl_generics: &ty::Generics, - impl_trait_ref: &ty::TraitRef) { - /*! - * The situation is as follows. We have some trait like: - * - * trait Foo : Bar { - * fn method() { ... } - * } - * - * and an impl like: - * - * impl Foo for int { ... } - * - * We want to validate that the various requirements of the trait - * are met: - * - * A:Clone, Self:Bar - * - * But of course after substituting the types from the impl: - * - * B:Clone, int:Bar - * - * We store these results away as the "impl_res" for use by the - * default methods. - */ - - debug!("resolve_impl(impl_item.id={})", - impl_item.id); - - let param_env = ty::construct_parameter_environment(tcx, - impl_generics, - impl_item.id); - - // The impl_trait_ref in our example above would be - // `Foo for int` - let impl_trait_ref = impl_trait_ref.subst(tcx, ¶m_env.free_substs); - debug!("impl_trait_ref={}", impl_trait_ref.repr(tcx)); - - let infcx = &infer::new_infer_ctxt(tcx); - let unboxed_closures = RefCell::new(DefIdMap::new()); - let vcx = VtableContext { - infcx: infcx, - param_env: ¶m_env, - unboxed_closures: &unboxed_closures, - }; - - // Resolve the vtables for the trait reference on the impl. This - // serves many purposes, best explained by example. Imagine we have: - // - // trait A : C { fn x(&self) { ... } } - // - // and - // - // impl A for uint { ... } - // - // In that case, the trait ref will be `A for uint`. Resolving - // this will first check that the various types meet their requirements: - // - // 1. Because of T:B, int must implement the trait B - // 2. Because of the supertrait C, uint must implement the trait C. - // - // Simultaneously, the result of this resolution (`vtbls`), is precisely - // the set of vtable information needed to compile the default method - // `x()` adapted to the impl. (After all, a default method is basically - // the same as: - // - // fn default_x(...) { .. .}) - - let trait_def = ty::lookup_trait_def(tcx, impl_trait_ref.def_id); - let vtbls = lookup_vtables(&vcx, - impl_item.span, - &trait_def.generics.types, - &impl_trait_ref.substs, - false); - - infcx.resolve_regions_and_report_errors(); - - let vtbls = writeback::resolve_impl_res(infcx, impl_item.span, &vtbls); - let impl_def_id = ast_util::local_def(impl_item.id); - - debug!("impl_vtables for {} are {}", - impl_def_id.repr(tcx), - vtbls.repr(tcx)); - - tcx.impl_vtables.borrow_mut().insert(impl_def_id, vtbls); -} - -/// Resolve vtables for a method call after typeck has finished. -/// Used by trans to monomorphize artificial method callees (e.g. drop). -pub fn trans_resolve_method(tcx: &ty::ctxt, id: ast::NodeId, - substs: &subst::Substs) -> vtable_res { - let generics = ty::lookup_item_type(tcx, ast_util::local_def(id)).generics; - let unboxed_closures = RefCell::new(DefIdMap::new()); - let vcx = VtableContext { - infcx: &infer::new_infer_ctxt(tcx), - param_env: &ty::construct_parameter_environment(tcx, &ty::Generics::empty(), id), - unboxed_closures: &unboxed_closures, - }; - - lookup_vtables(&vcx, - tcx.map.span(id), - &generics.types, - substs, - false) -} - -impl<'a, 'b, 'tcx, 'v> Visitor<'v> for &'a FnCtxt<'b, 'tcx> { - fn visit_expr(&mut self, ex: &ast::Expr) { - early_resolve_expr(ex, *self, false); - visit::walk_expr(self, ex); - } - fn visit_item(&mut self, _: &ast::Item) { - // no-op - } -} - -// Detect points where a trait-bounded type parameter is -// instantiated, resolve the impls for the parameters. -pub fn resolve_in_block(mut fcx: &FnCtxt, bl: &ast::Block) { - visit::walk_block(&mut fcx, bl); -} - -/// Used in the kind checker after typechecking has finished. Calls -/// `any_missing` if any bounds were missing. -pub fn check_param_bounds(tcx: &ty::ctxt, - span: Span, - parameter_environment: &ty::ParameterEnvironment, - type_param_defs: - &VecPerParamSpace, - substs: &subst::Substs, - any_missing: |&ty::TraitRef|) { - let unboxed_closures = RefCell::new(DefIdMap::new()); - let vcx = VtableContext { - infcx: &infer::new_infer_ctxt(tcx), - param_env: parameter_environment, - unboxed_closures: &unboxed_closures, - }; - let vtable_param_results = - lookup_vtables(&vcx, span, type_param_defs, substs, false); - for (vtable_param_result, type_param_def) in - vtable_param_results.iter().zip(type_param_defs.iter()) { - for (vtable_result, trait_ref) in - vtable_param_result.iter() - .zip(type_param_def.bounds - .trait_bounds - .iter()) { - match *vtable_result { - vtable_error => any_missing(&**trait_ref), - vtable_static(..) | - vtable_param(..) | - vtable_unboxed_closure(..) => {} - } - } - } -} - diff --git a/src/librustc/middle/typeck/check/vtable2.rs b/src/librustc/middle/typeck/check/vtable2.rs new file mode 100644 index 0000000000000..f75d2622fdb89 --- /dev/null +++ b/src/librustc/middle/typeck/check/vtable2.rs @@ -0,0 +1,407 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use middle::subst::{SelfSpace}; +use middle::traits; +use middle::traits::{SelectionError, Overflow, + OutputTypeParameterMismatch, Unimplemented}; +use middle::traits::{Obligation, obligation_for_builtin_bound}; +use middle::traits::{FulfillmentError, Ambiguity}; +use middle::traits::{ObligationCause}; +use middle::ty; +use middle::typeck::check::{FnCtxt, + structurally_resolved_type}; +use middle::typeck::infer; +use std::rc::Rc; +use syntax::ast; +use syntax::codemap::Span; +use util::ppaux::UserString; +use util::ppaux::Repr; + +/// When reporting an error about a failed trait obligation, it's nice +/// to include some context indicating why we were checking that +/// obligation in the first place. The span is often enough but +/// sometimes it's not. Currently this enum is a bit of a hack and I +/// suspect it should be carried in the obligation or more deeply +/// integrated somehow. +pub enum ErrorReportingContext { + GenericContext, + ImplSupertraitCheck, +} + +pub fn check_object_cast(fcx: &FnCtxt, + cast_expr: &ast::Expr, + source_expr: &ast::Expr, + target_object_ty: ty::t) +{ + debug!("check_object_cast(cast_expr={}, target_object_ty={})", + cast_expr.repr(fcx.tcx()), + target_object_ty.repr(fcx.tcx())); + + // Look up vtables for the type we're casting to, + // passing in the source and target type. The source + // must be a pointer type suitable to the object sigil, + // e.g.: `&x as &Trait` or `box x as Box` + let source_ty = fcx.expr_ty(source_expr); + let source_ty = structurally_resolved_type(fcx, source_expr.span, source_ty); + debug!("source_ty={}", source_ty.repr(fcx.tcx())); + match (&ty::get(source_ty).sty, &ty::get(target_object_ty).sty) { + (&ty::ty_uniq(referent_ty), &ty::ty_uniq(object_trait_ty)) => { + let object_trait = object_trait(&object_trait_ty); + + // Ensure that if ~T is cast to ~Trait, then T : Trait + push_cast_obligation(fcx, cast_expr, object_trait, referent_ty); + } + + (&ty::ty_rptr(referent_region, ty::mt { ty: referent_ty, + mutbl: referent_mutbl }), + &ty::ty_rptr(target_region, ty::mt { ty: object_trait_ty, + mutbl: target_mutbl })) => + { + let object_trait = object_trait(&object_trait_ty); + if !mutability_allowed(referent_mutbl, target_mutbl) { + fcx.tcx().sess.span_err(source_expr.span, + "types differ in mutability"); + } else { + // Ensure that if &'a T is cast to &'b Trait, then T : Trait + push_cast_obligation(fcx, cast_expr, + object_trait, + referent_ty); + + // Ensure that if &'a T is cast to &'b Trait, then 'b <= 'a + infer::mk_subr(fcx.infcx(), + infer::RelateObjectBound(source_expr.span), + target_region, + referent_region); + } + } + + (_, &ty::ty_uniq(..)) => { + fcx.ccx.tcx.sess.span_err( + source_expr.span, + format!("can only cast an boxed pointer \ + to a boxed object, not a {}", + ty::ty_sort_string(fcx.tcx(), source_ty)).as_slice()); + } + + (_, &ty::ty_rptr(..)) => { + fcx.ccx.tcx.sess.span_err( + source_expr.span, + format!("can only cast a &-pointer \ + to an &-object, not a {}", + ty::ty_sort_string(fcx.tcx(), source_ty)).as_slice()); + } + + _ => { + fcx.tcx().sess.span_bug( + source_expr.span, + "expected object type"); + } + } + + // Because we currently give unsound lifetimes to the "ty_box", I + // could have written &'static ty::TyTrait here, but it seems + // gratuitously unsafe. + fn object_trait<'a>(t: &'a ty::t) -> &'a ty::TyTrait { + match ty::get(*t).sty { + ty::ty_trait(ref ty_trait) => &**ty_trait, + _ => fail!("expected ty_trait") + } + } + + fn mutability_allowed(a_mutbl: ast::Mutability, + b_mutbl: ast::Mutability) + -> bool { + a_mutbl == b_mutbl || + (a_mutbl == ast::MutMutable && b_mutbl == ast::MutImmutable) + } + + fn push_cast_obligation(fcx: &FnCtxt, + cast_expr: &ast::Expr, + object_trait: &ty::TyTrait, + referent_ty: ty::t) { + let object_trait_ref = + register_object_cast_obligations(fcx, + cast_expr.span, + object_trait, + referent_ty); + + // Finally record the object_trait_ref for use during trans + // (it would prob be better not to do this, but it's just kind + // of a pain to have to reconstruct it). + fcx.write_object_cast(cast_expr.id, object_trait_ref); + } +} + +pub fn register_object_cast_obligations(fcx: &FnCtxt, + span: Span, + object_trait: &ty::TyTrait, + referent_ty: ty::t) + -> Rc +{ + // This is just for better error reporting. Kinda goofy. The object type stuff + // needs some refactoring so there is a more convenient type to pass around. + let object_trait_ty = + ty::mk_trait(fcx.tcx(), + object_trait.def_id, + object_trait.substs.clone(), + object_trait.bounds); + + debug!("register_object_cast_obligations: referent_ty={} object_trait_ty={}", + referent_ty.repr(fcx.tcx()), + object_trait_ty.repr(fcx.tcx())); + + // Take the type parameters from the object type, but set + // the Self type (which is unknown, for the object type) + // to be the type we are casting from. + let mut object_substs = object_trait.substs.clone(); + assert!(object_substs.self_ty().is_none()); + object_substs.types.push(SelfSpace, referent_ty); + + // Create the obligation for casting from T to Trait. + let object_trait_ref = + Rc::new(ty::TraitRef { def_id: object_trait.def_id, + substs: object_substs }); + let object_obligation = + Obligation::new( + ObligationCause::new(span, + traits::ObjectCastObligation(object_trait_ty)), + object_trait_ref.clone()); + fcx.register_obligation(object_obligation); + + // Create additional obligations for all the various builtin + // bounds attached to the object cast. (In other words, if the + // object type is Foo+Send, this would create an obligation + // for the Send check.) + for builtin_bound in object_trait.bounds.builtin_bounds.iter() { + fcx.register_obligation( + obligation_for_builtin_bound( + fcx.tcx(), + ObligationCause::new(span, + traits::ObjectCastObligation(object_trait_ty)), + referent_ty, + builtin_bound)); + } + + object_trait_ref +} + +pub fn select_all_fcx_obligations_or_error(fcx: &FnCtxt) { + debug!("select_all_fcx_obligations_or_error"); + + let mut fulfillment_cx = fcx.inh.fulfillment_cx.borrow_mut(); + let r = + fulfillment_cx.select_all_or_error( + fcx.infcx(), + &fcx.inh.param_env, + &*fcx.inh.unboxed_closures.borrow()); + match r { + Ok(()) => { } + Err(errors) => { report_fulfillment_errors(fcx, &errors); } + } +} + +pub fn check_builtin_bound_obligations(fcx: &FnCtxt) { + /*! + * Hacky second pass to check builtin-bounds obligations *after* + * writeback occurs. + */ + + match + fcx.inh.fulfillment_cx.borrow() + .check_builtin_bound_obligations(fcx.infcx()) + { + Ok(()) => { } + Err(errors) => { report_fulfillment_errors(fcx, &errors); } + } +} + +fn resolve_trait_ref(fcx: &FnCtxt, obligation: &Obligation) + -> (ty::TraitRef, ty::t) +{ + let trait_ref = + fcx.infcx().resolve_type_vars_in_trait_ref_if_possible( + &*obligation.trait_ref); + let self_ty = + trait_ref.substs.self_ty().unwrap(); + (trait_ref, self_ty) +} + +pub fn report_fulfillment_errors(fcx: &FnCtxt, + errors: &Vec) { + for error in errors.iter() { + report_fulfillment_error(fcx, error); + } +} + +pub fn report_fulfillment_error(fcx: &FnCtxt, + error: &FulfillmentError) { + match error.code { + SelectionError(ref e) => { + report_selection_error(fcx, &error.obligation, e); + } + Ambiguity => { + maybe_report_ambiguity(fcx, &error.obligation); + } + } +} + +pub fn report_selection_error(fcx: &FnCtxt, + obligation: &Obligation, + error: &SelectionError) { + match *error { + Unimplemented => { + let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation); + if !ty::type_is_error(self_ty) { + fcx.tcx().sess.span_err( + obligation.cause.span, + format!( + "the trait `{}` is not implemented for the type `{}`", + trait_ref.user_string(fcx.tcx()), + self_ty.user_string(fcx.tcx())).as_slice()); + note_obligation_cause(fcx, obligation); + } + } + Overflow => { + report_overflow(fcx, obligation); + } + OutputTypeParameterMismatch(ref expected_trait_ref, ref e) => { + let expected_trait_ref = + fcx.infcx().resolve_type_vars_in_trait_ref_if_possible( + &**expected_trait_ref); + let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation); + if !ty::type_is_error(self_ty) { + fcx.tcx().sess.span_err( + obligation.cause.span, + format!( + "type mismatch: the type `{}` implements the trait `{}`, \ + but the trait `{}` is required ({})", + self_ty.user_string(fcx.tcx()), + expected_trait_ref.user_string(fcx.tcx()), + trait_ref.user_string(fcx.tcx()), + ty::type_err_to_str(fcx.tcx(), e)).as_slice()); + note_obligation_cause(fcx, obligation); + } + } + } +} + +pub fn report_overflow(fcx: &FnCtxt, obligation: &Obligation) { + let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation); + if ty::type_is_error(self_ty) { + fcx.tcx().sess.span_err( + obligation.cause.span, + format!( + "could not locate an impl of the trait `{}` for \ + the type `{}` due to overflow; possible cyclic \ + dependency between impls", + trait_ref.user_string(fcx.tcx()), + self_ty.user_string(fcx.tcx())).as_slice()); + note_obligation_cause(fcx, obligation); + } +} + +pub fn maybe_report_ambiguity(fcx: &FnCtxt, obligation: &Obligation) { + // Unable to successfully determine, probably means + // insufficient type information, but could mean + // ambiguous impls. The latter *ought* to be a + // coherence violation, so we don't report it here. + let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation); + debug!("maybe_report_ambiguity(trait_ref={}, self_ty={}, obligation={})", + trait_ref.repr(fcx.tcx()), + self_ty.repr(fcx.tcx()), + obligation.repr(fcx.tcx())); + if ty::type_is_error(self_ty) { + } else if ty::type_needs_infer(self_ty) { + fcx.tcx().sess.span_err( + obligation.cause.span, + format!( + "unable to infer enough type information to \ + locate the impl of the trait `{}` for \ + the type `{}`; type annotations required", + trait_ref.user_string(fcx.tcx()), + self_ty.user_string(fcx.tcx())).as_slice()); + note_obligation_cause(fcx, obligation); + } else if fcx.tcx().sess.err_count() == 0 { + // Ambiguity. Coherence should have reported an error. + fcx.tcx().sess.span_bug( + obligation.cause.span, + format!( + "coherence failed to report ambiguity: \ + cannot locate the impl of the trait `{}` for \ + the type `{}`", + trait_ref.user_string(fcx.tcx()), + self_ty.user_string(fcx.tcx())).as_slice()); + } +} + +pub fn select_fcx_obligations_where_possible(fcx: &FnCtxt) { + /*! Select as many obligations as we can at present. */ + + match + fcx.inh.fulfillment_cx + .borrow_mut() + .select_where_possible(fcx.infcx(), + &fcx.inh.param_env, + &*fcx.inh.unboxed_closures.borrow()) + { + Ok(()) => { } + Err(errors) => { report_fulfillment_errors(fcx, &errors); } + } +} + +fn note_obligation_cause(fcx: &FnCtxt, + obligation: &Obligation) { + let tcx = fcx.tcx(); + let trait_name = ty::item_path_str(tcx, obligation.trait_ref.def_id); + match obligation.cause.code { + traits::MiscObligation => { } + traits::ItemObligation(item_def_id) => { + let item_name = ty::item_path_str(tcx, item_def_id); + tcx.sess.span_note( + obligation.cause.span, + format!( + "the trait `{}` must be implemented because it is required by `{}`", + trait_name, + item_name).as_slice()); + } + traits::ObjectCastObligation(object_ty) => { + tcx.sess.span_note( + obligation.cause.span, + format!( + "the trait `{}` must be implemented for the cast \ + to the object type `{}`", + trait_name, + fcx.infcx().ty_to_string(object_ty)).as_slice()); + } + traits::RepeatVec => { + tcx.sess.span_note( + obligation.cause.span, + format!( + "the `Copy` trait is required because the \ + repeated element will be copied").as_slice()); + } + traits::VariableType(_) => { + tcx.sess.span_note( + obligation.cause.span, + "all local variables must have a statically known size"); + } + traits::AssignmentLhsSized => { + tcx.sess.span_note( + obligation.cause.span, + "the left-hand-side of an assignment must have a statically known size"); + } + traits::StructInitializerSized => { + tcx.sess.span_note( + obligation.cause.span, + "structs must have a statically known size to be initialized"); + } + } +} diff --git a/src/librustc/middle/typeck/check/wf.rs b/src/librustc/middle/typeck/check/wf.rs new file mode 100644 index 0000000000000..73c0a4e10fc2a --- /dev/null +++ b/src/librustc/middle/typeck/check/wf.rs @@ -0,0 +1,365 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use middle::subst::{Subst}; +use middle::traits; +use middle::ty; +use middle::ty_fold::{TypeFolder, TypeFoldable}; +use middle::typeck::astconv::AstConv; +use middle::typeck::check::{FnCtxt, Inherited, blank_fn_ctxt, vtable2, regionck}; +use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig; +use middle::typeck::CrateCtxt; +use util::ppaux::Repr; + +use std::collections::HashSet; +use syntax::ast; +use syntax::ast_util::{local_def}; +use syntax::codemap::Span; +use syntax::visit; +use syntax::visit::Visitor; + +pub struct CheckTypeWellFormedVisitor<'ccx, 'tcx:'ccx> { + ccx: &'ccx CrateCtxt<'ccx, 'tcx>, + cache: HashSet +} + +impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { + pub fn new(ccx: &'ccx CrateCtxt<'ccx, 'tcx>) -> CheckTypeWellFormedVisitor<'ccx, 'tcx> { + CheckTypeWellFormedVisitor { ccx: ccx, cache: HashSet::new() } + } + + fn check_item_well_formed(&mut self, ccx: &CrateCtxt, item: &ast::Item) { + /*! + * Checks that the field types (in a struct def'n) or + * argument types (in an enum def'n) are well-formed, + * meaning that they do not require any constraints not + * declared in the struct definition itself. + * For example, this definition would be illegal: + * + * struct Ref<'a, T> { x: &'a T } + * + * because the type did not declare that `T:'a`. + * + * We do this check as a pre-pass before checking fn bodies + * because if these constraints are not included it frequently + * leads to confusing errors in fn bodies. So it's better to check + * the types first. + */ + + debug!("check_item_well_formed(it.id={}, it.ident={})", + item.id, + ty::item_path_str(ccx.tcx, local_def(item.id))); + + let ccx = self.ccx; + match item.node { + ast::ItemImpl(..) => { + self.check_impl(item); + } + ast::ItemFn(..) => { + self.check_item_type(item); + } + ast::ItemStatic(..) => { + self.check_item_type(item); + } + ast::ItemStruct(..) => { + self.check_type_defn(item, |fcx| { + ty::struct_fields(ccx.tcx, local_def(item.id), + &fcx.inh.param_env.free_substs) + .iter() + .map(|f| f.mt.ty) + .collect() + }); + } + ast::ItemEnum(..) => { + self.check_type_defn(item, |fcx| { + ty::substd_enum_variants(ccx.tcx, local_def(item.id), + &fcx.inh.param_env.free_substs) + .iter() + .flat_map(|variant| { + variant.args + .iter() + .map(|&arg_ty| arg_ty) + }) + .collect() + }); + } + _ => {} + } + } + + fn with_fcx(&mut self, + ccx: &CrateCtxt, + item: &ast::Item, + f: |&mut CheckTypeWellFormedVisitor, &FnCtxt|) { + let item_def_id = local_def(item.id); + let polytype = ty::lookup_item_type(ccx.tcx, item_def_id); + let param_env = + ty::construct_parameter_environment(ccx.tcx, + item.span, + &polytype.generics, + item.id); + let inh = Inherited::new(ccx.tcx, param_env); + let fcx = blank_fn_ctxt(ccx, &inh, polytype.ty, item.id); + f(self, &fcx); + vtable2::select_all_fcx_obligations_or_error(&fcx); + regionck::regionck_item(&fcx, item); + vtable2::check_builtin_bound_obligations(&fcx); + } + + fn check_type_defn(&mut self, + item: &ast::Item, + lookup_fields: |&FnCtxt| -> Vec) + { + /*! + * In a type definition, we check that to ensure that the types of the fields are + * well-formed. + */ + + self.with_fcx(self.ccx, item, |this, fcx| { + let field_tys = lookup_fields(fcx); + let mut bounds_checker = BoundsChecker::new(fcx, item.span, + item.id, Some(&mut this.cache)); + for &ty in field_tys.iter() { + // Regions are checked below. + bounds_checker.check_traits_in_ty(ty); + } + + regionck::regionck_ensure_component_tys_wf( + fcx, item.span, field_tys.as_slice()); + }); + } + + fn check_item_type(&mut self, + item: &ast::Item) + { + self.with_fcx(self.ccx, item, |this, fcx| { + let mut bounds_checker = BoundsChecker::new(fcx, item.span, + item.id, Some(&mut this.cache)); + let polytype = ty::lookup_item_type(fcx.tcx(), local_def(item.id)); + let item_ty = polytype.ty.subst(fcx.tcx(), &fcx.inh.param_env.free_substs); + bounds_checker.check_traits_in_ty(item_ty); + }); + } + + fn check_impl(&mut self, + item: &ast::Item) + { + self.with_fcx(self.ccx, item, |this, fcx| { + let mut bounds_checker = BoundsChecker::new(fcx, item.span, + item.id, Some(&mut this.cache)); + + let self_ty = ty::node_id_to_type(fcx.tcx(), item.id); + let self_ty = self_ty.subst(fcx.tcx(), &fcx.inh.param_env.free_substs); + + bounds_checker.check_traits_in_ty(self_ty); + + let trait_ref = match ty::impl_trait_ref(fcx.tcx(), local_def(item.id)) { + None => { return; } + Some(t) => { t } + }; + let trait_ref = (*trait_ref).subst(fcx.tcx(), &fcx.inh.param_env.free_substs); + + // We are stricter on the trait-ref in an impl than the + // self-type. In particular, we enforce region + // relationships. The reason for this is that (at least + // presently) "appyling" an impl does not require that the + // application site check the well-formedness constraints on the + // trait reference. Instead, this is done at the impl site. + // Arguably this is wrong and we should treat the trait-reference + // the same way as we treat the self-type. + bounds_checker.check_trait_ref(&trait_ref); + + let trait_def = ty::lookup_trait_def(fcx.tcx(), trait_ref.def_id); + + let cause = + traits::ObligationCause::new( + item.span, + traits::ItemObligation(trait_ref.def_id)); + + // Find the supertrait bounds. This will add `int:Bar`. + // + // FIXME -- This is a bit ill-factored. There is very similar + // code in traits::util::obligations_for_generics. + fcx.add_region_obligations_for_type_parameter(item.span, + ty::ParamTy::for_self(trait_ref.def_id), + &trait_def.bounds, + trait_ref.self_ty()); + for builtin_bound in trait_def.bounds.builtin_bounds.iter() { + fcx.register_obligation( + traits::obligation_for_builtin_bound(fcx.tcx(), + cause, + trait_ref.self_ty(), + builtin_bound)); + } + for trait_bound in trait_def.bounds.trait_bounds.iter() { + let trait_bound = trait_bound.subst(fcx.tcx(), &trait_ref.substs); + fcx.register_obligation( + traits::Obligation::new(cause, trait_bound)); + } + }); + } +} + +impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> { + fn visit_item(&mut self, i: &'v ast::Item) { + self.check_item_well_formed(self.ccx, i); + visit::walk_item(self, i); + } +} + +pub struct BoundsChecker<'cx,'tcx:'cx> { + fcx: &'cx FnCtxt<'cx,'tcx>, + span: Span, + scope_id: ast::NodeId, + binding_count: uint, + cache: Option<&'cx mut HashSet>, +} + +impl<'cx,'tcx> BoundsChecker<'cx,'tcx> { + pub fn new(fcx: &'cx FnCtxt<'cx,'tcx>, + span: Span, + scope_id: ast::NodeId, + cache: Option<&'cx mut HashSet>) + -> BoundsChecker<'cx,'tcx> { + BoundsChecker { fcx: fcx, span: span, scope_id: scope_id, + cache: cache, binding_count: 0 } + } + + pub fn check_trait_ref(&mut self, trait_ref: &ty::TraitRef) { + /*! + * Given a trait ref like `A : Trait`, where `Trait` is + * defined as (say): + * + * trait Trait : Copy { ... } + * + * This routine will check that `B : OtherTrait` and `A : + * Trait`. It will also recursively check that the types + * `A` and `B` are well-formed. + * + * Note that it does not (currently, at least) + * check that `A : Copy` (that check is delegated to the point + * where impl `A : Trait` is implemented). + */ + + let trait_def = ty::lookup_trait_def(self.fcx.tcx(), trait_ref.def_id); + + self.fcx.add_obligations_for_parameters( + traits::ObligationCause::new( + self.span, + traits::ItemObligation(trait_ref.def_id)), + &trait_ref.substs, + &trait_def.generics); + + for &ty in trait_ref.substs.types.iter() { + self.check_traits_in_ty(ty); + } + } + + pub fn check_ty(&mut self, ty: ty::t) { + ty.fold_with(self); + } + + fn check_traits_in_ty(&mut self, ty: ty::t) { + // When checking types outside of a type def'n, we ignore + // region obligations. See discussion below in fold_ty(). + self.binding_count += 1; + ty.fold_with(self); + self.binding_count -= 1; + } +} + +impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> { + fn tcx(&self) -> &ty::ctxt<'tcx> { + self.fcx.tcx() + } + + fn fold_ty(&mut self, t: ty::t) -> ty::t { + debug!("BoundsChecker t={}", + t.repr(self.tcx())); + + match self.cache { + Some(ref mut cache) => { + if !cache.insert(t) { + // Already checked this type! Don't check again. + debug!("cached"); + return t; + } + } + None => { } + } + + match ty::get(t).sty{ + ty::ty_struct(type_id, ref substs) | + ty::ty_enum(type_id, ref substs) => { + let polytype = ty::lookup_item_type(self.fcx.tcx(), type_id); + + if self.binding_count == 0 { + self.fcx.add_obligations_for_parameters( + traits::ObligationCause::new(self.span, + traits::ItemObligation(type_id)), + substs, + &polytype.generics); + } else { + // There are two circumstances in which we ignore + // region obligations. + // + // The first is when we are inside of a closure + // type. This is because in that case the region + // obligations for the parameter types are things + // that the closure body gets to assume and the + // caller must prove at the time of call. In other + // words, if there is a type like `<'a, 'b> | &'a + // &'b int |`, it is well-formed, and caller will + // have to show that `'b : 'a` at the time of + // call. + // + // The second is when we are checking for + // well-formedness outside of a type def'n or fn + // body. This is for a similar reason: in general, + // we only do WF checking for regions in the + // result of expressions and type definitions, so + // to as allow for implicit where clauses. + // + // (I believe we should do the same for traits, but + // that will require an RFC. -nmatsakis) + self.fcx.add_trait_obligations_for_generics( + traits::ObligationCause::new(self.span, + traits::ItemObligation(type_id)), + substs, + &polytype.generics); + } + + self.fold_substs(substs); + } + ty::ty_bare_fn(ty::BareFnTy{sig: ref fn_sig, ..}) | + ty::ty_closure(box ty::ClosureTy{sig: ref fn_sig, ..}) => { + self.binding_count += 1; + + let (_, fn_sig) = + replace_late_bound_regions_in_fn_sig( + self.fcx.tcx(), fn_sig, + |br| ty::ReFree(ty::FreeRegion{scope_id: self.scope_id, + bound_region: br})); + + debug!("late-bound regions replaced: {}", + fn_sig.repr(self.tcx())); + + self.fold_sig(&fn_sig); + + self.binding_count -= 1; + } + ref sty => { + self.fold_sty(sty); + } + } + + t // we're not folding to produce a new type, so just return `t` here + } +} diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs index 4716ffe700b50..ffe019b314a87 100644 --- a/src/librustc/middle/typeck/check/writeback.rs +++ b/src/librustc/middle/typeck/check/writeback.rs @@ -44,6 +44,7 @@ pub fn resolve_type_vars_in_expr(fcx: &FnCtxt, e: &ast::Expr) { wbcx.visit_expr(e); wbcx.visit_upvar_borrow_map(); wbcx.visit_unboxed_closures(); + wbcx.visit_object_cast_map(); } pub fn resolve_type_vars_in_fn(fcx: &FnCtxt, @@ -63,6 +64,7 @@ pub fn resolve_type_vars_in_fn(fcx: &FnCtxt, } wbcx.visit_upvar_borrow_map(); wbcx.visit_unboxed_closures(); + wbcx.visit_object_cast_map(); } pub fn resolve_impl_res(infcx: &infer::InferCtxt, @@ -128,8 +130,6 @@ impl<'cx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'tcx> { self.visit_node_id(ResolvingExpr(e.span), e.id); self.visit_method_map_entry(ResolvingExpr(e.span), MethodCall::expr(e.id)); - self.visit_vtable_map_entry(ResolvingExpr(e.span), - MethodCall::expr(e.id)); match e.node { ast::ExprFnBlock(_, ref decl, _) | @@ -235,6 +235,27 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } + fn visit_object_cast_map(&self) { + if self.fcx.writeback_errors.get() { + return + } + + for (&node_id, trait_ref) in self.fcx + .inh + .object_cast_map + .borrow() + .iter() + { + let span = ty::expr_span(self.tcx(), node_id); + let reason = ResolvingExpr(span); + let closure_ty = self.resolve(trait_ref, reason); + self.tcx() + .object_cast_map + .borrow_mut() + .insert(node_id, closure_ty); + } + } + fn visit_node_id(&self, reason: ResolveReason, id: ast::NodeId) { // Resolve any borrowings for the node with id `id` self.visit_adjustments(reason, id); @@ -284,13 +305,11 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { for autoderef in range(0, adj.autoderefs) { let method_call = MethodCall::autoderef(id, autoderef); self.visit_method_map_entry(reason, method_call); - self.visit_vtable_map_entry(reason, method_call); } if adj_object { let method_call = MethodCall::autoobject(id); self.visit_method_map_entry(reason, method_call); - self.visit_vtable_map_entry(reason, method_call); } ty::AutoDerefRef(ty::AutoDerefRef { @@ -329,22 +348,6 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } - fn visit_vtable_map_entry(&self, - reason: ResolveReason, - vtable_key: MethodCall) { - // Resolve any vtable map entry - match self.fcx.inh.vtable_map.borrow_mut().pop(&vtable_key) { - Some(origins) => { - let r_origins = self.resolve(&origins, reason); - debug!("writeback::resolve_vtable_map_entry(\ - vtable_key={}, vtables={:?})", - vtable_key, r_origins.repr(self.tcx())); - self.tcx().vtable_map.borrow_mut().insert(vtable_key, r_origins); - } - None => {} - } - } - fn resolve(&self, t: &T, reason: ResolveReason) -> T { t.resolve_in(&mut Resolver::new(self.fcx, reason)) } @@ -504,3 +507,11 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> { } } } + +/////////////////////////////////////////////////////////////////////////// +// During type check, we store promises with the result of trait +// lookup rather than the actual results (because the results are not +// necessarily available immediately). These routines unwind the +// promises. It is expected that we will have already reported any +// errors that may be encountered, so if the promises store an error, +// a dummy result is returned. diff --git a/src/librustc/middle/typeck/infer/coercion.rs b/src/librustc/middle/typeck/infer/coercion.rs index c66d10138d8bb..e0a35dc72a39f 100644 --- a/src/librustc/middle/typeck/infer/coercion.rs +++ b/src/librustc/middle/typeck/infer/coercion.rs @@ -327,10 +327,14 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let sty_b = &ty::get(b).sty; match (sty_a, sty_b) { - (&ty::ty_rptr(_, ty::mt{ty: t_a, ..}), &ty::ty_rptr(_, mt_b)) => { + (&ty::ty_rptr(_, ty::mt{ty: t_a, mutbl: mutbl_a}), &ty::ty_rptr(_, mt_b)) => { self.unpack_actual_value(t_a, |sty_a| { - match self.unsize_ty(sty_a, mt_b.ty) { + match self.unsize_ty(t_a, sty_a, mt_b.ty) { Some((ty, kind)) => { + if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) { + return Err(ty::terr_mutability); + } + let coercion = Coercion(self.get_ref().trace.clone()); let r_borrow = self.get_ref().infcx.next_region_var(coercion); let ty = ty::mk_rptr(self.get_ref().infcx.tcx, @@ -349,10 +353,14 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } }) } - (&ty::ty_rptr(_, ty::mt{ty: t_a, ..}), &ty::ty_ptr(mt_b)) => { + (&ty::ty_rptr(_, ty::mt{ty: t_a, mutbl: mutbl_a}), &ty::ty_ptr(mt_b)) => { self.unpack_actual_value(t_a, |sty_a| { - match self.unsize_ty(sty_a, mt_b.ty) { + match self.unsize_ty(t_a, sty_a, mt_b.ty) { Some((ty, kind)) => { + if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) { + return Err(ty::terr_mutability); + } + let ty = ty::mk_ptr(self.get_ref().infcx.tcx, ty::mt{ty: ty, mutbl: mt_b.mutbl}); try!(self.get_ref().infcx.try(|| sub.tys(ty, b))); @@ -510,19 +518,23 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { a: ty::t, sty_a: &ty::sty, b: ty::t, + b_mutbl: ast::Mutability, mk_ty: |ty::t| -> ty::t, mk_adjust: || -> ty::AutoRef) -> CoerceResult { let tcx = self.get_ref().infcx.tcx; match *sty_a { - ty::ty_rptr(_, ty::mt{ty, ..}) => match ty::get(ty).sty { + ty::ty_rptr(_, ty::mt{ty, mutbl}) => match ty::get(ty).sty { ty::ty_trait(box ty::TyTrait { def_id, ref substs, bounds, .. - }) => { + }) => + { + debug!("mutbl={} b_mutbl={}", mutbl, b_mutbl); + let tr = ty::mk_trait(tcx, def_id, substs.clone(), bounds); try!(self.subtype(mk_ty(tr), b)); Ok(Some(AutoDerefRef(AutoDerefRef { @@ -624,3 +636,14 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { }))) } } + +fn can_coerce_mutbls(from_mutbl: ast::Mutability, + to_mutbl: ast::Mutability) + -> bool { + match (from_mutbl, to_mutbl) { + (ast::MutMutable, ast::MutMutable) => true, + (ast::MutImmutable, ast::MutImmutable) => true, + (ast::MutMutable, ast::MutImmutable) => true, + (ast::MutImmutable, ast::MutMutable) => false, + } +} From 5ba0196cb8eef04dced1f8374a57f6d617dfed04 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 12 Sep 2014 12:09:17 -0400 Subject: [PATCH 07/10] misc ppaux changes --- src/librustc/util/ppaux.rs | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index ba1f7ca2cb231..be4a1c95e5550 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -496,7 +496,13 @@ pub fn parameterized(cx: &ctxt, if cx.sess.verbose() { for t in substs.types.get_slice(subst::SelfSpace).iter() { - strs.push(format!("for {}", t.repr(cx))); + strs.push(format!("self {}", t.repr(cx))); + } + + // generally there shouldn't be any substs in the fn param + // space, but in verbose mode, print them out. + for t in substs.types.get_slice(subst::FnSpace).iter() { + strs.push(format!("fn {}", t.repr(cx))); } } @@ -539,15 +545,15 @@ impl Repr for () { } } -impl Repr for Rc { +impl<'a,T:Repr> Repr for &'a T { fn repr(&self, tcx: &ctxt) -> String { (&**self).repr(tcx) } } -impl<'a, T:Repr> Repr for &'a T { +impl Repr for Rc { fn repr(&self, tcx: &ctxt) -> String { - (*self).repr(tcx) + (&**self).repr(tcx) } } @@ -690,7 +696,11 @@ impl Repr for ty::ParamBounds { impl Repr for ty::TraitRef { fn repr(&self, tcx: &ctxt) -> String { - trait_ref_to_string(tcx, self) + let base = ty::item_path_str(tcx, self.def_id); + let trait_def = ty::lookup_trait_def(tcx, self.def_id); + format!("<{} as {}>", + self.substs.self_ty().repr(tcx), + parameterized(tcx, base.as_slice(), &self.substs, &trait_def.generics)) } } @@ -962,18 +972,16 @@ impl Repr for typeck::MethodOrigin { impl Repr for typeck::MethodParam { fn repr(&self, tcx: &ctxt) -> String { - format!("MethodParam({},{:?},{:?},{:?})", - self.trait_id.repr(tcx), - self.method_num, - self.param_num, - self.bound_num) + format!("MethodParam({},{})", + self.trait_ref.repr(tcx), + self.method_num) } } impl Repr for typeck::MethodObject { fn repr(&self, tcx: &ctxt) -> String { format!("MethodObject({},{:?},{:?})", - self.trait_id.repr(tcx), + self.trait_ref.repr(tcx), self.method_num, self.real_index) } @@ -1231,3 +1239,4 @@ impl Repr for (A,B) { format!("({},{})", a.repr(tcx), b.repr(tcx)) } } + From a2b95624fd094300e26b5b367b0ae95c27e3b2f2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 12 Sep 2014 12:09:54 -0400 Subject: [PATCH 08/10] add Send bound on impl because stricter trait checking requires it --- src/librustuv/access.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustuv/access.rs b/src/librustuv/access.rs index 664c942500732..b7475c8c077fc 100644 --- a/src/librustuv/access.rs +++ b/src/librustuv/access.rs @@ -136,7 +136,7 @@ impl<'a, T: Send> DerefMut for Guard<'a, T> { } #[unsafe_destructor] -impl<'a, T> Drop for Guard<'a, T> { +impl<'a, T:Send> Drop for Guard<'a, T> { fn drop(&mut self) { // This guard's homing missile is still armed, so we're guaranteed to be // on the same I/O event loop, so this unsafety should be ok. From 48bc291a80085978987d13f75b70b82b69ec9b4d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 12 Sep 2014 12:10:13 -0400 Subject: [PATCH 09/10] silence various warnings in stdlib, no idea why they suddenly started --- src/liballoc/heap.rs | 1 - src/libsync/comm/mod.rs | 12 ++++++------ src/libsync/deque.rs | 10 +++++----- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index c7bc1bb973330..0dc62e7363447 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -255,7 +255,6 @@ mod imp { #[cfg(not(jemalloc), unix)] mod imp { use core::cmp; - use core::mem; use core::ptr; use libc; use libc_heap; diff --git a/src/libsync/comm/mod.rs b/src/libsync/comm/mod.rs index c8b86c47c90b5..9177fa4a6b446 100644 --- a/src/libsync/comm/mod.rs +++ b/src/libsync/comm/mod.rs @@ -379,7 +379,7 @@ pub struct Receiver { inner: UnsafeCell>, receives: Cell, // can't share in an arc - marker: marker::NoSync, + _marker: marker::NoSync, } /// An iterator over messages on a receiver, this iterator will block @@ -397,7 +397,7 @@ pub struct Sender { inner: UnsafeCell>, sends: Cell, // can't share in an arc - marker: marker::NoSync, + _marker: marker::NoSync, } /// The sending-half of Rust's synchronous channel type. This half can only be @@ -406,7 +406,7 @@ pub struct Sender { pub struct SyncSender { inner: Arc>>, // can't share in an arc - marker: marker::NoSync, + _marker: marker::NoSync, } /// This enumeration is the list of the possible reasons that try_recv could not @@ -543,7 +543,7 @@ impl Sender { Sender { inner: UnsafeCell::new(inner), sends: Cell::new(0), - marker: marker::NoSync, + _marker: marker::NoSync, } } @@ -719,7 +719,7 @@ impl Drop for Sender { impl SyncSender { fn new(inner: Arc>>) -> SyncSender { - SyncSender { inner: inner, marker: marker::NoSync } + SyncSender { inner: inner, _marker: marker::NoSync } } /// Sends a value on this synchronous channel. @@ -807,7 +807,7 @@ impl Drop for SyncSender { impl Receiver { fn new(inner: Flavor) -> Receiver { - Receiver { inner: UnsafeCell::new(inner), receives: Cell::new(0), marker: marker::NoSync } + Receiver { inner: UnsafeCell::new(inner), receives: Cell::new(0), _marker: marker::NoSync } } /// Blocks waiting for a value on this receiver diff --git a/src/libsync/deque.rs b/src/libsync/deque.rs index e70a730dc3a13..521a7d0bd73d7 100644 --- a/src/libsync/deque.rs +++ b/src/libsync/deque.rs @@ -87,7 +87,7 @@ struct Deque { /// There may only be one worker per deque. pub struct Worker { deque: Arc>, - noshare: marker::NoSync, + _noshare: marker::NoSync, } /// The stealing half of the work-stealing deque. Stealers have access to the @@ -95,7 +95,7 @@ pub struct Worker { /// `steal` method. pub struct Stealer { deque: Arc>, - noshare: marker::NoSync, + _noshare: marker::NoSync, } /// When stealing some data, this is an enumeration of the possible outcomes. @@ -153,8 +153,8 @@ impl BufferPool { pub fn deque(&self) -> (Worker, Stealer) { let a = Arc::new(Deque::new(self.clone())); let b = a.clone(); - (Worker { deque: a, noshare: marker::NoSync }, - Stealer { deque: b, noshare: marker::NoSync }) + (Worker { deque: a, _noshare: marker::NoSync }, + Stealer { deque: b, _noshare: marker::NoSync }) } fn alloc(&mut self, bits: uint) -> Box> { @@ -217,7 +217,7 @@ impl Stealer { impl Clone for Stealer { fn clone(&self) -> Stealer { - Stealer { deque: self.deque.clone(), noshare: marker::NoSync } + Stealer { deque: self.deque.clone(), _noshare: marker::NoSync } } } From eafeb335a0731b4bfcd8be6203d0d29a3668cd76 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 15 Sep 2014 18:52:20 -0400 Subject: [PATCH 10/10] Update docs to include Sized trait, which is needed --- src/doc/guide-unsafe.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/doc/guide-unsafe.md b/src/doc/guide-unsafe.md index a95401682cf0d..8c67634d57aec 100644 --- a/src/doc/guide-unsafe.md +++ b/src/doc/guide-unsafe.md @@ -461,11 +461,12 @@ fn start(_argc: int, _argv: *const *const u8) -> int { 0 } -// These functions are invoked by the compiler, but not +// These functions and traits are used by the compiler, but not // for a bare-bones hello world. These are normally // provided by libstd. #[lang = "stack_exhausted"] extern fn stack_exhausted() {} #[lang = "eh_personality"] extern fn eh_personality() {} +#[lang = "sized"] trait Sized { } # // fn main() {} tricked you, rustdoc! ``` @@ -488,13 +489,14 @@ pub extern fn main(argc: int, argv: *const *const u8) -> int { #[lang = "stack_exhausted"] extern fn stack_exhausted() {} #[lang = "eh_personality"] extern fn eh_personality() {} +#[lang = "sized"] trait Sized { } # // fn main() {} tricked you, rustdoc! ``` The compiler currently makes a few assumptions about symbols which are available in the executable to call. Normally these functions are provided by the standard -library, but without it you must define your own. +xlibrary, but without it you must define your own. The first of these two functions, `stack_exhausted`, is invoked whenever stack overflow is detected. This function has a number of restrictions about how it @@ -508,6 +510,12 @@ mechanisms of the compiler. This is often mapped to GCC's personality function information), but crates which do not trigger failure can be assured that this function is never called. +The final item in the example is a trait called `Sized`. This a trait +that represents data of a known static size: it is integral to the +Rust type system, and so the compiler expects the standard library to +provide it. Since you are not using the standard library, you have to +provide it yourself. + ## Using libcore > **Note**: the core library's structure is unstable, and it is recommended to @@ -686,6 +694,7 @@ fn main(argc: int, argv: *const *const u8) -> int { #[lang = "stack_exhausted"] extern fn stack_exhausted() {} #[lang = "eh_personality"] extern fn eh_personality() {} +#[lang = "sized"] trait Sized {} ``` Note the use of `abort`: the `exchange_malloc` lang item is assumed to