diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index c84f31bf6c3b..125f39b1a43e 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -21,8 +21,10 @@ use super::VtableImplData; use middle::infer; use middle::subst::Subst; -use middle::ty::{mod, AsPredicate, RegionEscape, HasProjectionTypes, ToPolyTraitRef, Ty}; +use middle::ty::{mod, AsPredicate, ReferencesError, RegionEscape, + HasProjectionTypes, ToPolyTraitRef, Ty}; use middle::ty_fold::{mod, TypeFoldable, TypeFolder}; +use std::rc::Rc; use util::ppaux::Repr; pub type PolyProjectionObligation<'tcx> = @@ -372,6 +374,15 @@ fn project_type<'cx,'tcx>( return Err(ProjectionTyError::TraitSelectionError(Overflow)); } + let obligation_trait_ref = + selcx.infcx().resolve_type_vars_if_possible(&obligation.predicate.trait_ref); + + debug!("project: obligation_trait_ref={}", obligation_trait_ref.repr(selcx.tcx())); + + if obligation_trait_ref.references_error() { + return Ok(ProjectedTy::Progress(selcx.tcx().types.err, vec!())); + } + let mut candidates = ProjectionTyCandidateSet { vec: Vec::new(), ambiguous: false, @@ -379,15 +390,18 @@ fn project_type<'cx,'tcx>( assemble_candidates_from_object_type(selcx, obligation, + &obligation_trait_ref, &mut candidates); if candidates.vec.is_empty() { assemble_candidates_from_param_env(selcx, obligation, + &obligation_trait_ref, &mut candidates); if let Err(e) = assemble_candidates_from_impls(selcx, obligation, + &obligation_trait_ref, &mut candidates) { return Err(ProjectionTyError::TraitSelectionError(e)); } @@ -421,17 +435,20 @@ fn project_type<'cx,'tcx>( /// there that can answer this question. fn assemble_candidates_from_param_env<'cx,'tcx>( selcx: &mut SelectionContext<'cx,'tcx>, - obligation: &ProjectionTyObligation<'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + obligation_trait_ref: &Rc>, candidate_set: &mut ProjectionTyCandidateSet<'tcx>) { let env_predicates = selcx.param_env().caller_bounds.predicates.clone(); let env_predicates = env_predicates.iter().cloned().collect(); - assemble_candidates_from_predicates(selcx, obligation, candidate_set, env_predicates); + assemble_candidates_from_predicates(selcx, obligation, obligation_trait_ref, + candidate_set, env_predicates); } fn assemble_candidates_from_predicates<'cx,'tcx>( selcx: &mut SelectionContext<'cx,'tcx>, - obligation: &ProjectionTyObligation<'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + obligation_trait_ref: &Rc>, candidate_set: &mut ProjectionTyCandidateSet<'tcx>, env_predicates: Vec>) { @@ -445,7 +462,7 @@ fn assemble_candidates_from_predicates<'cx,'tcx>( let is_match = infcx.probe(|_| { let origin = infer::Misc(obligation.cause.span); let obligation_poly_trait_ref = - obligation.predicate.trait_ref.to_poly_trait_ref(); + obligation_trait_ref.to_poly_trait_ref(); let data_poly_trait_ref = data.to_poly_trait_ref(); infcx.sub_poly_trait_refs(false, @@ -466,14 +483,14 @@ fn assemble_candidates_from_predicates<'cx,'tcx>( fn assemble_candidates_from_object_type<'cx,'tcx>( selcx: &mut SelectionContext<'cx,'tcx>, - obligation: &ProjectionTyObligation<'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + obligation_trait_ref: &Rc>, candidate_set: &mut ProjectionTyCandidateSet<'tcx>) { let infcx = selcx.infcx(); - let trait_ref = infcx.resolve_type_vars_if_possible(&obligation.predicate.trait_ref); debug!("assemble_candidates_from_object_type(trait_ref={})", - trait_ref.repr(infcx.tcx)); - let self_ty = trait_ref.self_ty(); + obligation_trait_ref.repr(infcx.tcx)); + let self_ty = obligation_trait_ref.self_ty(); let data = match self_ty.sty { ty::ty_trait(ref data) => data, _ => { return; } @@ -482,21 +499,21 @@ fn assemble_candidates_from_object_type<'cx,'tcx>( let env_predicates = projection_bounds.iter() .map(|p| p.as_predicate()) .collect(); - assemble_candidates_from_predicates(selcx, obligation, candidate_set, env_predicates) + assemble_candidates_from_predicates(selcx, obligation, obligation_trait_ref, + candidate_set, env_predicates) } fn assemble_candidates_from_impls<'cx,'tcx>( selcx: &mut SelectionContext<'cx,'tcx>, obligation: &ProjectionTyObligation<'tcx>, + obligation_trait_ref: &Rc>, candidate_set: &mut ProjectionTyCandidateSet<'tcx>) -> Result<(), SelectionError<'tcx>> { // If we are resolving `>::Item == Type`, // start out by selecting the predicate `T as TraitRef<...>`: - let trait_ref = - obligation.predicate.trait_ref.to_poly_trait_ref(); - let trait_obligation = - obligation.with(trait_ref.to_poly_trait_predicate()); + let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); + let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate()); let vtable = match selcx.select(&trait_obligation) { Ok(Some(vtable)) => vtable, Ok(None) => { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 7bc5d3d07089..399d537088c7 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -7269,7 +7269,7 @@ impl ReferencesError for Binder { impl ReferencesError for Rc { fn references_error(&self) -> bool { - (&*self).references_error() + (&**self).references_error() } } diff --git a/src/test/compile-fail/associated-types-ICE-when-projecting-out-of-err.rs b/src/test/compile-fail/associated-types-ICE-when-projecting-out-of-err.rs new file mode 100644 index 000000000000..5743216b6ca6 --- /dev/null +++ b/src/test/compile-fail/associated-types-ICE-when-projecting-out-of-err.rs @@ -0,0 +1,34 @@ +// 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 that we do not ICE when the self type is `ty::err`, but rather +// just propagate the error. + +#![crate_type = "lib"] +#![feature(associated_types, default_type_params, lang_items)] +#![no_std] + +#[lang="sized"] +pub trait Sized for Sized? { + // Empty. +} + +#[lang = "add"] +trait Add { + type Output; + + fn add(self, RHS) -> Self::Output; +} + +fn ice(a: A) { + let r = loop {}; + r = r + a; // here the type `r` is not yet inferred, hence `r+a` generates an error. + //~^ ERROR type of this value must be known +}