about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2015-01-02 04:20:34 -0500
committerJorge Aparicio <japaricious@gmail.com>2015-01-02 12:20:29 -0500
commitcddb41dd1fd7ace99fbc653b8aca48a0feba9c48 (patch)
treedfcd83a8c79f3678e36cfd30c724bf4700e5f68a /src
parent64b7c22c46b204520a6fae1c5cd750a3d3c6a66a (diff)
downloadrust-cddb41dd1fd7ace99fbc653b8aca48a0feba9c48.tar.gz
rust-cddb41dd1fd7ace99fbc653b8aca48a0feba9c48.zip
Do not ICE when projecting out of a value with type `ty::ty_err`
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/traits/project.rs45
-rw-r--r--src/librustc/middle/ty.rs2
-rw-r--r--src/test/compile-fail/associated-types-ICE-when-projecting-out-of-err.rs34
3 files changed, 66 insertions, 15 deletions
diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs
index c84f31bf6c3..125f39b1a43 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<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) => {
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 7bc5d3d0708..399d537088c 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -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()
     }
 }
 
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 00000000000..5743216b6ca
--- /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 <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
+}