Change:
Attempting to compile with and yields the following ICE:
Reduced test case: Still ICEs with The ICE goes away if the on the is changed to a bare instead of a reference.
Slightly different test case: EDIT: Nevermind, it's the same but uses a closure instead of the more general .
I have bisected this issue to rust-lang/rust (from )
A workaround would be simply:
This doesn't help much if you need to call methods that are on the trait (which was on the original code).
cc me
This is blocking collect-rs from compiling.
This is interesting. The culprit is : it registers obligations from implementation's methods into an hybrid parameter environment which has trait's methods in it. In the example given in this issue, when the associate type is projected out, the implementation's method acquires an extra lifetime variable. The trait's method doesn't have it so the lifetime resolution fails in an ICE later on. I'm not sure how to fix that though.
This compiles so at first glance it looks like a viable workaround: But if one tries to really use as an , compiler panics on an assertion failure:
Getting this with some hashing code. will output something along the lines of: Start hash BYTES: [69, 84, 87, 87, 100, 57, 118, 102, 80, 97, 122, 56, 100, 116, 80, 82, 74, 78, 104, 116, 109, 51, 88, 54, 56, 98, 56, 97, 66, 119, 105, 116, 90, 114, 50, 83, 107, 99, 51, 52, 89, 121, 121, 112, 86, 116, 57, 66, 120, 87, 86, 112, 88, 55, 66, 49, 76, 90, 86, 48, 49, 53, 56, 53, 52, 48, 56, 56, 49, 53, 54, 48, 51] lyra2 finished: CfV9jehQVXsVnx6Vrg5f9VgHVkWeatbrFGxKVz2knfEc Starting argon thread 'certificate::tests::checkcertdiff' panicked at 'index out of bounds: the len is 0 but the index is 31',

Discussion:
Err(ty::terr_projection_name_mismatched( expected_found(self, a.item_name, b.item_name))) } else { <del> // Note that the trait refs for the projection must be // *equal*. This is because there is no inherent // relationship between `<T as Foo>::Bar` and `<U as // Foo>::Bar` that we can derive based on how `T` relates // to `U`. Issue #21726 contains further discussion and // in-depth examples. let trait_ref = try!(self.equate().trait_refs(&*a.trait_ref, &*b.trait_ref)); </del> <ins> let trait_ref = try!(self.trait_refs(&*a.trait_ref, &*b.trait_ref)); </ins> Ok(ty::ProjectionTy { trait_ref: Rc::new(trait_ref), item_name: a.item_name }) } }

b_def_id: ast::DefId) -> bool { <ins> debug!("overlap(a_def_id={}, b_def_id={})", a_def_id.repr(selcx.tcx()), b_def_id.repr(selcx.tcx())); </ins> let (a_trait_ref, a_obligations) = impl_trait_ref_and_oblig(selcx, a_def_id); let (b_trait_ref, b_obligations) = impl_trait_ref_and_oblig(selcx, b_def_id); <ins> debug!("overlap: a_trait_ref={}", a_trait_ref.repr(selcx.tcx())); debug!("overlap: b_trait_ref={}", b_trait_ref.repr(selcx.tcx())); </ins> // Does `a <: b` hold? If not, no overlap. if let Err(_) = infer::mk_sub_poly_trait_refs(selcx.infcx(), true,

return false; } <ins> debug!("overlap: subtraitref check succeeded"); </ins> // Are any of the obligations unsatisfiable? If so, no overlap. <del> a_obligations.iter() .chain(b_obligations.iter()) .all(|o| selcx.evaluate_obligation(o)) </del> <ins> let opt_failing_obligation = a_obligations.iter() .chain(b_obligations.iter()) .find(|o| !selcx.evaluate_obligation(o)); if let Some(failing_obligation) = opt_failing_obligation { debug!("overlap: obligation unsatisfiable {}", failing_obligation.repr(selcx.tcx())); return false; } true </ins> } /// Instantiate fresh variables for all bound parameters of the impl

use middle::subst; use middle::ty::{self, HasProjectionTypes, Ty}; use middle::ty_fold::TypeFoldable; <del> use middle::infer::{self, InferCtxt}; </del> <ins> use middle::infer::{self, fixup_err_to_string, InferCtxt}; </ins> use std::slice::Iter; use std::rc::Rc; use syntax::ast;

} } <ins> /// Normalizes the parameter environment, reporting errors if they occur. </ins> pub fn normalize_param_env_or_error<'a,'tcx>(unnormalized_env: ty::ParameterEnvironment<'a,'tcx>, cause: ObligationCause<'tcx>) -> ty::ParameterEnvironment<'a,'tcx> { <del> match normalize_param_env(&unnormalized_env, cause) { Ok(p) => p, </del> <ins> // I'm not wild about reporting errors here; I'd prefer to // have the errors get reported at a defined place (e.g., // during typeck). Instead I have all parameter // environments, in effect, going through this function // and hence potentially reporting errors. This ensurse of // course that we never forget to normalize (the // alternative seemed like it would involve a lot of // manual invocations of this fn -- and then we'd have to // deal with the errors at each of those sites). // // In any case, in practice, typeck constructs all the // parameter environments once for every fn as it goes, // and errors will get reported then; so after typeck we // can be sure that no errors should occur. let tcx = unnormalized_env.tcx; let span = cause.span; let body_id = cause.body_id; debug!("normalize_param_env_or_error(unnormalized_env={})", unnormalized_env.repr(tcx)); let infcx = infer::new_infer_ctxt(tcx); let predicates = match fully_normalize(&infcx, &unnormalized_env, cause, &unnormalized_env.caller_bounds) { Ok(predicates) => predicates, </ins> Err(errors) => { <del> // I'm not wild about reporting errors here; I'd prefer to // have the errors get reported at a defined place (e.g., // during typeck). Instead I have all parameter // environments, in effect, going through this function // and hence potentially reporting errors. This ensurse of // course that we never forget to normalize (the // alternative seemed like it would involve a lot of // manual invocations of this fn -- and then we'd have to // deal with the errors at each of those sites). // // In any case, in practice, typeck constructs all the // parameter environments once for every fn as it goes, // and errors will get reported then; so after typeck we // can be sure that no errors should occur. let infcx = infer::new_infer_ctxt(unnormalized_env.tcx); </del> report_fulfillment_errors(&infcx, &errors); <del> // Normalized failed? use what they gave us, it's better than nothing. unnormalized_env </del> <ins> return unnormalized_env; // an unnormalized env is better than nothing </ins> } <del> } } pub fn normalize_param_env<'a,'tcx>(param_env: &ty::ParameterEnvironment<'a,'tcx>, cause: ObligationCause<'tcx>) -> Result<ty::ParameterEnvironment<'a,'tcx>, Vec<FulfillmentError<'tcx>>> { let tcx = param_env.tcx; debug!("normalize_param_env(param_env={})", param_env.repr(tcx)); </del> <ins> }; </ins> <del> let infcx = infer::new_infer_ctxt(tcx); let predicates = try!(fully_normalize(&infcx, param_env, cause, &param_env.caller_bounds)); </del> <ins> infcx.resolve_regions_and_report_errors(body_id); let predicates = match infcx.fully_resolve(&predicates) { Ok(predicates) => predicates, Err(fixup_err) => { // If we encounter a fixup error, it means that some type // variable wound up unconstrained. I actually don't know // if this can happen, and I certainly don't expect it to // happen often, but if it did happen it probably // represents a legitimate failure due to some kind of // unconstrained variable, and it seems better not to ICE, // all things considered. let err_msg = fixup_err_to_string(fixup_err); tcx.sess.span_err(span, &err_msg); return unnormalized_env; // an unnormalized env is better than nothing } }; </ins> <del> debug!("normalize_param_env: predicates={}", </del> <ins> debug!("normalize_param_env_or_error: predicates={}", </ins> predicates.repr(tcx)); <del> Ok(param_env.with_caller_bounds(predicates)) </del> <ins> unnormalized_env.with_caller_bounds(predicates) </ins> } pub fn fully_normalize<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,

{ let tcx = closure_typer.tcx(); <del> debug!("normalize_param_env(value={})", value.repr(tcx)); </del> <ins> debug!("normalize_param_env(value={})", value.repr(tcx)); </ins> let mut selcx = &mut SelectionContext::new(infcx, closure_typer); let mut fulfill_cx = FulfillmentContext::new();

} try!(fulfill_cx.select_all_or_error(infcx, closure_typer)); let resolved_value = infcx.resolve_type_vars_if_possible(&normalized_value); <del> debug!("normalize_param_env: resolved_value={}", resolved_value.repr(tcx)); </del> <ins> debug!("normalize_param_env: resolved_value={}", resolved_value.repr(tcx)); </ins> Ok(resolved_value) }

//! failure, but rather because the target type `Foo<Y>` is itself just //! not well-formed. Basically we get to assume well-formedness of all //! types involved before considering variance. <ins> //! //! ### Associated types //! //! Any trait with an associated type is invariant with respect to all //! of its inputs. To see why this makes sense, consider what //! subtyping for a trait reference means: //! //!    <T as Trait> <: <U as Trait> //! //! means that if I know that `T as Trait`, //! I also know that `U as //! Trait`. Moreover, if you think of it as //! dictionary passing style, it means that //! a dictionary for `<T as Trait>` is safe //! to use where a dictionary for `<U as //! Trait>` is expected. //! //! The problem is that when you can //! project types out from `<T as Trait>`, //! the relationship to types projected out //! of `<U as Trait>` is completely unknown //! unless `T==U` (see #21726 for more //! details). Making `Trait` invariant //! ensures that this is true. //! //! *Historical note: we used to preserve this invariant another way, //! by tweaking the subtyping rules and requiring that when a type `T` //! appeared as part of a projection, that was considered an invariant //! location, but this version does away with the need for those //! somewhat "special-case-feeling" rules.* //! //! Another related reason is that if we didn't make traits with //! associated types invariant, then projection is no longer a //! function with a single result. Consider: //! //! ``` //! trait Identity { type Out; fn foo(&self); } //! impl<T> Identity for T { type Out = T; ... } //! ``` //! //! Now if I have `<&'static () as Identity>::Out`, this can be //! validly derived as `&'a ()` for any `'a`: //! //!    <&'a () as Identity> <: <&'static () as Identity> //!    if &'static () < : &'a ()   -- Identity is contravariant in Self //!    if 'static : 'a             -- Subtyping rules for relations //! //! This change otoh means that `<'static () as Identity>::Out` is //! always `&'static ()` (which might then be upcast to `'a ()`, //! separately). This was helpful in solving #21750. </ins> use self::VarianceTerm::*; use self::ParamKind::*;

&method.fty.sig, self.covariant); } <del> ty::TypeTraitItem(_) => {} </del> <ins> ty::TypeTraitItem(ref data) => { // Any trait with an associated type is // invariant with respect to all of its // inputs. See length discussion in the comment // on this module. let projection_ty = ty::mk_projection(tcx, trait_def.trait_ref.clone(), data.name); self.add_constraints_from_ty(&trait_def.generics, projection_ty, self.invariant); } </ins> } } }

trait_def.generics.types.as_slice(), trait_def.generics.regions.as_slice(), trait_ref.substs, <del> self.invariant); </del> <ins> variance); </ins> } ty::ty_trait(ref data) => {