Change:
For example, this code does not compile: cc
I think this may be another instance of
Trusting analysis, closing in favor of but adding test case there as well.
(it of course would be good to confirm that this actually is an instance of -- my initial reaction when I saw it was "they might be related ... but wait, wasn't part of the opt-in-builtin-bounds work to be able to move the special case handling of / out into library code...?"; I've only done some rough skimming that makes me think the hypothesis remains plausible.)
Ah either way is fine by me, I personally like fewer issues :). We can reopen once is addressed one way or another if necessary (or if you'd like to reopen now that's also fine by me!)
oh that was really just a note to myself as much as anything else, not a comment on your choice to close this ticket. :)
I don't think this code uses type-contents. If it does, that is itself a bug! Either way, we should keep this open for the time being.
cc

Discussion:
} } <ins> fn collect_predicates_for_types(&mut self, obligation: &TraitObligation<'tcx>, trait_def_id: ast::DefId, types: Vec<Ty<'tcx>>) -> Vec<PredicateObligation<'tcx>> { let derived_cause = match self.tcx().lang_items.to_builtin_kind(trait_def_id) { Some(_) => { self.derived_cause(obligation, BuiltinDerivedObligation) }, None => { self.derived_cause(obligation, ImplDerivedObligation) } }; let normalized = project::normalize_with_depth(self, obligation.cause.clone(), obligation.recursion_depth + 1, &types); let obligations = normalized.value.iter().map(|&nested_ty| { // the obligation might be higher-ranked, e.g. for<'a> &'a // int : Copy. In that case, we will wind up with // late-bound regions in the `nested` vector. So for each // one we instantiate to a skolemized region, do our work // to produce something like `&'0 int : Copy`, and then // re-bind it. This is a bit of busy-work but preserves // the invariant that we only manipulate free regions, not // bound ones. self.infcx.try(|snapshot| { let (skol_ty, skol_map) = self.infcx().skolemize_late_bound_regions(&ty::Binder(nested_ty), snapshot); let skol_predicate = util::predicate_for_trait_def( self.tcx(), derived_cause.clone(), trait_def_id, obligation.recursion_depth + 1, skol_ty); match skol_predicate { Ok(skol_predicate) => Ok(self.infcx().plug_leaks(skol_map, snapshot, &skol_predicate)), Err(ErrorReported) => Err(ErrorReported) } }) }).collect::<Result<Vec<PredicateObligation<'tcx>>, _>>(); match obligations { Ok(mut obls) => { obls.push_all(normalized.obligations.as_slice()); obls }, Err(ErrorReported) => Vec::new() } } </ins> /////////////////////////////////////////////////////////////////////////// // CONFIRMATION //

nested: Vec<Ty<'tcx>>) -> VtableBuiltinData<PredicateObligation<'tcx>> { <del> let derived_cause = self.derived_cause(obligation, BuiltinDerivedObligation); let obligations = nested.iter().map(|&bound_ty| { // the obligation might be higher-ranked, e.g. for<'a> &'a // int : Copy. In that case, we will wind up with // late-bound regions in the `nested` vector. So for each // one we instantiate to a skolemized region, do our work // to produce something like `&'0 int : Copy`, and then // re-bind it. This is a bit of busy-work but preserves // the invariant that we only manipulate free regions, not // bound ones. self.infcx.try(|snapshot| { let (skol_ty, skol_map) = self.infcx().skolemize_late_bound_regions(&ty::Binder(bound_ty), snapshot); let skol_predicate = util::predicate_for_builtin_bound( self.tcx(), derived_cause.clone(), bound, obligation.recursion_depth + 1, skol_ty); match skol_predicate { Ok(skol_predicate) => Ok(self.infcx().plug_leaks(skol_map, snapshot, &skol_predicate)), Err(ErrorReported) => Err(ErrorReported) } }) }).collect::<Result<_, _>>(); let obligations = match obligations { Ok(o) => o, Err(ErrorReported) => Vec::new(), </del> <ins> let trait_def = match self.tcx().lang_items.from_builtin_kind(bound) { Ok(def_id) => def_id, Err(_) => { self.tcx().sess.bug("builtin trait definition not found"); } </ins> }; <ins> let obligations = self.collect_predicates_for_types(obligation, trait_def, nested); </ins> let obligations = VecPerParamSpace::new(obligations, Vec::new(), Vec::new()); debug!("vtable_builtin_data: obligations={}",

nested: Vec<Ty<'tcx>>) -> VtableDefaultImplData<PredicateObligation<'tcx>> { <del> let derived_cause = self.derived_cause(obligation, ImplDerivedObligation); let obligations = nested.iter().map(|&nested_ty| { // the obligation might be higher-ranked, e.g. for<'a> &'a // int : Copy. In that case, we will wind up with // late-bound regions in the `nested` vector. So for each // one we instantiate to a skolemized region, do our work // to produce something like `&'0 int : Copy`, and then // re-bind it. This is a bit of busy-work but preserves // the invariant that we only manipulate free regions, not // bound ones. self.infcx.try(|snapshot| { let (skol_ty, skol_map) = self.infcx().skolemize_late_bound_regions(&ty::Binder(nested_ty), snapshot); let skol_predicate = util::predicate_for_default_trait_impl( self.tcx(), derived_cause.clone(), trait_def_id, obligation.recursion_depth + 1, skol_ty); match skol_predicate { Ok(skol_predicate) => Ok(self.infcx().plug_leaks(skol_map, snapshot, &skol_predicate)), Err(ErrorReported) => Err(ErrorReported) } }) }).collect::<Result<_, _>>(); let mut obligations = match obligations { Ok(o) => o, Err(ErrorReported) => Vec::new() }; </del> <ins> let mut obligations = self.collect_predicates_for_types(obligation, trait_def_id, nested); </ins> let _: Result<(),()> = self.infcx.try(|snapshot| { let (_, skol_map) =

}) } <del> pub fn predicate_for_default_trait_impl<'tcx>( </del> <ins> pub fn predicate_for_trait_def<'tcx>( </ins> tcx: &ty::ctxt<'tcx>, cause: ObligationCause<'tcx>, trait_def_id: ast::DefId,

<ins> // Copyright 2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. // Test transitive analysis for associated types. Collected types // should be normalized and new obligations generated. use std::borrow::{ToOwned, Cow}; fn assert_send<T: Send>(_: T) {} fn main() { assert_send(Cow::Borrowed("foo")); } </ins>

<ins> // Copyright 2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. // Test transitive analysis for associated types. Collected types // should be normalized and new obligations generated. trait Foo { type A; fn foo(&self) {} } impl Foo for usize { type A = usize; } struct Bar<T: Foo> { inner: T::A } fn is_send<T: Send>() {} fn main() { is_send::<Bar<usize>>(); } </ins>