Do not ICE when projecting out of a value with type `ty::ty_err`

This commit is contained in:
Niko Matsakis 2015-01-02 04:20:34 -05:00 committed by Jorge Aparicio
parent 64b7c22c46
commit cddb41dd1f
3 changed files with 66 additions and 15 deletions

View File

@ -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<ty::TraitRef<'tcx>>,
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<ty::TraitRef<'tcx>>,
candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
env_predicates: Vec<ty::Predicate<'tcx>>)
{
@ -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<ty::TraitRef<'tcx>>,
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<ty::TraitRef<'tcx>>,
candidate_set: &mut ProjectionTyCandidateSet<'tcx>)
-> Result<(), SelectionError<'tcx>>
{
// If we are resolving `<T as TraitRef<...>>::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) => {

View File

@ -7269,7 +7269,7 @@ impl<T:ReferencesError> ReferencesError for Binder<T> {
impl<T:ReferencesError> ReferencesError for Rc<T> {
fn references_error(&self) -> bool {
(&*self).references_error()
(&**self).references_error()
}
}

View File

@ -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 <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 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<RHS=Self> {
type Output;
fn add(self, RHS) -> Self::Output;
}
fn ice<A>(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
}