mirror of
https://github.com/rust-lang/rust.git
synced 2024-10-31 22:41:50 +00:00
auto merge of #20374 : nikomatsakis/rust/assoc-types, r=nikomatsakis
These mostly derive from problems that @japaric encountered. r? @pcwalton
This commit is contained in:
commit
7d4f4876d6
@ -1402,6 +1402,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
||||
}
|
||||
ty::TypeTraitItem(associated_type) => {
|
||||
encode_name(rbml_w, associated_type.name);
|
||||
encode_def_id(rbml_w, associated_type.def_id);
|
||||
|
||||
let elem = ast_map::PathName(associated_type.name);
|
||||
encode_path(rbml_w,
|
||||
|
@ -77,13 +77,7 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
"overflow evaluating the requirement `{}`",
|
||||
predicate.user_string(infcx.tcx)).as_slice());
|
||||
|
||||
let current_limit = infcx.tcx.sess.recursion_limit.get();
|
||||
let suggested_limit = current_limit * 2;
|
||||
infcx.tcx.sess.span_note(
|
||||
obligation.cause.span,
|
||||
format!(
|
||||
"consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
|
||||
suggested_limit)[]);
|
||||
suggest_new_overflow_limit(infcx, obligation.cause.span);
|
||||
|
||||
note_obligation_cause(infcx, obligation);
|
||||
}
|
||||
@ -165,73 +159,76 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
// ambiguous impls. The latter *ought* to be a
|
||||
// coherence violation, so we don't report it here.
|
||||
|
||||
let trait_ref = match obligation.predicate {
|
||||
ty::Predicate::Trait(ref trait_predicate) => {
|
||||
infcx.resolve_type_vars_if_possible(
|
||||
&trait_predicate.to_poly_trait_ref())
|
||||
}
|
||||
_ => {
|
||||
infcx.tcx.sess.span_bug(
|
||||
obligation.cause.span,
|
||||
format!("ambiguity from something other than a trait: {}",
|
||||
obligation.predicate.repr(infcx.tcx)).as_slice());
|
||||
}
|
||||
};
|
||||
let predicate = infcx.resolve_type_vars_if_possible(&obligation.predicate);
|
||||
|
||||
let self_ty = trait_ref.self_ty();
|
||||
|
||||
debug!("maybe_report_ambiguity(trait_ref={}, self_ty={}, obligation={})",
|
||||
trait_ref.repr(infcx.tcx),
|
||||
self_ty.repr(infcx.tcx),
|
||||
debug!("maybe_report_ambiguity(predicate={}, obligation={})",
|
||||
predicate.repr(infcx.tcx),
|
||||
obligation.repr(infcx.tcx));
|
||||
let all_types = &trait_ref.substs().types;
|
||||
if all_types.iter().any(|&t| ty::type_is_error(t)) {
|
||||
} else if all_types.iter().any(|&t| ty::type_needs_infer(t)) {
|
||||
// This is kind of a hack: it frequently happens that some earlier
|
||||
// error prevents types from being fully inferred, and then we get
|
||||
// a bunch of uninteresting errors saying something like "<generic
|
||||
// #0> doesn't implement Sized". It may even be true that we
|
||||
// could just skip over all checks where the self-ty is an
|
||||
// inference variable, but I was afraid that there might be an
|
||||
// inference variable created, registered as an obligation, and
|
||||
// then never forced by writeback, and hence by skipping here we'd
|
||||
// be ignoring the fact that we don't KNOW the type works
|
||||
// out. Though even that would probably be harmless, given that
|
||||
// we're only talking about builtin traits, which are known to be
|
||||
// inhabited. But in any case I just threw in this check for
|
||||
// has_errors() to be sure that compilation isn't happening
|
||||
// anyway. In that case, why inundate the user.
|
||||
if !infcx.tcx.sess.has_errors() {
|
||||
if infcx.tcx.lang_items.sized_trait()
|
||||
.map_or(false, |sized_id| sized_id == trait_ref.def_id()) {
|
||||
infcx.tcx.sess.span_err(
|
||||
|
||||
match predicate {
|
||||
ty::Predicate::Trait(ref data) => {
|
||||
let trait_ref = data.to_poly_trait_ref();
|
||||
let self_ty = trait_ref.self_ty();
|
||||
let all_types = &trait_ref.substs().types;
|
||||
if all_types.iter().any(|&t| ty::type_is_error(t)) {
|
||||
} else if all_types.iter().any(|&t| ty::type_needs_infer(t)) {
|
||||
// This is kind of a hack: it frequently happens that some earlier
|
||||
// error prevents types from being fully inferred, and then we get
|
||||
// a bunch of uninteresting errors saying something like "<generic
|
||||
// #0> doesn't implement Sized". It may even be true that we
|
||||
// could just skip over all checks where the self-ty is an
|
||||
// inference variable, but I was afraid that there might be an
|
||||
// inference variable created, registered as an obligation, and
|
||||
// then never forced by writeback, and hence by skipping here we'd
|
||||
// be ignoring the fact that we don't KNOW the type works
|
||||
// out. Though even that would probably be harmless, given that
|
||||
// we're only talking about builtin traits, which are known to be
|
||||
// inhabited. But in any case I just threw in this check for
|
||||
// has_errors() to be sure that compilation isn't happening
|
||||
// anyway. In that case, why inundate the user.
|
||||
if !infcx.tcx.sess.has_errors() {
|
||||
if
|
||||
infcx.tcx.lang_items.sized_trait()
|
||||
.map_or(false, |sized_id| sized_id == trait_ref.def_id())
|
||||
{
|
||||
infcx.tcx.sess.span_err(
|
||||
obligation.cause.span,
|
||||
format!(
|
||||
"unable to infer enough type information about `{}`; \
|
||||
type annotations required",
|
||||
self_ty.user_string(infcx.tcx)).as_slice());
|
||||
} else {
|
||||
infcx.tcx.sess.span_err(
|
||||
obligation.cause.span,
|
||||
format!(
|
||||
"type annotations required: cannot resolve `{}`",
|
||||
predicate.user_string(infcx.tcx)).as_slice());
|
||||
note_obligation_cause(infcx, obligation);
|
||||
}
|
||||
}
|
||||
} else if !infcx.tcx.sess.has_errors() {
|
||||
// Ambiguity. Coherence should have reported an error.
|
||||
infcx.tcx.sess.span_bug(
|
||||
obligation.cause.span,
|
||||
format!(
|
||||
"unable to infer enough type information about `{}`; type annotations \
|
||||
required",
|
||||
self_ty.user_string(infcx.tcx)).as_slice());
|
||||
} else {
|
||||
infcx.tcx.sess.span_err(
|
||||
obligation.cause.span,
|
||||
format!(
|
||||
"unable to infer enough type information to \
|
||||
locate the impl of the trait `{}` for \
|
||||
the type `{}`; type annotations required",
|
||||
"coherence failed to report ambiguity: \
|
||||
cannot locate the impl of the trait `{}` for \
|
||||
the type `{}`",
|
||||
trait_ref.user_string(infcx.tcx),
|
||||
self_ty.user_string(infcx.tcx)).as_slice());
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
if !infcx.tcx.sess.has_errors() {
|
||||
infcx.tcx.sess.span_err(
|
||||
obligation.cause.span,
|
||||
format!(
|
||||
"type annotations required: cannot resolve `{}`",
|
||||
predicate.user_string(infcx.tcx)).as_slice());
|
||||
note_obligation_cause(infcx, obligation);
|
||||
}
|
||||
}
|
||||
} else if !infcx.tcx.sess.has_errors() {
|
||||
// Ambiguity. Coherence should have reported an error.
|
||||
infcx.tcx.sess.span_bug(
|
||||
obligation.cause.span,
|
||||
format!(
|
||||
"coherence failed to report ambiguity: \
|
||||
cannot locate the impl of the trait `{}` for \
|
||||
the type `{}`",
|
||||
trait_ref.user_string(infcx.tcx),
|
||||
self_ty.user_string(infcx.tcx)).as_slice());
|
||||
}
|
||||
}
|
||||
|
||||
@ -335,3 +332,12 @@ fn note_obligation_cause_code<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn suggest_new_overflow_limit(infcx: &InferCtxt, span: Span) {
|
||||
let current_limit = infcx.tcx.sess.recursion_limit.get();
|
||||
let suggested_limit = current_limit * 2;
|
||||
infcx.tcx.sess.span_note(
|
||||
span,
|
||||
format!(
|
||||
"consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
|
||||
suggested_limit)[]);
|
||||
}
|
||||
|
@ -8,9 +8,9 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use middle::infer::{mod, InferCtxt};
|
||||
use middle::infer::{InferCtxt};
|
||||
use middle::mem_categorization::Typer;
|
||||
use middle::ty::{mod, AsPredicate, RegionEscape, Ty, ToPolyTraitRef};
|
||||
use middle::ty::{mod, RegionEscape, Ty};
|
||||
use std::collections::HashSet;
|
||||
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
||||
use std::default::Default;
|
||||
@ -23,7 +23,6 @@ use super::CodeAmbiguity;
|
||||
use super::CodeProjectionError;
|
||||
use super::CodeSelectionError;
|
||||
use super::FulfillmentError;
|
||||
use super::Obligation;
|
||||
use super::ObligationCause;
|
||||
use super::PredicateObligation;
|
||||
use super::project;
|
||||
@ -110,6 +109,8 @@ impl<'tcx> FulfillmentContext<'tcx> {
|
||||
/// `projection_ty` again.
|
||||
pub fn normalize_projection_type<'a>(&mut self,
|
||||
infcx: &InferCtxt<'a,'tcx>,
|
||||
param_env: &ty::ParameterEnvironment<'tcx>,
|
||||
typer: &Typer<'tcx>,
|
||||
projection_ty: ty::ProjectionTy<'tcx>,
|
||||
cause: ObligationCause<'tcx>)
|
||||
-> Ty<'tcx>
|
||||
@ -121,18 +122,16 @@ impl<'tcx> FulfillmentContext<'tcx> {
|
||||
|
||||
// FIXME(#20304) -- cache
|
||||
|
||||
let ty_var = infcx.next_ty_var();
|
||||
let projection =
|
||||
ty::Binder(ty::ProjectionPredicate {
|
||||
projection_ty: projection_ty,
|
||||
ty: ty_var
|
||||
});
|
||||
let obligation = Obligation::new(cause, projection.as_predicate());
|
||||
self.register_predicate(infcx, obligation);
|
||||
let mut selcx = SelectionContext::new(infcx, param_env, typer);
|
||||
let normalized = project::normalize_projection_type(&mut selcx, projection_ty, cause, 0);
|
||||
|
||||
debug!("normalize_associated_type: result={}", ty_var.repr(infcx.tcx));
|
||||
for obligation in normalized.obligations.into_iter() {
|
||||
self.register_predicate_obligation(infcx, obligation);
|
||||
}
|
||||
|
||||
ty_var
|
||||
debug!("normalize_associated_type: result={}", normalized.value.repr(infcx.tcx));
|
||||
|
||||
normalized.value
|
||||
}
|
||||
|
||||
pub fn register_builtin_bound<'a>(&mut self,
|
||||
@ -143,7 +142,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
|
||||
{
|
||||
match predicate_for_builtin_bound(infcx.tcx, cause, builtin_bound, 0, ty) {
|
||||
Ok(predicate) => {
|
||||
self.register_predicate(infcx, predicate);
|
||||
self.register_predicate_obligation(infcx, predicate);
|
||||
}
|
||||
Err(ErrorReported) => { }
|
||||
}
|
||||
@ -158,10 +157,14 @@ impl<'tcx> FulfillmentContext<'tcx> {
|
||||
register_region_obligation(infcx.tcx, t_a, r_b, cause, &mut self.region_obligations);
|
||||
}
|
||||
|
||||
pub fn register_predicate<'a>(&mut self,
|
||||
infcx: &InferCtxt<'a,'tcx>,
|
||||
obligation: PredicateObligation<'tcx>)
|
||||
pub fn register_predicate_obligation<'a>(&mut self,
|
||||
infcx: &InferCtxt<'a,'tcx>,
|
||||
obligation: PredicateObligation<'tcx>)
|
||||
{
|
||||
// this helps to reduce duplicate errors, as well as making
|
||||
// debug output much nicer to read and so on.
|
||||
let obligation = infcx.resolve_type_vars_if_possible(&obligation);
|
||||
|
||||
if !self.duplicate_set.insert(obligation.predicate.clone()) {
|
||||
debug!("register_predicate({}) -- already seen, skip", obligation.repr(infcx.tcx));
|
||||
return;
|
||||
@ -290,7 +293,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
|
||||
// Now go through all the successful ones,
|
||||
// registering any nested obligations for the future.
|
||||
for new_obligation in new_obligations.into_iter() {
|
||||
self.register_predicate(selcx.infcx(), new_obligation);
|
||||
self.register_predicate_obligation(selcx.infcx(), new_obligation);
|
||||
}
|
||||
}
|
||||
|
||||
@ -398,104 +401,18 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
|
||||
project_obligation.repr(tcx),
|
||||
result.repr(tcx));
|
||||
match result {
|
||||
Ok(()) => {
|
||||
Ok(Some(obligations)) => {
|
||||
new_obligations.extend(obligations.into_iter());
|
||||
true
|
||||
}
|
||||
Err(project::ProjectionError::TooManyCandidates) => {
|
||||
// Without more type information, we can't say much.
|
||||
Ok(None) => {
|
||||
false
|
||||
}
|
||||
Err(project::ProjectionError::NoCandidate) => {
|
||||
// This means that we have a type like `<T as
|
||||
// Trait>::name = U` but we couldn't find any more
|
||||
// information. This could just be that we're in a
|
||||
// function like:
|
||||
//
|
||||
// fn foo<T:Trait>(...)
|
||||
//
|
||||
// in which case this is not an error. But it
|
||||
// might also mean we're in a situation where we
|
||||
// don't actually know that `T : Trait` holds,
|
||||
// which would be weird (e.g., if `T` was not a
|
||||
// parameter type but a normal type, like `int`).
|
||||
//
|
||||
// So what we do is to (1) add a requirement that
|
||||
// `T : Trait` (just in case) and (2) try to unify
|
||||
// `U` with `<T as Trait>::name`.
|
||||
|
||||
if !ty::binds_late_bound_regions(selcx.tcx(), data) {
|
||||
// Check that `T : Trait` holds.
|
||||
let trait_ref = data.to_poly_trait_ref();
|
||||
new_obligations.push(obligation.with(trait_ref.as_predicate()));
|
||||
|
||||
// Fallback to `<T as Trait>::name`. If this
|
||||
// fails, then the output must be at least
|
||||
// somewhat constrained, and we cannot verify
|
||||
// that constraint, so yield an error.
|
||||
let ty_projection = ty::mk_projection(tcx,
|
||||
trait_ref.0.clone(),
|
||||
data.0.projection_ty.item_name);
|
||||
|
||||
debug!("process_predicate: falling back to projection {}",
|
||||
ty_projection.repr(selcx.tcx()));
|
||||
|
||||
match infer::mk_eqty(selcx.infcx(),
|
||||
true,
|
||||
infer::EquatePredicate(obligation.cause.span),
|
||||
ty_projection,
|
||||
data.0.ty) {
|
||||
Ok(()) => { }
|
||||
Err(_) => {
|
||||
debug!("process_predicate: fallback failed to unify; error");
|
||||
errors.push(
|
||||
FulfillmentError::new(
|
||||
obligation.clone(),
|
||||
CodeSelectionError(Unimplemented)));
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
} else {
|
||||
// If we have something like
|
||||
//
|
||||
// for<'a> <T<'a> as Trait>::name == &'a int
|
||||
//
|
||||
// there is no "canonical form" for us to
|
||||
// make, so just report the lack of candidates
|
||||
// as an error.
|
||||
|
||||
debug!("process_predicate: can't fallback, higher-ranked");
|
||||
errors.push(
|
||||
FulfillmentError::new(
|
||||
obligation.clone(),
|
||||
CodeSelectionError(Unimplemented)));
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
Err(project::ProjectionError::MismatchedTypes(e)) => {
|
||||
Err(err) => {
|
||||
errors.push(
|
||||
FulfillmentError::new(
|
||||
obligation.clone(),
|
||||
CodeProjectionError(e)));
|
||||
true
|
||||
}
|
||||
Err(project::ProjectionError::TraitSelectionError(_)) => {
|
||||
// There was an error matching `T : Trait` (which
|
||||
// is a pre-requisite for `<T as Trait>::Name`
|
||||
// being valid). We could just report the error
|
||||
// now, but that tends to lead to double error
|
||||
// reports for the user (one for the obligation `T
|
||||
// : Trait`, typically incurred somewhere else,
|
||||
// and one from here). Instead, we'll create the
|
||||
// `T : Trait` obligation and add THAT as a
|
||||
// requirement. This will (eventually) trigger the
|
||||
// same error, but it will also wind up flagged as
|
||||
// a duplicate if another requirement that `T :
|
||||
// Trait` arises from somewhere else.
|
||||
let trait_predicate = data.to_poly_trait_ref();
|
||||
let trait_obligation = obligation.with(trait_predicate.as_predicate());
|
||||
new_obligations.push(trait_obligation);
|
||||
CodeProjectionError(err)));
|
||||
true
|
||||
}
|
||||
}
|
||||
|
@ -27,8 +27,8 @@ use util::ppaux::Repr;
|
||||
pub use self::error_reporting::report_fulfillment_errors;
|
||||
pub use self::fulfill::{FulfillmentContext, RegionObligation};
|
||||
pub use self::project::MismatchedProjectionTypes;
|
||||
pub use self::project::project_type;
|
||||
pub use self::project::ProjectionResult;
|
||||
pub use self::project::normalize;
|
||||
pub use self::project::Normalized;
|
||||
pub use self::select::SelectionContext;
|
||||
pub use self::select::SelectionCache;
|
||||
pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch};
|
||||
@ -320,6 +320,16 @@ impl<'tcx,O> Obligation<'tcx,O> {
|
||||
predicate: trait_ref }
|
||||
}
|
||||
|
||||
fn with_depth(cause: ObligationCause<'tcx>,
|
||||
recursion_depth: uint,
|
||||
trait_ref: O)
|
||||
-> Obligation<'tcx, O>
|
||||
{
|
||||
Obligation { cause: cause,
|
||||
recursion_depth: recursion_depth,
|
||||
predicate: trait_ref }
|
||||
}
|
||||
|
||||
pub fn misc(span: Span, body_id: ast::NodeId, trait_ref: O) -> Obligation<'tcx, O> {
|
||||
Obligation::new(ObligationCause::misc(span, body_id), trait_ref)
|
||||
}
|
||||
|
@ -12,6 +12,8 @@
|
||||
|
||||
use super::elaborate_predicates;
|
||||
use super::Obligation;
|
||||
use super::ObligationCause;
|
||||
use super::Overflow;
|
||||
use super::PredicateObligation;
|
||||
use super::SelectionContext;
|
||||
use super::SelectionError;
|
||||
@ -19,7 +21,8 @@ use super::VtableImplData;
|
||||
|
||||
use middle::infer;
|
||||
use middle::subst::Subst;
|
||||
use middle::ty::{mod, AsPredicate, ToPolyTraitRef, Ty};
|
||||
use middle::ty::{mod, AsPredicate, RegionEscape, HasProjectionTypes, ToPolyTraitRef, Ty};
|
||||
use middle::ty_fold::{mod, TypeFoldable, TypeFolder};
|
||||
use util::ppaux::Repr;
|
||||
|
||||
pub type PolyProjectionObligation<'tcx> =
|
||||
@ -31,21 +34,11 @@ pub type ProjectionObligation<'tcx> =
|
||||
pub type ProjectionTyObligation<'tcx> =
|
||||
Obligation<'tcx, ty::ProjectionTy<'tcx>>;
|
||||
|
||||
/// When attempting to resolve `<T as TraitRef>::Name == U`...
|
||||
pub enum ProjectionError<'tcx> {
|
||||
/// ...we could not find any helpful information on what `Name`
|
||||
/// might be. This could occur, for example, if there is a where
|
||||
/// clause `T : TraitRef` but not `T : TraitRef<Name=V>`. When
|
||||
/// normalizing, this case is where we opt to normalize back to
|
||||
/// the projection type `<T as TraitRef>::Name`.
|
||||
NoCandidate,
|
||||
|
||||
/// When attempting to resolve `<T as TraitRef>::Name` ...
|
||||
pub enum ProjectionTyError<'tcx> {
|
||||
/// ...we found multiple sources of information and couldn't resolve the ambiguity.
|
||||
TooManyCandidates,
|
||||
|
||||
/// ...`<T as TraitRef::Name>` ws resolved to some type `V` that failed to unify with `U`
|
||||
MismatchedTypes(MismatchedProjectionTypes<'tcx>),
|
||||
|
||||
/// ...an error occurred matching `T : TraitRef`
|
||||
TraitSelectionError(SelectionError<'tcx>),
|
||||
}
|
||||
@ -55,8 +48,6 @@ pub struct MismatchedProjectionTypes<'tcx> {
|
||||
pub err: ty::type_err<'tcx>
|
||||
}
|
||||
|
||||
pub type ProjectionResult<'tcx, T> = Result<T, ProjectionError<'tcx>>;
|
||||
|
||||
enum ProjectionTyCandidate<'tcx> {
|
||||
ParamEnv(ty::PolyProjectionPredicate<'tcx>),
|
||||
Impl(VtableImplData<'tcx, PredicateObligation<'tcx>>),
|
||||
@ -70,24 +61,43 @@ struct ProjectionTyCandidateSet<'tcx> {
|
||||
pub fn poly_project_and_unify_type<'cx,'tcx>(
|
||||
selcx: &mut SelectionContext<'cx,'tcx>,
|
||||
obligation: &PolyProjectionObligation<'tcx>)
|
||||
-> ProjectionResult<'tcx, ()>
|
||||
-> Result<Option<Vec<PredicateObligation<'tcx>>>, MismatchedProjectionTypes<'tcx>>
|
||||
{
|
||||
debug!("poly_project(obligation={})",
|
||||
obligation.repr(selcx.tcx()));
|
||||
|
||||
let infcx = selcx.infcx();
|
||||
|
||||
infcx.try(|snapshot| {
|
||||
let result = infcx.try(|snapshot| {
|
||||
let (skol_predicate, skol_map) =
|
||||
infcx.skolemize_late_bound_regions(&obligation.predicate, snapshot);
|
||||
|
||||
let skol_obligation = obligation.with(skol_predicate);
|
||||
let () = try!(project_and_unify_type(selcx, &skol_obligation));
|
||||
match infcx.leak_check(&skol_map, snapshot) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(e) => Err(ProjectionError::MismatchedTypes(MismatchedProjectionTypes{err: e})),
|
||||
match project_and_unify_type(selcx, &skol_obligation) {
|
||||
Ok(Some(obligations)) => {
|
||||
match infcx.leak_check(&skol_map, snapshot) {
|
||||
Ok(()) => Ok(infcx.plug_leaks(skol_map, snapshot, &obligations)),
|
||||
Err(e) => Err(Some(MismatchedProjectionTypes { err: e })),
|
||||
}
|
||||
}
|
||||
Ok(None) => {
|
||||
// Signal ambiguity using Err just so that infcx.try()
|
||||
// rolls back the snapshot. We adapt below.
|
||||
Err(None)
|
||||
}
|
||||
Err(e) => {
|
||||
Err(Some(e))
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
// Above, we use Err(None) to signal ambiguity so that the
|
||||
// snapshot will be rolled back. But here, we want to translate to
|
||||
// Ok(None). Kind of weird.
|
||||
match result {
|
||||
Ok(obligations) => Ok(Some(obligations)),
|
||||
Err(None) => Ok(None),
|
||||
Err(Some(e)) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute result of projecting an associated type and unify it with
|
||||
@ -95,55 +105,281 @@ pub fn poly_project_and_unify_type<'cx,'tcx>(
|
||||
pub fn project_and_unify_type<'cx,'tcx>(
|
||||
selcx: &mut SelectionContext<'cx,'tcx>,
|
||||
obligation: &ProjectionObligation<'tcx>)
|
||||
-> ProjectionResult<'tcx, ()>
|
||||
-> Result<Option<Vec<PredicateObligation<'tcx>>>, MismatchedProjectionTypes<'tcx>>
|
||||
{
|
||||
debug!("project_and_unify(obligation={})",
|
||||
obligation.repr(selcx.tcx()));
|
||||
|
||||
let ty_obligation = obligation.with(obligation.predicate.projection_ty.clone());
|
||||
let projected_ty = try!(project_type(selcx, &ty_obligation));
|
||||
let Normalized { value: normalized_ty, obligations } =
|
||||
match opt_normalize_projection_type(selcx,
|
||||
obligation.predicate.projection_ty.clone(),
|
||||
obligation.cause.clone(),
|
||||
obligation.recursion_depth) {
|
||||
Some(n) => n,
|
||||
None => { return Ok(None); }
|
||||
};
|
||||
|
||||
debug!("project_and_unify_type: normalized_ty={} obligations={}",
|
||||
normalized_ty.repr(selcx.tcx()),
|
||||
obligations.repr(selcx.tcx()));
|
||||
|
||||
let infcx = selcx.infcx();
|
||||
let origin = infer::RelateOutputImplTypes(obligation.cause.span);
|
||||
debug!("project_and_unify_type: projected_ty = {}", projected_ty.repr(selcx.tcx()));
|
||||
match infer::mk_eqty(infcx, true, origin, projected_ty, obligation.predicate.ty) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(e) => Err(ProjectionError::MismatchedTypes(MismatchedProjectionTypes{err: e})),
|
||||
match infer::mk_eqty(infcx, true, origin, normalized_ty, obligation.predicate.ty) {
|
||||
Ok(()) => Ok(Some(obligations)),
|
||||
Err(err) => Err(MismatchedProjectionTypes { err: err }),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn normalize<'a,'b,'tcx,T>(selcx: &'a mut SelectionContext<'b,'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
value: &T)
|
||||
-> Normalized<'tcx, T>
|
||||
where T : TypeFoldable<'tcx> + HasProjectionTypes + Clone
|
||||
{
|
||||
let mut normalizer = AssociatedTypeNormalizer::new(selcx, cause, 0);
|
||||
let result = normalizer.fold(value);
|
||||
Normalized {
|
||||
value: result,
|
||||
obligations: normalizer.obligations,
|
||||
}
|
||||
}
|
||||
|
||||
struct AssociatedTypeNormalizer<'a,'b:'a,'tcx:'b> {
|
||||
selcx: &'a mut SelectionContext<'b,'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
obligations: Vec<PredicateObligation<'tcx>>,
|
||||
depth: uint,
|
||||
}
|
||||
|
||||
impl<'a,'b,'tcx> AssociatedTypeNormalizer<'a,'b,'tcx> {
|
||||
fn new(selcx: &'a mut SelectionContext<'b,'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
depth: uint)
|
||||
-> AssociatedTypeNormalizer<'a,'b,'tcx>
|
||||
{
|
||||
AssociatedTypeNormalizer {
|
||||
selcx: selcx,
|
||||
cause: cause,
|
||||
obligations: vec!(),
|
||||
depth: depth,
|
||||
}
|
||||
}
|
||||
|
||||
fn fold<T:TypeFoldable<'tcx> + HasProjectionTypes + Clone>(&mut self, value: &T) -> T {
|
||||
let value = self.selcx.infcx().resolve_type_vars_if_possible(value);
|
||||
|
||||
if !value.has_projection_types() {
|
||||
value.clone()
|
||||
} else {
|
||||
value.fold_with(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a,'b,'tcx> TypeFolder<'tcx> for AssociatedTypeNormalizer<'a,'b,'tcx> {
|
||||
fn tcx(&self) -> &ty::ctxt<'tcx> {
|
||||
self.selcx.tcx()
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
// We don't want to normalize associated types that occur inside of region
|
||||
// binders, because they may contain bound regions, and we can't cope with that.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// for<'a> fn(<T as Foo<&'a>>::A)
|
||||
//
|
||||
// Instead of normalizing `<T as Foo<&'a>>::A` here, we'll
|
||||
// normalize it when we instantiate those bound regions (which
|
||||
// should occur eventually).
|
||||
|
||||
match ty.sty {
|
||||
ty::ty_projection(ref data) if !data.has_escaping_regions() => { // (*)
|
||||
|
||||
// (*) This is kind of hacky -- we need to be able to
|
||||
// handle normalization within binders because
|
||||
// otherwise we wind up a need to normalize when doing
|
||||
// trait matching (since you can have a trait
|
||||
// obligation like `for<'a> T::B : Fn(&'a int)`), but
|
||||
// we can't normalize with bound regions in scope. So
|
||||
// far now we just ignore binders but only normalize
|
||||
// if all bound regions are gone (and then we still
|
||||
// have to renormalize whenever we instantiate a
|
||||
// binder). It would be better to normalize in a
|
||||
// binding-aware fashion.
|
||||
|
||||
let Normalized { value: ty, obligations } =
|
||||
normalize_projection_type(self.selcx,
|
||||
data.clone(),
|
||||
self.cause.clone(),
|
||||
self.depth);
|
||||
self.obligations.extend(obligations.into_iter());
|
||||
ty
|
||||
}
|
||||
_ => {
|
||||
ty_fold::super_fold_ty(self, ty)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Normalized<'tcx,T> {
|
||||
pub value: T,
|
||||
pub obligations: Vec<PredicateObligation<'tcx>>,
|
||||
}
|
||||
|
||||
pub type NormalizedTy<'tcx> = Normalized<'tcx, Ty<'tcx>>;
|
||||
|
||||
pub fn normalize_projection_type<'a,'b,'tcx>(
|
||||
selcx: &'a mut SelectionContext<'b,'tcx>,
|
||||
projection_ty: ty::ProjectionTy<'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
depth: uint)
|
||||
-> NormalizedTy<'tcx>
|
||||
{
|
||||
opt_normalize_projection_type(selcx, projection_ty.clone(), cause.clone(), depth)
|
||||
.unwrap_or_else(move || {
|
||||
// if we bottom out in ambiguity, create a type variable
|
||||
// and a deferred predicate to resolve this when more type
|
||||
// information is available.
|
||||
|
||||
let ty_var = selcx.infcx().next_ty_var();
|
||||
let projection = ty::Binder(ty::ProjectionPredicate {
|
||||
projection_ty: projection_ty,
|
||||
ty: ty_var
|
||||
});
|
||||
let obligation = Obligation::with_depth(cause, depth+1, projection.as_predicate());
|
||||
Normalized {
|
||||
value: ty_var,
|
||||
obligations: vec!(obligation)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn opt_normalize_projection_type<'a,'b,'tcx>(
|
||||
selcx: &'a mut SelectionContext<'b,'tcx>,
|
||||
projection_ty: ty::ProjectionTy<'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
depth: uint)
|
||||
-> Option<NormalizedTy<'tcx>>
|
||||
{
|
||||
debug!("normalize_projection_type(\
|
||||
projection_ty={}, \
|
||||
depth={})",
|
||||
projection_ty.repr(selcx.tcx()),
|
||||
depth);
|
||||
|
||||
let obligation = Obligation::with_depth(cause.clone(), depth, projection_ty.clone());
|
||||
match project_type(selcx, &obligation) {
|
||||
Ok(ProjectedTy::Progress(projected_ty, mut obligations)) => {
|
||||
// if projection succeeded, then what we get out of this
|
||||
// is also non-normalized (consider: it was derived from
|
||||
// an impl, where-clause etc) and hence we must
|
||||
// re-normalize it
|
||||
|
||||
debug!("normalize_projection_type: projected_ty={} depth={}",
|
||||
projected_ty.repr(selcx.tcx()),
|
||||
depth);
|
||||
|
||||
if ty::type_has_projection(projected_ty) {
|
||||
let tcx = selcx.tcx();
|
||||
let mut normalizer = AssociatedTypeNormalizer::new(selcx, cause, depth);
|
||||
let normalized_ty = normalizer.fold(&projected_ty);
|
||||
|
||||
debug!("normalize_projection_type: normalized_ty={} depth={}",
|
||||
normalized_ty.repr(tcx),
|
||||
depth);
|
||||
|
||||
obligations.extend(normalizer.obligations.into_iter());
|
||||
Some(Normalized {
|
||||
value: normalized_ty,
|
||||
obligations: obligations,
|
||||
})
|
||||
} else {
|
||||
Some(Normalized {
|
||||
value: projected_ty,
|
||||
obligations: obligations,
|
||||
})
|
||||
}
|
||||
}
|
||||
Ok(ProjectedTy::NoProgress(projected_ty)) => {
|
||||
Some(Normalized {
|
||||
value: projected_ty,
|
||||
obligations: vec!()
|
||||
})
|
||||
}
|
||||
Err(ProjectionTyError::TooManyCandidates) => {
|
||||
None
|
||||
}
|
||||
Err(ProjectionTyError::TraitSelectionError(_)) => {
|
||||
// if we got an error processing the `T as Trait` part,
|
||||
// just return `ty::err` but add the obligation `T :
|
||||
// Trait`, which when processed will cause the error to be
|
||||
// reported later
|
||||
|
||||
Some(normalize_to_error(selcx, projection_ty, cause, depth))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// in various error cases, we just set ty_err and return an obligation
|
||||
/// that, when fulfiled, will lead to an error
|
||||
fn normalize_to_error<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
|
||||
projection_ty: ty::ProjectionTy<'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
depth: uint)
|
||||
-> NormalizedTy<'tcx>
|
||||
{
|
||||
let trait_ref = projection_ty.trait_ref.to_poly_trait_ref();
|
||||
let trait_obligation = Obligation { cause: cause,
|
||||
recursion_depth: depth,
|
||||
predicate: trait_ref.as_predicate() };
|
||||
Normalized {
|
||||
value: selcx.tcx().types.err,
|
||||
obligations: vec!(trait_obligation)
|
||||
}
|
||||
}
|
||||
|
||||
enum ProjectedTy<'tcx> {
|
||||
Progress(Ty<'tcx>, Vec<PredicateObligation<'tcx>>),
|
||||
NoProgress(Ty<'tcx>),
|
||||
}
|
||||
|
||||
/// Compute the result of a projection type (if we can).
|
||||
pub fn project_type<'cx,'tcx>(
|
||||
fn project_type<'cx,'tcx>(
|
||||
selcx: &mut SelectionContext<'cx,'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>)
|
||||
-> ProjectionResult<'tcx, Ty<'tcx>>
|
||||
-> Result<ProjectedTy<'tcx>, ProjectionTyError<'tcx>>
|
||||
{
|
||||
debug!("project(obligation={})",
|
||||
obligation.repr(selcx.tcx()));
|
||||
|
||||
let recursion_limit = selcx.tcx().sess.recursion_limit.get();
|
||||
if obligation.recursion_depth >= recursion_limit {
|
||||
debug!("project: overflow!");
|
||||
return Err(ProjectionTyError::TraitSelectionError(Overflow));
|
||||
}
|
||||
|
||||
let mut candidates = ProjectionTyCandidateSet {
|
||||
vec: Vec::new(),
|
||||
ambiguous: false,
|
||||
};
|
||||
|
||||
let () = assemble_candidates_from_param_env(selcx,
|
||||
obligation,
|
||||
&mut candidates);
|
||||
|
||||
let () = assemble_candidates_from_object_type(selcx,
|
||||
obligation,
|
||||
&mut candidates);
|
||||
assemble_candidates_from_object_type(selcx,
|
||||
obligation,
|
||||
&mut candidates);
|
||||
|
||||
if candidates.vec.is_empty() {
|
||||
// FIXME(#20297) -- In `select.rs` there is similar logic that
|
||||
// gives precedence to where-clauses, but it's a bit more
|
||||
// fine-grained. I was lazy here and just always give
|
||||
// precedence to where-clauses or other such sources over
|
||||
// actually dredging through impls. This logic probably should
|
||||
// be tightened up.
|
||||
assemble_candidates_from_param_env(selcx,
|
||||
obligation,
|
||||
&mut candidates);
|
||||
|
||||
let () = try!(assemble_candidates_from_impls(selcx,
|
||||
obligation,
|
||||
&mut candidates));
|
||||
if let Err(e) = assemble_candidates_from_impls(selcx,
|
||||
obligation,
|
||||
&mut candidates) {
|
||||
return Err(ProjectionTyError::TraitSelectionError(e));
|
||||
}
|
||||
}
|
||||
|
||||
debug!("{} candidates, ambiguous={}",
|
||||
@ -153,15 +389,18 @@ pub fn project_type<'cx,'tcx>(
|
||||
// We probably need some winnowing logic similar to select here.
|
||||
|
||||
if candidates.ambiguous || candidates.vec.len() > 1 {
|
||||
return Err(ProjectionError::TooManyCandidates);
|
||||
return Err(ProjectionTyError::TooManyCandidates);
|
||||
}
|
||||
|
||||
match candidates.vec.pop() {
|
||||
Some(candidate) => {
|
||||
Ok(try!(confirm_candidate(selcx, obligation, candidate)))
|
||||
let (ty, obligations) = confirm_candidate(selcx, obligation, candidate);
|
||||
Ok(ProjectedTy::Progress(ty, obligations))
|
||||
}
|
||||
None => {
|
||||
Err(ProjectionError::NoCandidate)
|
||||
Ok(ProjectedTy::NoProgress(ty::mk_projection(selcx.tcx(),
|
||||
obligation.predicate.trait_ref.clone(),
|
||||
obligation.predicate.item_name)))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -237,9 +476,9 @@ fn assemble_candidates_from_object_type<'cx,'tcx>(
|
||||
|
||||
fn assemble_candidates_from_impls<'cx,'tcx>(
|
||||
selcx: &mut SelectionContext<'cx,'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
candidate_set: &mut ProjectionTyCandidateSet<'tcx>)
|
||||
-> ProjectionResult<'tcx, ()>
|
||||
-> Result<(), SelectionError<'tcx>>
|
||||
{
|
||||
// If we are resolving `<T as TraitRef<...>>::Item == Type`,
|
||||
// start out by selecting the predicate `T as TraitRef<...>`:
|
||||
@ -256,7 +495,7 @@ fn assemble_candidates_from_impls<'cx,'tcx>(
|
||||
Err(e) => {
|
||||
debug!("assemble_candidates_from_impls: selection error {}",
|
||||
e.repr(selcx.tcx()));
|
||||
return Err(ProjectionError::TraitSelectionError(e));
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
|
||||
@ -308,9 +547,9 @@ fn assemble_candidates_from_impls<'cx,'tcx>(
|
||||
|
||||
fn confirm_candidate<'cx,'tcx>(
|
||||
selcx: &mut SelectionContext<'cx,'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
candidate: ProjectionTyCandidate<'tcx>)
|
||||
-> ProjectionResult<'tcx, Ty<'tcx>>
|
||||
-> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
|
||||
{
|
||||
let infcx = selcx.infcx();
|
||||
|
||||
@ -318,7 +557,7 @@ fn confirm_candidate<'cx,'tcx>(
|
||||
candidate.repr(infcx.tcx),
|
||||
obligation.repr(infcx.tcx));
|
||||
|
||||
let projected_ty = match candidate {
|
||||
match candidate {
|
||||
ProjectionTyCandidate::ParamEnv(poly_projection) => {
|
||||
let projection =
|
||||
infcx.replace_late_bound_regions_with_fresh_var(
|
||||
@ -345,7 +584,7 @@ fn confirm_candidate<'cx,'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
projection.ty
|
||||
(projection.ty, vec!())
|
||||
}
|
||||
|
||||
ProjectionTyCandidate::Impl(impl_vtable) => {
|
||||
@ -371,7 +610,7 @@ fn confirm_candidate<'cx,'tcx>(
|
||||
}
|
||||
|
||||
match impl_ty {
|
||||
Some(ty) => ty,
|
||||
Some(ty) => (ty, impl_vtable.nested.to_vec()),
|
||||
None => {
|
||||
selcx.tcx().sess.span_bug(
|
||||
obligation.cause.span,
|
||||
@ -381,21 +620,15 @@ fn confirm_candidate<'cx,'tcx>(
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ok(projected_ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Repr<'tcx> for ProjectionError<'tcx> {
|
||||
impl<'tcx> Repr<'tcx> for ProjectionTyError<'tcx> {
|
||||
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
|
||||
match *self {
|
||||
ProjectionError::NoCandidate =>
|
||||
ProjectionTyError::TooManyCandidates =>
|
||||
format!("NoCandidate"),
|
||||
ProjectionError::TooManyCandidates =>
|
||||
format!("NoCandidate"),
|
||||
ProjectionError::MismatchedTypes(ref m) =>
|
||||
format!("MismatchedTypes({})", m.repr(tcx)),
|
||||
ProjectionError::TraitSelectionError(ref e) =>
|
||||
ProjectionTyError::TraitSelectionError(ref e) =>
|
||||
format!("TraitSelectionError({})", e.repr(tcx)),
|
||||
}
|
||||
}
|
||||
@ -411,4 +644,3 @@ impl<'tcx> Repr<'tcx> for ProjectionTyCandidate<'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5449,8 +5449,15 @@ pub fn predicates_for_trait_ref<'tcx>(tcx: &ctxt<'tcx>,
|
||||
.map(|poly_trait_ref| ty::Binder(poly_trait_ref.0.subst(tcx, trait_ref.substs())))
|
||||
.collect();
|
||||
|
||||
debug!("bounds_for_trait_ref: trait_bounds={}",
|
||||
trait_bounds.repr(tcx));
|
||||
let projection_bounds: Vec<_> =
|
||||
trait_def.bounds.projection_bounds
|
||||
.iter()
|
||||
.map(|poly_proj| ty::Binder(poly_proj.0.subst(tcx, trait_ref.substs())))
|
||||
.collect();
|
||||
|
||||
debug!("bounds_for_trait_ref: trait_bounds={} projection_bounds={}",
|
||||
trait_bounds.repr(tcx),
|
||||
projection_bounds.repr(tcx));
|
||||
|
||||
// The region bounds and builtin bounds do not currently introduce
|
||||
// binders so we can just substitute in a straightforward way here.
|
||||
@ -5463,11 +5470,7 @@ pub fn predicates_for_trait_ref<'tcx>(tcx: &ctxt<'tcx>,
|
||||
trait_bounds: trait_bounds,
|
||||
region_bounds: region_bounds,
|
||||
builtin_bounds: builtin_bounds,
|
||||
|
||||
// FIXME(#19451) -- if a trait has a bound like `trait Foo :
|
||||
// Bar<T=X>`, we should probably be returning that, but this
|
||||
// code here will just ignore it.
|
||||
projection_bounds: Vec::new(),
|
||||
projection_bounds: projection_bounds,
|
||||
};
|
||||
|
||||
predicates(tcx, trait_ref.self_ty(), &bounds)
|
||||
@ -6385,7 +6388,7 @@ pub fn construct_parameter_environment<'tcx>(
|
||||
}
|
||||
|
||||
fn push_types_from_defs<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
types: &mut subst::VecPerParamSpace<Ty<'tcx>>,
|
||||
types: &mut VecPerParamSpace<Ty<'tcx>>,
|
||||
defs: &[TypeParameterDef<'tcx>]) {
|
||||
for def in defs.iter() {
|
||||
debug!("construct_parameter_environment(): push_types_from_defs: def={}",
|
||||
@ -6915,12 +6918,49 @@ impl<'tcx> RegionEscape for Ty<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx,T:RegionEscape> RegionEscape for VecPerParamSpace<T> {
|
||||
fn has_regions_escaping_depth(&self, depth: u32) -> bool {
|
||||
self.iter_enumerated().any(|(space, _, t)| {
|
||||
if space == subst::FnSpace {
|
||||
t.has_regions_escaping_depth(depth+1)
|
||||
} else {
|
||||
t.has_regions_escaping_depth(depth)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> RegionEscape for TypeScheme<'tcx> {
|
||||
fn has_regions_escaping_depth(&self, depth: u32) -> bool {
|
||||
self.ty.has_regions_escaping_depth(depth) ||
|
||||
self.generics.has_regions_escaping_depth(depth)
|
||||
}
|
||||
}
|
||||
|
||||
impl RegionEscape for Region {
|
||||
fn has_regions_escaping_depth(&self, depth: u32) -> bool {
|
||||
self.escapes_depth(depth)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> RegionEscape for Generics<'tcx> {
|
||||
fn has_regions_escaping_depth(&self, depth: u32) -> bool {
|
||||
self.predicates.has_regions_escaping_depth(depth)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> RegionEscape for Predicate<'tcx> {
|
||||
fn has_regions_escaping_depth(&self, depth: u32) -> bool {
|
||||
match *self {
|
||||
Predicate::Trait(ref data) => data.has_regions_escaping_depth(depth),
|
||||
Predicate::Equate(ref data) => data.has_regions_escaping_depth(depth),
|
||||
Predicate::RegionOutlives(ref data) => data.has_regions_escaping_depth(depth),
|
||||
Predicate::TypeOutlives(ref data) => data.has_regions_escaping_depth(depth),
|
||||
Predicate::Projection(ref data) => data.has_regions_escaping_depth(depth),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> RegionEscape for TraitRef<'tcx> {
|
||||
fn has_regions_escaping_depth(&self, depth: u32) -> bool {
|
||||
self.substs.types.iter().any(|t| t.has_regions_escaping_depth(depth)) ||
|
||||
@ -6988,9 +7028,15 @@ pub trait HasProjectionTypes {
|
||||
fn has_projection_types(&self) -> bool;
|
||||
}
|
||||
|
||||
impl<'tcx,T:HasProjectionTypes> HasProjectionTypes for VecPerParamSpace<T> {
|
||||
fn has_projection_types(&self) -> bool {
|
||||
self.iter().any(|p| p.has_projection_types())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasProjectionTypes for ty::GenericBounds<'tcx> {
|
||||
fn has_projection_types(&self) -> bool {
|
||||
self.predicates.iter().any(|p| p.has_projection_types())
|
||||
self.predicates.has_projection_types()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -954,28 +954,47 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
|
||||
// Currently, we use a fulfillment context to completely resolve
|
||||
// all nested obligations. This is because they can inform the
|
||||
// inference of the impl's type parameters. However, in principle,
|
||||
// we only need to do this until the impl's type parameters are
|
||||
// fully bound. It could be a slight optimization to stop
|
||||
// iterating early.
|
||||
// inference of the impl's type parameters.
|
||||
let mut fulfill_cx = traits::FulfillmentContext::new();
|
||||
let vtable = selection.map_move_nested(|predicate| {
|
||||
fulfill_cx.register_predicate(&infcx, predicate);
|
||||
fulfill_cx.register_predicate_obligation(&infcx, predicate);
|
||||
});
|
||||
match fulfill_cx.select_all_or_error(&infcx, ¶m_env, tcx) {
|
||||
let vtable = drain_fulfillment_cx(span, &infcx, ¶m_env, &mut fulfill_cx, &vtable);
|
||||
|
||||
info!("Cache miss: {}", trait_ref.repr(ccx.tcx()));
|
||||
ccx.trait_cache().borrow_mut().insert(trait_ref,
|
||||
vtable.clone());
|
||||
|
||||
vtable
|
||||
}
|
||||
|
||||
pub fn drain_fulfillment_cx<'a,'tcx,T>(span: Span,
|
||||
infcx: &infer::InferCtxt<'a,'tcx>,
|
||||
param_env: &ty::ParameterEnvironment<'tcx>,
|
||||
fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
|
||||
result: &T)
|
||||
-> T
|
||||
where T : TypeFoldable<'tcx> + Repr<'tcx>
|
||||
{
|
||||
debug!("drain_fulfillment_cx(result={})",
|
||||
result.repr(infcx.tcx));
|
||||
|
||||
// In principle, we only need to do this so long as `result`
|
||||
// contains unbound type parameters. It could be a slight
|
||||
// optimization to stop iterating early.
|
||||
match fulfill_cx.select_all_or_error(infcx, param_env, infcx.tcx) {
|
||||
Ok(()) => { }
|
||||
Err(errors) => {
|
||||
if errors.iter().all(|e| e.is_overflow()) {
|
||||
// See Ok(None) case above.
|
||||
ccx.sess().span_fatal(
|
||||
infcx.tcx.sess.span_fatal(
|
||||
span,
|
||||
"reached the recursion limit during monomorphization");
|
||||
} else {
|
||||
tcx.sess.span_bug(
|
||||
infcx.tcx.sess.span_bug(
|
||||
span,
|
||||
format!("Encountered errors `{}` fulfilling `{}` during trans",
|
||||
errors.repr(tcx),
|
||||
trait_ref.repr(tcx))[]);
|
||||
format!("Encountered errors `{}` fulfilling during trans",
|
||||
errors.repr(infcx.tcx))[]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -985,13 +1004,7 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
// sort of overkill because we do not expect there to be any
|
||||
// unbound type variables, hence no `TyFresh` types should ever be
|
||||
// inserted.
|
||||
let vtable = vtable.fold_with(&mut infcx.freshener());
|
||||
|
||||
info!("Cache miss: {}", trait_ref.repr(ccx.tcx()));
|
||||
ccx.trait_cache().borrow_mut().insert(trait_ref,
|
||||
vtable.clone());
|
||||
|
||||
vtable
|
||||
result.fold_with(&mut infcx.freshener())
|
||||
}
|
||||
|
||||
// Key used to lookup values supplied for type parameters in an expr.
|
||||
|
@ -16,7 +16,7 @@ use middle::infer;
|
||||
use middle::subst;
|
||||
use middle::subst::{Subst, Substs};
|
||||
use middle::traits;
|
||||
use middle::ty_fold::{mod, TypeFolder, TypeFoldable};
|
||||
use middle::ty_fold::{TypeFolder, TypeFoldable};
|
||||
use trans::base::{set_llvm_fn_attrs, set_inline_hint};
|
||||
use trans::base::{trans_enum_variant, push_ctxt, get_item_val};
|
||||
use trans::base::{trans_fn, decl_internal_rust_fn};
|
||||
@ -31,8 +31,8 @@ use syntax::ast;
|
||||
use syntax::ast_map;
|
||||
use syntax::ast_util::{local_def, PostExpansionMethod};
|
||||
use syntax::attr;
|
||||
use syntax::codemap::DUMMY_SP;
|
||||
use std::hash::{sip, Hash};
|
||||
use std::rc::Rc;
|
||||
|
||||
pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
fn_id: ast::DefId,
|
||||
@ -310,13 +310,13 @@ pub fn apply_param_substs<'tcx,T>(tcx: &ty::ctxt<'tcx>,
|
||||
/// monomorphization, we know that only concrete types are involved,
|
||||
/// and hence we can be sure that all associated types will be
|
||||
/// completely normalized away.
|
||||
pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, t: &T) -> T
|
||||
pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> T
|
||||
where T : TypeFoldable<'tcx> + Repr<'tcx> + HasProjectionTypes + Clone
|
||||
{
|
||||
debug!("normalize_associated_type(t={})", t.repr(tcx));
|
||||
debug!("normalize_associated_type(t={})", value.repr(tcx));
|
||||
|
||||
if !t.has_projection_types() {
|
||||
return t.clone();
|
||||
if !value.has_projection_types() {
|
||||
return value.clone();
|
||||
}
|
||||
|
||||
// FIXME(#20304) -- cache
|
||||
@ -324,52 +324,19 @@ pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, t: &T) -> T
|
||||
let infcx = infer::new_infer_ctxt(tcx);
|
||||
let param_env = ty::empty_parameter_environment();
|
||||
let mut selcx = traits::SelectionContext::new(&infcx, ¶m_env, tcx);
|
||||
let mut normalizer = AssociatedTypeNormalizer { selcx: &mut selcx };
|
||||
let result = t.fold_with(&mut normalizer);
|
||||
let cause = traits::ObligationCause::dummy();
|
||||
let traits::Normalized { value: result, obligations } =
|
||||
traits::normalize(&mut selcx, cause, value);
|
||||
|
||||
debug!("normalize_associated_type: t={} result={}",
|
||||
t.repr(tcx),
|
||||
result.repr(tcx));
|
||||
debug!("normalize_associated_type: result={} obligations={}",
|
||||
result.repr(tcx),
|
||||
obligations.repr(tcx));
|
||||
|
||||
let mut fulfill_cx = traits::FulfillmentContext::new();
|
||||
for obligation in obligations.into_iter() {
|
||||
fulfill_cx.register_predicate_obligation(&infcx, obligation);
|
||||
}
|
||||
let result = drain_fulfillment_cx(DUMMY_SP, &infcx, ¶m_env, &mut fulfill_cx, &result);
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
struct AssociatedTypeNormalizer<'a,'tcx:'a> {
|
||||
selcx: &'a mut traits::SelectionContext<'a,'tcx>,
|
||||
}
|
||||
|
||||
impl<'a,'tcx> TypeFolder<'tcx> for AssociatedTypeNormalizer<'a,'tcx> {
|
||||
fn tcx(&self) -> &ty::ctxt<'tcx> { self.selcx.tcx() }
|
||||
|
||||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
match ty.sty {
|
||||
ty::ty_projection(ref data) => {
|
||||
debug!("ty_projection({})", data.repr(self.tcx()));
|
||||
|
||||
let tcx = self.selcx.tcx();
|
||||
let substs = data.trait_ref.substs.clone().erase_regions();
|
||||
let substs = self.tcx().mk_substs(substs);
|
||||
assert!(substs.types.iter().all(|&t| (!ty::type_has_params(t) &&
|
||||
!ty::type_has_self(t))));
|
||||
let trait_ref = Rc::new(ty::TraitRef::new(data.trait_ref.def_id, substs));
|
||||
let projection_ty = ty::ProjectionTy { trait_ref: trait_ref.clone(),
|
||||
item_name: data.item_name };
|
||||
let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
|
||||
projection_ty);
|
||||
match traits::project_type(self.selcx, &obligation) {
|
||||
Ok(ty) => ty,
|
||||
Err(errors) => {
|
||||
tcx.sess.bug(
|
||||
format!("Encountered error(s) `{}` selecting `{}` during trans",
|
||||
errors.repr(tcx),
|
||||
trait_ref.repr(tcx)).as_slice());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
ty_fold::super_fold_ty(self, ty)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,85 +9,34 @@
|
||||
// except according to those terms.
|
||||
|
||||
use middle::infer::InferCtxt;
|
||||
use middle::traits::{ObligationCause, ObligationCauseCode, FulfillmentContext};
|
||||
use middle::ty::{mod, RegionEscape, HasProjectionTypes, Ty};
|
||||
use middle::ty_fold::{mod, TypeFoldable, TypeFolder};
|
||||
use middle::mem_categorization as mc;
|
||||
use middle::traits::{mod, FulfillmentContext, Normalized, MiscObligation,
|
||||
SelectionContext, ObligationCause};
|
||||
use middle::ty::{mod, HasProjectionTypes};
|
||||
use middle::ty_fold::{TypeFoldable, TypeFolder};
|
||||
use syntax::ast;
|
||||
use syntax::codemap::Span;
|
||||
use util::ppaux::Repr;
|
||||
|
||||
pub fn normalize_associated_types_in<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
|
||||
param_env: &ty::ParameterEnvironment<'tcx>,
|
||||
typer: &(mc::Typer<'tcx>+'a),
|
||||
fulfillment_cx: &mut FulfillmentContext<'tcx>,
|
||||
span: Span,
|
||||
body_id: ast::NodeId,
|
||||
value: &T)
|
||||
-> T
|
||||
where T : TypeFoldable<'tcx> + HasProjectionTypes + Clone
|
||||
where T : TypeFoldable<'tcx> + HasProjectionTypes + Clone + Repr<'tcx>
|
||||
{
|
||||
let value = infcx.resolve_type_vars_if_possible(value);
|
||||
|
||||
if !value.has_projection_types() {
|
||||
return value.clone();
|
||||
}
|
||||
|
||||
let mut normalizer = AssociatedTypeNormalizer { span: span,
|
||||
body_id: body_id,
|
||||
infcx: infcx,
|
||||
fulfillment_cx: fulfillment_cx };
|
||||
value.fold_with(&mut normalizer)
|
||||
}
|
||||
|
||||
struct AssociatedTypeNormalizer<'a,'tcx:'a> {
|
||||
infcx: &'a InferCtxt<'a, 'tcx>,
|
||||
fulfillment_cx: &'a mut FulfillmentContext<'tcx>,
|
||||
span: Span,
|
||||
body_id: ast::NodeId,
|
||||
}
|
||||
|
||||
impl<'a,'tcx> TypeFolder<'tcx> for AssociatedTypeNormalizer<'a,'tcx> {
|
||||
fn tcx(&self) -> &ty::ctxt<'tcx> {
|
||||
self.infcx.tcx
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
// We don't want to normalize associated types that occur inside of region
|
||||
// binders, because they may contain bound regions, and we can't cope with that.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// for<'a> fn(<T as Foo<&'a>>::A)
|
||||
//
|
||||
// Instead of normalizing `<T as Foo<&'a>>::A` here, we'll
|
||||
// normalize it when we instantiate those bound regions (which
|
||||
// should occur eventually).
|
||||
|
||||
match ty.sty {
|
||||
ty::ty_projection(ref data) if !data.has_escaping_regions() => { // (*)
|
||||
|
||||
// (*) This is kind of hacky -- we need to be able to
|
||||
// handle normalization within binders because
|
||||
// otherwise we wind up a need to normalize when doing
|
||||
// trait matching (since you can have a trait
|
||||
// obligation like `for<'a> T::B : Fn(&'a int)`), but
|
||||
// we can't normalize with bound regions in scope. So
|
||||
// far now we just ignore binders but only normalize
|
||||
// if all bound regions are gone (and then we still
|
||||
// have to renormalize whenever we instantiate a
|
||||
// binder). It would be better to normalize in a
|
||||
// binding-aware fashion.
|
||||
|
||||
let cause =
|
||||
ObligationCause::new(
|
||||
self.span,
|
||||
self.body_id,
|
||||
ObligationCauseCode::MiscObligation);
|
||||
self.fulfillment_cx
|
||||
.normalize_projection_type(self.infcx,
|
||||
data.clone(),
|
||||
cause)
|
||||
}
|
||||
_ => {
|
||||
ty_fold::super_fold_ty(self, ty)
|
||||
}
|
||||
}
|
||||
debug!("normalize_associated_types_in(value={})", value.repr(infcx.tcx));
|
||||
let mut selcx = SelectionContext::new(infcx, param_env, typer);
|
||||
let cause = ObligationCause::new(span, body_id, MiscObligation);
|
||||
let Normalized { value: result, obligations } = traits::normalize(&mut selcx, cause, value);
|
||||
debug!("normalize_associated_types_in: result={} predicates={}",
|
||||
result.repr(infcx.tcx),
|
||||
obligations.repr(infcx.tcx));
|
||||
for obligation in obligations.into_iter() {
|
||||
fulfillment_cx.register_predicate_obligation(infcx, obligation);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
@ -216,7 +216,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>,
|
||||
//
|
||||
// Note that as the method comes from a trait, it should not have
|
||||
// any late-bound regions appearing in its bounds.
|
||||
let method_bounds = method_ty.generics.to_bounds(fcx.tcx(), trait_ref.substs);
|
||||
let method_bounds = fcx.instantiate_bounds(span, trait_ref.substs, &method_ty.generics);
|
||||
assert!(!method_bounds.has_escaping_regions());
|
||||
fcx.add_obligations_for_parameters(
|
||||
traits::ObligationCause::misc(span, fcx.body_id),
|
||||
|
@ -768,6 +768,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
||||
// Check whether the impl imposes obligations we have to worry about.
|
||||
let impl_generics = ty::lookup_item_type(self.tcx(), impl_def_id).generics;
|
||||
let impl_bounds = impl_generics.to_bounds(self.tcx(), substs);
|
||||
// FIXME(#20378) assoc type normalization here?
|
||||
|
||||
// Erase any late-bound regions bound in the impl
|
||||
// which appear in the bounds.
|
||||
|
@ -93,7 +93,7 @@ use middle::subst::{mod, Subst, Substs, VecPerParamSpace, ParamSpace};
|
||||
use middle::traits;
|
||||
use middle::ty::{FnSig, VariantInfo, TypeScheme};
|
||||
use middle::ty::{Disr, ParamTy, ParameterEnvironment};
|
||||
use middle::ty::{mod, HasProjectionTypes, Ty};
|
||||
use middle::ty::{mod, HasProjectionTypes, RegionEscape, Ty};
|
||||
use middle::ty::liberate_late_bound_regions;
|
||||
use middle::ty::{MethodCall, MethodCallee, MethodMap, ObjectCastMap};
|
||||
use middle::ty_fold::{TypeFolder, TypeFoldable};
|
||||
@ -351,11 +351,18 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn normalize_associated_types_in<T>(&self, span: Span, body_id: ast::NodeId, value: &T) -> T
|
||||
where T : TypeFoldable<'tcx> + Clone + HasProjectionTypes
|
||||
fn normalize_associated_types_in<T>(&self,
|
||||
typer: &mc::Typer<'tcx>,
|
||||
span: Span,
|
||||
body_id: ast::NodeId,
|
||||
value: &T)
|
||||
-> T
|
||||
where T : TypeFoldable<'tcx> + Clone + HasProjectionTypes + Repr<'tcx>
|
||||
{
|
||||
let mut fulfillment_cx = self.fulfillment_cx.borrow_mut();
|
||||
assoc::normalize_associated_types_in(&self.infcx,
|
||||
&self.param_env,
|
||||
typer,
|
||||
&mut *fulfillment_cx, span,
|
||||
body_id,
|
||||
value)
|
||||
@ -439,7 +446,7 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||
let fn_sig =
|
||||
liberate_late_bound_regions(ccx.tcx, CodeExtent::from_node_id(body.id), &fn_sig);
|
||||
let fn_sig =
|
||||
inh.normalize_associated_types_in(body.span, body.id, &fn_sig);
|
||||
inh.normalize_associated_types_in(ccx.tcx, body.span, body.id, &fn_sig);
|
||||
|
||||
let fcx = check_fn(ccx, fn_ty.unsafety, id, &fn_sig,
|
||||
decl, id, body, &inh);
|
||||
@ -1191,6 +1198,8 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
impl_sig.subst(tcx, impl_to_skol_substs);
|
||||
let impl_sig =
|
||||
assoc::normalize_associated_types_in(&infcx,
|
||||
&impl_param_env,
|
||||
infcx.tcx,
|
||||
&mut fulfillment_cx,
|
||||
impl_m_span,
|
||||
impl_m_body_id,
|
||||
@ -1210,6 +1219,8 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
trait_sig.subst(tcx, &trait_to_skol_substs);
|
||||
let trait_sig =
|
||||
assoc::normalize_associated_types_in(&infcx,
|
||||
&impl_param_env,
|
||||
infcx.tcx,
|
||||
&mut fulfillment_cx,
|
||||
impl_m_span,
|
||||
impl_m_body_id,
|
||||
@ -1742,10 +1753,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
result
|
||||
}
|
||||
|
||||
fn normalize_associated_types_in<T>(&self, span: Span, value: &T) -> T
|
||||
where T : TypeFoldable<'tcx> + Clone + HasProjectionTypes
|
||||
/// As `instantiate_type_scheme`, but for the bounds found in a
|
||||
/// generic type scheme.
|
||||
fn instantiate_bounds(&self,
|
||||
span: Span,
|
||||
substs: &Substs<'tcx>,
|
||||
generics: &ty::Generics<'tcx>)
|
||||
-> ty::GenericBounds<'tcx>
|
||||
{
|
||||
self.inh.normalize_associated_types_in(span, self.body_id, value)
|
||||
ty::GenericBounds {
|
||||
predicates: self.instantiate_type_scheme(span, substs, &generics.predicates)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn normalize_associated_types_in<T>(&self, span: Span, value: &T) -> T
|
||||
where T : TypeFoldable<'tcx> + Clone + HasProjectionTypes + Repr<'tcx>
|
||||
{
|
||||
self.inh.normalize_associated_types_in(self, span, self.body_id, value)
|
||||
}
|
||||
|
||||
fn normalize_associated_type(&self,
|
||||
@ -1760,6 +1785,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
self.inh.fulfillment_cx
|
||||
.borrow_mut()
|
||||
.normalize_projection_type(self.infcx(),
|
||||
&self.inh.param_env,
|
||||
self,
|
||||
ty::ProjectionTy {
|
||||
trait_ref: trait_ref,
|
||||
item_name: item_name,
|
||||
@ -1853,7 +1880,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
span,
|
||||
&type_scheme.generics);
|
||||
let bounds =
|
||||
type_scheme.generics.to_bounds(self.tcx(), &substs);
|
||||
self.instantiate_bounds(span, &substs, &type_scheme.generics);
|
||||
self.add_obligations_for_parameters(
|
||||
traits::ObligationCause::new(
|
||||
span,
|
||||
@ -1930,7 +1957,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
self.inh.fulfillment_cx
|
||||
.borrow_mut()
|
||||
.register_predicate(self.infcx(), obligation);
|
||||
.register_predicate_obligation(self.infcx(), obligation);
|
||||
}
|
||||
|
||||
pub fn to_ty(&self, ast_t: &ast::Ty) -> Ty<'tcx> {
|
||||
@ -4456,7 +4483,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
if let Some(did) = did {
|
||||
let polytype = ty::lookup_item_type(tcx, did);
|
||||
let substs = Substs::new_type(vec![idx_type], vec![]);
|
||||
let bounds = polytype.generics.to_bounds(tcx, &substs);
|
||||
let bounds = fcx.instantiate_bounds(expr.span, &substs, &polytype.generics);
|
||||
fcx.add_obligations_for_parameters(
|
||||
traits::ObligationCause::new(expr.span,
|
||||
fcx.body_id,
|
||||
@ -5271,31 +5298,20 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
}
|
||||
|
||||
// The things we are substituting into the type should not contain
|
||||
// escaping late-bound regions.
|
||||
// escaping late-bound regions, and nor should the base type scheme.
|
||||
assert!(!substs.has_regions_escaping_depth(0));
|
||||
assert!(!type_scheme.has_escaping_regions());
|
||||
|
||||
// In the case of static items taken from impls, there may be
|
||||
// late-bound regions associated with the impl (not declared on
|
||||
// the fn itself). Those should be replaced with fresh variables
|
||||
// now. These can appear either on the type being referenced, or
|
||||
// on the associated bounds.
|
||||
let bounds = type_scheme.generics.to_bounds(fcx.tcx(), &substs);
|
||||
let (ty_late_bound, bounds) =
|
||||
fcx.infcx().replace_late_bound_regions_with_fresh_var(
|
||||
span,
|
||||
infer::FnCall,
|
||||
&ty::Binder((type_scheme.ty, bounds))).0;
|
||||
|
||||
debug!("after late-bounds have been replaced: ty_late_bound={}", ty_late_bound.repr(fcx.tcx()));
|
||||
debug!("after late-bounds have been replaced: bounds={}", bounds.repr(fcx.tcx()));
|
||||
|
||||
// Add all the obligations that are required, substituting and
|
||||
// normalized appropriately.
|
||||
let bounds = fcx.instantiate_bounds(span, &substs, &type_scheme.generics);
|
||||
fcx.add_obligations_for_parameters(
|
||||
traits::ObligationCause::new(span, fcx.body_id, traits::ItemObligation(def.def_id())),
|
||||
&bounds);
|
||||
|
||||
// Substitute the values for the type parameters into the type of
|
||||
// the referenced item.
|
||||
let ty_substituted = fcx.instantiate_type_scheme(span, &substs, &ty_late_bound);
|
||||
let ty_substituted = fcx.instantiate_type_scheme(span, &substs, &type_scheme.ty);
|
||||
|
||||
fcx.write_ty(node_id, ty_substituted);
|
||||
fcx.write_substs(node_id, ty::ItemSubsts { substs: substs });
|
||||
|
@ -269,7 +269,8 @@ impl<'cx,'tcx> BoundsChecker<'cx,'tcx> {
|
||||
pub fn check_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>) {
|
||||
let trait_def = ty::lookup_trait_def(self.fcx.tcx(), trait_ref.def_id);
|
||||
|
||||
let bounds = trait_def.generics.to_bounds(self.tcx(), trait_ref.substs);
|
||||
let bounds = self.fcx.instantiate_bounds(self.span, trait_ref.substs, &trait_def.generics);
|
||||
|
||||
self.fcx.add_obligations_for_parameters(
|
||||
traits::ObligationCause::new(
|
||||
self.span,
|
||||
@ -319,13 +320,14 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> {
|
||||
ty::ty_struct(type_id, substs) |
|
||||
ty::ty_enum(type_id, substs) => {
|
||||
let type_scheme = ty::lookup_item_type(self.fcx.tcx(), type_id);
|
||||
let bounds = self.fcx.instantiate_bounds(self.span, substs, &type_scheme.generics);
|
||||
|
||||
if self.binding_count == 0 {
|
||||
self.fcx.add_obligations_for_parameters(
|
||||
traits::ObligationCause::new(self.span,
|
||||
self.fcx.body_id,
|
||||
traits::ItemObligation(type_id)),
|
||||
&type_scheme.generics.to_bounds(self.tcx(), substs));
|
||||
&bounds);
|
||||
} else {
|
||||
// There are two circumstances in which we ignore
|
||||
// region obligations.
|
||||
@ -349,7 +351,6 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> {
|
||||
//
|
||||
// (I believe we should do the same for traits, but
|
||||
// that will require an RFC. -nmatsakis)
|
||||
let bounds = type_scheme.generics.to_bounds(self.tcx(), substs);
|
||||
let bounds = filter_to_trait_obligations(bounds);
|
||||
self.fcx.add_obligations_for_parameters(
|
||||
traits::ObligationCause::new(self.span,
|
||||
|
46
src/test/compile-fail/associated-types-issue-20346.rs
Normal file
46
src/test/compile-fail/associated-types-issue-20346.rs
Normal file
@ -0,0 +1,46 @@
|
||||
// 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 reliably check the value of the associated type.
|
||||
|
||||
#![crate_type = "lib"]
|
||||
#![feature(associated_types)]
|
||||
#![no_implicit_prelude]
|
||||
|
||||
use std::option::Option::{None, Some, mod};
|
||||
use std::vec::Vec;
|
||||
|
||||
trait Iterator {
|
||||
type Item;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item>;
|
||||
}
|
||||
|
||||
fn is_iterator_of<A, I: Iterator<Item=A>>(_: &I) {}
|
||||
|
||||
struct Adapter<I> {
|
||||
iter: I,
|
||||
found_none: bool,
|
||||
}
|
||||
|
||||
impl<T, I> Iterator for Adapter<I> where I: Iterator<Item=Option<T>> {
|
||||
type Item = T;
|
||||
|
||||
fn next(&mut self) -> Option<T> {
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
fn test_adapter<T, I: Iterator<Item=Option<T>>>(it: I) {
|
||||
is_iterator_of::<Option<T>, _>(&it); // Sanity check
|
||||
let adapter = Adapter { iter: it, found_none: false };
|
||||
is_iterator_of::<T, _>(&adapter); // OK
|
||||
is_iterator_of::<Option<T>, _>(&adapter); //~ ERROR type mismatch
|
||||
}
|
@ -25,11 +25,30 @@ pub fn f2<T: Foo>(a: T) -> T::A {
|
||||
panic!();
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
f1(2i, 4i); //~ ERROR expected uint, found int
|
||||
f1(2i, 4u);
|
||||
f1(2u, 4u); //~ ERROR the trait `Foo` is not implemented
|
||||
f1(2u, 4i); //~ ERROR the trait `Foo` is not implemented
|
||||
|
||||
let _: int = f2(2i); //~ERROR expected `int`, found `uint`
|
||||
pub fn f1_int_int() {
|
||||
f1(2i, 4i);
|
||||
//~^ ERROR expected uint, found int
|
||||
}
|
||||
|
||||
pub fn f1_int_uint() {
|
||||
f1(2i, 4u);
|
||||
}
|
||||
|
||||
pub fn f1_uint_uint() {
|
||||
f1(2u, 4u);
|
||||
//~^ ERROR the trait `Foo` is not implemented
|
||||
//~| ERROR the trait `Foo` is not implemented
|
||||
}
|
||||
|
||||
pub fn f1_uint_int() {
|
||||
f1(2u, 4i);
|
||||
//~^ ERROR the trait `Foo` is not implemented
|
||||
//~| ERROR the trait `Foo` is not implemented
|
||||
}
|
||||
|
||||
pub fn f2_int() {
|
||||
let _: int = f2(2i);
|
||||
//~^ ERROR expected `int`, found `uint`
|
||||
}
|
||||
|
||||
pub fn main() { }
|
||||
|
@ -29,9 +29,10 @@ fn bar<'a, 'b, I : for<'x> Foo<&'x int>>(
|
||||
x: <I as Foo<&'a int>>::A,
|
||||
y: <I as Foo<&'b int>>::A,
|
||||
cond: bool)
|
||||
{ //~ ERROR cannot infer
|
||||
{
|
||||
// x and y here have two distinct lifetimes:
|
||||
let z: I::A = if cond { x } else { y };
|
||||
//~^ ERROR cannot infer
|
||||
}
|
||||
|
||||
pub fn main() {}
|
||||
|
28
src/test/compile-fail/associated-types-unconstrained.rs
Normal file
28
src/test/compile-fail/associated-types-unconstrained.rs
Normal file
@ -0,0 +1,28 @@
|
||||
// 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.
|
||||
|
||||
// Check that an associated type cannot be bound in an expression path.
|
||||
|
||||
#![feature(associated_types)]
|
||||
|
||||
trait Foo {
|
||||
type A;
|
||||
fn bar() -> int;
|
||||
}
|
||||
|
||||
impl Foo for int {
|
||||
type A = uint;
|
||||
fn bar() -> int { 42 }
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let x: int = Foo::bar();
|
||||
//~^ ERROR type annotations required
|
||||
}
|
@ -33,7 +33,7 @@ where T : Convert<U>
|
||||
}
|
||||
|
||||
fn a() {
|
||||
test(22_i32, 44); //~ ERROR unable to infer
|
||||
test(22_i32, 44); //~ ERROR type annotations required
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
58
src/test/run-pass/associated-types-impl-redirect.rs
Normal file
58
src/test/run-pass/associated-types-impl-redirect.rs
Normal file
@ -0,0 +1,58 @@
|
||||
// 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 how resolving a projection interacts with inference. In this
|
||||
// case, we were eagerly unifying the type variable for the iterator
|
||||
// type with `I` from the where clause, ignoring the in-scope `impl`
|
||||
// for `ByRef`. The right answer was to consider the result ambiguous
|
||||
// until more type information was available.
|
||||
|
||||
// ignore-pretty -- FIXME(#17362)
|
||||
|
||||
#![feature(associated_types, lang_items, unboxed_closures)]
|
||||
#![no_implicit_prelude]
|
||||
|
||||
use std::option::Option::{None, Some, mod};
|
||||
|
||||
trait Iterator {
|
||||
type Item;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item>;
|
||||
}
|
||||
|
||||
trait IteratorExt: Iterator {
|
||||
fn by_ref(&mut self) -> ByRef<Self> {
|
||||
ByRef(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> IteratorExt for I where I: Iterator {}
|
||||
|
||||
struct ByRef<'a, I: 'a + Iterator>(&'a mut I);
|
||||
|
||||
impl<'a, I: Iterator> Iterator for ByRef<'a, I> {
|
||||
type Item = I::Item;
|
||||
|
||||
fn next(&mut self) -> Option< <I as Iterator>::Item > {
|
||||
self.0.next()
|
||||
}
|
||||
}
|
||||
|
||||
fn is_iterator_of<A, I: Iterator<Item=A>>(_: &I) {}
|
||||
|
||||
fn test<A, I: Iterator<Item=A>>(mut it: I) {
|
||||
is_iterator_of::<A, _>(&it.by_ref());
|
||||
}
|
||||
|
||||
fn test2<A, I1: Iterator<Item=A>, I2: Iterator<Item=I1::Item>>(mut it: I2) {
|
||||
is_iterator_of::<A, _>(&it)
|
||||
}
|
||||
|
||||
fn main() { }
|
17
src/test/run-pass/associated-types-issue-20371.rs
Normal file
17
src/test/run-pass/associated-types-issue-20371.rs
Normal file
@ -0,0 +1,17 @@
|
||||
// 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 are able to have an impl that defines an associated type
|
||||
// before the actual trait.
|
||||
|
||||
#![feature(associated_types)]
|
||||
impl X for f64 { type Y = int; }
|
||||
trait X {type Y; }
|
||||
fn main() {}
|
@ -0,0 +1,41 @@
|
||||
// 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 normalize associated types that appear in bounds; if
|
||||
// we didn't, the call to `self.split2()` fails to type check.
|
||||
|
||||
#![feature(associated_types)]
|
||||
|
||||
struct Splits<'a, T, P>;
|
||||
struct SplitsN<I>;
|
||||
|
||||
trait SliceExt2 for Sized? {
|
||||
type Item;
|
||||
|
||||
fn split2<'a, P>(&'a self, pred: P) -> Splits<'a, Self::Item, P>
|
||||
where P: FnMut(&Self::Item) -> bool;
|
||||
fn splitn2<'a, P>(&'a self, n: uint, pred: P) -> SplitsN<Splits<'a, Self::Item, P>>
|
||||
where P: FnMut(&Self::Item) -> bool;
|
||||
}
|
||||
|
||||
impl<T> SliceExt2 for [T] {
|
||||
type Item = T;
|
||||
|
||||
fn split2<P>(&self, pred: P) -> Splits<T, P> where P: FnMut(&T) -> bool {
|
||||
loop {}
|
||||
}
|
||||
|
||||
fn splitn2<P>(&self, n: uint, pred: P) -> SplitsN<Splits<T, P>> where P: FnMut(&T) -> bool {
|
||||
SliceExt2::split2(self, pred);
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() { }
|
@ -0,0 +1,33 @@
|
||||
// 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 correctly handle projection bounds appearing in the
|
||||
// supertrait list (and in conjunction with overloaded operators). In
|
||||
// this case, the `Result=Self` binding in the supertrait listing of
|
||||
// `Int` was being ignored.
|
||||
|
||||
#![feature(associated_types)]
|
||||
|
||||
trait Not {
|
||||
type Result;
|
||||
|
||||
fn not(self) -> Self::Result;
|
||||
}
|
||||
|
||||
trait Int: Not<Result=Self> {
|
||||
fn count_ones(self) -> uint;
|
||||
fn count_zeros(self) -> uint {
|
||||
// neither works
|
||||
let x: Self = self.not();
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
fn main() { }
|
@ -0,0 +1,54 @@
|
||||
// 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 how resolving a projection interacts with inference. In this
|
||||
// case, we were eagerly unifying the type variable for the iterator
|
||||
// type with `I` from the where clause, ignoring the in-scope `impl`
|
||||
// for `ByRef`. The right answer was to consider the result ambiguous
|
||||
// until more type information was available.
|
||||
|
||||
// ignore-pretty -- FIXME(#17362) pretty prints with `<<` which lexes wrong
|
||||
|
||||
#![feature(associated_types, lang_items, unboxed_closures)]
|
||||
#![no_implicit_prelude]
|
||||
|
||||
use std::option::Option::{None, Some, mod};
|
||||
|
||||
trait Iterator {
|
||||
type Item;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item>;
|
||||
}
|
||||
|
||||
trait IteratorExt: Iterator {
|
||||
fn by_ref(&mut self) -> ByRef<Self> {
|
||||
ByRef(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> IteratorExt for I where I: Iterator {}
|
||||
|
||||
struct ByRef<'a, I: 'a + Iterator>(&'a mut I);
|
||||
|
||||
impl<'a, A, I> Iterator for ByRef<'a, I> where I: Iterator<Item=A> {
|
||||
type Item = A;
|
||||
|
||||
fn next(&mut self) -> Option< <I as Iterator>::Item > {
|
||||
self.0.next()
|
||||
}
|
||||
}
|
||||
|
||||
fn is_iterator_of<A, I: Iterator<Item=A>>(_: &I) {}
|
||||
|
||||
fn test<A, I: Iterator<Item=A>>(mut it: I) {
|
||||
is_iterator_of::<A, _>(&it.by_ref());
|
||||
}
|
||||
|
||||
fn main() { }
|
Loading…
Reference in New Issue
Block a user