提交 6cb425d9 编写于 作者: N Niko Matsakis

Rework normalization so that it works recursively, since the types extracted...

Rework normalization so that it works recursively, since the types extracted from an impl are potentially in need of normalization.  This also lays groundwork for further cleanup in other areas by disconnecting normalization from the fulfillment context.
上级 0aa7ba9f
......@@ -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,25 +159,16 @@ 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 self_ty = trait_ref.self_ty();
let predicate = infcx.resolve_type_vars_if_possible(&obligation.predicate);
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));
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)) {
......@@ -202,23 +187,22 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
// 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()) {
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",
"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",
trait_ref.user_string(infcx.tcx),
self_ty.user_string(infcx.tcx)).as_slice());
"type annotations required: cannot resolve `{}`",
predicate.user_string(infcx.tcx)).as_slice());
note_obligation_cause(infcx, obligation);
}
}
......@@ -233,6 +217,19 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
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);
}
}
}
}
fn note_obligation_cause<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
......@@ -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::CodeProjectionError;
use super::CodeSelectionError;
use super::FulfillmentError;
use super::Obligation;
use super::ObligationCause;
use super::PredicateObligation;
use super::project;
......@@ -110,6 +109,8 @@ pub fn new() -> 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 @@ pub fn normalize_projection_type<'a>(&mut self,
// 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);
for obligation in normalized.obligations.into_iter() {
self.register_predicate_obligation(infcx, obligation);
}
debug!("normalize_associated_type: result={}", ty_var.repr(infcx.tcx));
debug!("normalize_associated_type: result={}", normalized.value.repr(infcx.tcx));
ty_var
normalized.value
}
pub fn register_builtin_bound<'a>(&mut self,
......@@ -143,7 +142,7 @@ pub fn register_builtin_bound<'a>(&mut self,
{
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 @@ pub fn register_region_obligation<'a>(&mut self,
register_region_obligation(infcx.tcx, t_a, r_b, cause, &mut self.region_obligations);
}
pub fn register_predicate<'a>(&mut self,
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 @@ fn select<'a>(&mut self,
// 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");
Err(err) => {
errors.push(
FulfillmentError::new(
obligation.clone(),
CodeSelectionError(Unimplemented)));
true
}
}
Err(project::ProjectionError::MismatchedTypes(e)) => {
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 @@
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 @@ pub fn new(cause: ObligationCause<'tcx>,
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 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 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 project_and_unify_type(selcx, &skol_obligation) {
Ok(Some(obligations)) => {
match infcx.leak_check(&skol_map, snapshot) {
Ok(()) => Ok(()),
Err(e) => Err(ProjectionError::MismatchedTypes(MismatchedProjectionTypes{err: e})),
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,48 +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_object_type(selcx,
assemble_candidates_from_object_type(selcx,
obligation,
&mut candidates);
if candidates.vec.is_empty() {
let () = assemble_candidates_from_param_env(selcx,
assemble_candidates_from_param_env(selcx,
obligation,
&mut candidates);
let () = try!(assemble_candidates_from_impls(selcx,
if let Err(e) = assemble_candidates_from_impls(selcx,
obligation,
&mut candidates));
&mut candidates) {
return Err(ProjectionTyError::TraitSelectionError(e));
}
}
debug!("{} candidates, ambiguous={}",
......@@ -146,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)))
}
}
}
......@@ -232,7 +478,7 @@ fn assemble_candidates_from_impls<'cx,'tcx>(
selcx: &mut SelectionContext<'cx,'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<...>`:
......@@ -249,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);
}
};
......@@ -303,7 +549,7 @@ fn confirm_candidate<'cx,'tcx>(
selcx: &mut SelectionContext<'cx,'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
candidate: ProjectionTyCandidate<'tcx>)
-> ProjectionResult<'tcx, Ty<'tcx>>
-> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
{
let infcx = selcx.infcx();
......@@ -311,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(
......@@ -338,7 +584,7 @@ fn confirm_candidate<'cx,'tcx>(
}
}
projection.ty
(projection.ty, vec!())
}
ProjectionTyCandidate::Impl(impl_vtable) => {
......@@ -363,10 +609,8 @@ fn confirm_candidate<'cx,'tcx>(
break;
}
// TODO we need the impl_vtable items here
match impl_ty {
Some(ty) => ty,
Some(ty) => (ty, impl_vtable.nested.to_vec()),
None => {
selcx.tcx().sess.span_bug(
obligation.cause.span,
......@@ -376,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)),
}
}
......@@ -406,4 +644,3 @@ fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
}
}
}
......@@ -960,7 +960,7 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
// iterating early.
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, &param_env, tcx) {
Ok(()) => { }
......
......@@ -16,7 +16,7 @@
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};
......@@ -32,7 +32,6 @@
use syntax::ast_util::{local_def, PostExpansionMethod};
use syntax::attr;
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 +309,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 +323,15 @@ 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, &param_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));
result
}
struct AssociatedTypeNormalizer<'a,'tcx:'a> {
selcx: &'a mut traits::SelectionContext<'a,'tcx>,
}
assert_eq!(obligations.len(), 0); // TODO not good enough
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)
}
}
}
result
}
......@@ -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
}
......@@ -350,11 +350,18 @@ fn new(tcx: &'a ty::ctxt<'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)
......@@ -438,7 +445,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);
......@@ -1190,6 +1197,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,
......@@ -1209,6 +1218,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,
......@@ -1756,9 +1767,9 @@ fn instantiate_bounds(&self,
fn normalize_associated_types_in<T>(&self, span: Span, value: &T) -> T
where T : TypeFoldable<'tcx> + Clone + HasProjectionTypes
where T : TypeFoldable<'tcx> + Clone + HasProjectionTypes + Repr<'tcx>
{
self.inh.normalize_associated_types_in(span, self.body_id, value)
self.inh.normalize_associated_types_in(self, span, self.body_id, value)
}
fn normalize_associated_type(&self,
......@@ -1773,6 +1784,8 @@ fn normalize_associated_type(&self,
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,
......@@ -1943,7 +1956,7 @@ pub fn register_predicate(&self,
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> {
......
......@@ -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
pub fn f1_int_int() {
f1(2i, 4i);
//~^ ERROR expected uint, found int
}
pub fn f1_int_uint() {
f1(2i, 4u);
f1(2u, 4u); //~ ERROR the trait `Foo` is not implemented
f1(2u, 4i); //~ ERROR the trait `Foo` is not implemented
}
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
}
let _: int = f2(2i); //~ERROR expected `int`, found `uint`
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() {}
// 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 @@ fn test<T,U>(_: T, _: U)
}
fn a() {
test(22_i32, 44); //~ ERROR unable to infer
test(22_i32, 44); //~ ERROR type annotations required
}
fn main() {}
// 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() { }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册