Skip to content

A few fixes for associated types #26147

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 18, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 34 additions & 64 deletions src/librustc/middle/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ pub enum Vtable<'tcx, N> {
/// Vtable automatically generated for a closure. The def ID is the ID
/// of the closure expression. This is a `VtableImpl` in spirit, but the
/// impl is generated by the compiler and does not appear in the source.
VtableClosure(ast::DefId, subst::Substs<'tcx>),
VtableClosure(VtableClosureData<'tcx, N>),

/// Same as above, but for a fn pointer type with the given signature.
VtableFnPointer(ty::Ty<'tcx>),
Expand All @@ -268,7 +268,16 @@ pub struct VtableImplData<'tcx, N> {
pub nested: Vec<N>
}

#[derive(Debug,Clone)]
#[derive(Clone, PartialEq, Eq)]
pub struct VtableClosureData<'tcx, N> {
pub closure_def_id: ast::DefId,
pub substs: subst::Substs<'tcx>,
/// Nested obligations. This can be non-empty if the closure
/// signature contains associated types.
pub nested: Vec<N>
}

#[derive(Debug, Clone)]
pub struct VtableDefaultImplData<N> {
pub trait_def_id: ast::DefId,
pub nested: Vec<N>
Expand Down Expand Up @@ -304,12 +313,12 @@ pub fn predicates_for_generics<'tcx>(tcx: &ty::ctxt<'tcx>,
/// `bound` or is not known to meet bound (note that this is
/// conservative towards *no impl*, which is the opposite of the
/// `evaluate` methods).
pub fn evaluate_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
typer: &ty::ClosureTyper<'tcx>,
ty: Ty<'tcx>,
bound: ty::BuiltinBound,
span: Span)
-> SelectionResult<'tcx, ()>
pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
typer: &ty::ClosureTyper<'tcx>,
ty: Ty<'tcx>,
bound: ty::BuiltinBound,
span: Span)
-> bool
{
debug!("type_known_to_meet_builtin_bound(ty={}, bound={:?})",
ty.repr(infcx.tcx),
Expand All @@ -327,61 +336,18 @@ pub fn evaluate_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
// Note: we only assume something is `Copy` if we can
// *definitively* show that it implements `Copy`. Otherwise,
// assume it is move; linear is always ok.
let result = match fulfill_cx.select_all_or_error(infcx, typer) {
Ok(()) => Ok(Some(())), // Success, we know it implements Copy.
Err(errors) => {
// If there were any hard errors, propagate an arbitrary
// one of those. If no hard errors at all, report
// ambiguity.
let sel_error =
errors.iter()
.filter_map(|err| {
match err.code {
CodeAmbiguity => None,
CodeSelectionError(ref e) => Some(e.clone()),
CodeProjectionError(_) => {
infcx.tcx.sess.span_bug(
span,
"projection error while selecting?")
}
}
})
.next();
match sel_error {
None => { Ok(None) }
Some(e) => { Err(e) }
}
}
};

debug!("type_known_to_meet_builtin_bound: ty={} bound={:?} result={:?}",
ty.repr(infcx.tcx),
bound,
result);

result
}

pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
typer: &ty::ClosureTyper<'tcx>,
ty: Ty<'tcx>,
bound: ty::BuiltinBound,
span: Span)
-> bool
{
match evaluate_builtin_bound(infcx, typer, ty, bound, span) {
Ok(Some(())) => {
// definitely impl'd
match fulfill_cx.select_all_or_error(infcx, typer) {
Ok(()) => {
debug!("type_known_to_meet_builtin_bound: ty={} bound={:?} success",
ty.repr(infcx.tcx),
bound);
true
}
Ok(None) => {
// ambiguous: if coherence check was successful, shouldn't
// happen, but we might have reported an error and been
// soldering on, so just treat this like not implemented
false
}
Err(_) => {
// errors: not implemented.
Err(e) => {
debug!("type_known_to_meet_builtin_bound: ty={} bound={:?} errors={}",
ty.repr(infcx.tcx),
bound,
e.repr(infcx.tcx));
false
}
}
Expand Down Expand Up @@ -545,8 +511,8 @@ impl<'tcx, N> Vtable<'tcx, N> {
VtableParam(n) => n,
VtableBuiltin(i) => i.nested,
VtableDefaultImpl(d) => d.nested,
VtableObject(_) | VtableFnPointer(..) |
VtableClosure(..) => vec![]
VtableClosure(c) => c.nested,
VtableObject(_) | VtableFnPointer(..) => vec![]
}
}

Expand All @@ -567,7 +533,11 @@ impl<'tcx, N> Vtable<'tcx, N> {
nested: d.nested.into_iter().map(f).collect()
}),
VtableFnPointer(f) => VtableFnPointer(f),
VtableClosure(d, s) => VtableClosure(d, s),
VtableClosure(c) => VtableClosure(VtableClosureData {
closure_def_id: c.closure_def_id,
substs: c.substs,
nested: c.nested.into_iter().map(f).collect()
})
}
}
}
Expand Down
44 changes: 30 additions & 14 deletions src/librustc/middle/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ use super::ObligationCause;
use super::PredicateObligation;
use super::SelectionContext;
use super::SelectionError;
use super::VtableClosureData;
use super::VtableImplData;
use super::util;

use middle::infer;
use middle::subst::{Subst, Substs};
use middle::subst::Subst;
use middle::ty::{self, AsPredicate, ReferencesError, RegionEscape,
HasProjectionTypes, ToPolyTraitRef, Ty};
use middle::ty_fold::{self, TypeFoldable, TypeFolder};
use syntax::ast;
use syntax::parse::token;
use util::common::FN_OUTPUT_NAME;
use util::ppaux::Repr;
Expand Down Expand Up @@ -57,7 +57,7 @@ pub struct MismatchedProjectionTypes<'tcx> {
enum ProjectionTyCandidate<'tcx> {
ParamEnv(ty::PolyProjectionPredicate<'tcx>),
Impl(VtableImplData<'tcx, PredicateObligation<'tcx>>),
Closure(ast::DefId, Substs<'tcx>),
Closure(VtableClosureData<'tcx, PredicateObligation<'tcx>>),
FnPointer(Ty<'tcx>),
}

Expand Down Expand Up @@ -162,11 +162,16 @@ fn consider_unification_despite_ambiguity<'cx,'tcx>(selcx: &mut SelectionContext
self_ty,
&closure_type.sig,
util::TupleArgumentsFlag::No);
// We don't have to normalize the return type here - this is only
// reached for TyClosure: Fn inputs where the closure kind is
// still unknown, which should only occur in typeck where the
// closure type is already normalized.
let (ret_type, _) =
infcx.replace_late_bound_regions_with_fresh_var(
obligation.cause.span,
infer::AssocTypeProjection(obligation.predicate.projection_ty.item_name),
&ty::Binder(ret_type));

debug!("consider_unification_despite_ambiguity: ret_type={:?}",
ret_type.repr(selcx.tcx()));
let origin = infer::RelateOutputImplTypes(obligation.cause.span);
Expand Down Expand Up @@ -686,9 +691,9 @@ fn assemble_candidates_from_impls<'cx,'tcx>(
selcx, obligation, obligation_trait_ref, candidate_set,
data.object_ty);
}
super::VtableClosure(closure_def_id, substs) => {
super::VtableClosure(data) => {
candidate_set.vec.push(
ProjectionTyCandidate::Closure(closure_def_id, substs));
ProjectionTyCandidate::Closure(data));
}
super::VtableFnPointer(fn_type) => {
candidate_set.vec.push(
Expand Down Expand Up @@ -755,8 +760,8 @@ fn confirm_candidate<'cx,'tcx>(
confirm_impl_candidate(selcx, obligation, impl_vtable)
}

ProjectionTyCandidate::Closure(def_id, substs) => {
confirm_closure_candidate(selcx, obligation, def_id, &substs)
ProjectionTyCandidate::Closure(closure_vtable) => {
confirm_closure_candidate(selcx, obligation, closure_vtable)
}

ProjectionTyCandidate::FnPointer(fn_type) => {
Expand All @@ -779,13 +784,24 @@ fn confirm_fn_pointer_candidate<'cx,'tcx>(
fn confirm_closure_candidate<'cx,'tcx>(
selcx: &mut SelectionContext<'cx,'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
closure_def_id: ast::DefId,
substs: &Substs<'tcx>)
vtable: VtableClosureData<'tcx, PredicateObligation<'tcx>>)
-> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
{
let closure_typer = selcx.closure_typer();
let closure_type = closure_typer.closure_type(closure_def_id, substs);
confirm_callable_candidate(selcx, obligation, &closure_type.sig, util::TupleArgumentsFlag::No)
let closure_type = closure_typer.closure_type(vtable.closure_def_id, &vtable.substs);
let Normalized {
value: closure_type,
mut obligations
} = normalize_with_depth(selcx,
obligation.cause.clone(),
obligation.recursion_depth+1,
&closure_type);
let (ty, mut cc_obligations) = confirm_callable_candidate(selcx,
obligation,
&closure_type.sig,
util::TupleArgumentsFlag::No);
obligations.append(&mut cc_obligations);
(ty, obligations)
}

fn confirm_callable_candidate<'cx,'tcx>(
Expand All @@ -797,7 +813,7 @@ fn confirm_callable_candidate<'cx,'tcx>(
{
let tcx = selcx.tcx();

debug!("confirm_closure_candidate({},{})",
debug!("confirm_callable_candidate({},{})",
obligation.repr(tcx),
fn_sig.repr(tcx));

Expand Down Expand Up @@ -921,8 +937,8 @@ impl<'tcx> Repr<'tcx> for ProjectionTyCandidate<'tcx> {
format!("ParamEnv({})", data.repr(tcx)),
ProjectionTyCandidate::Impl(ref data) =>
format!("Impl({})", data.repr(tcx)),
ProjectionTyCandidate::Closure(ref a, ref b) =>
format!("Closure(({},{}))", a.repr(tcx), b.repr(tcx)),
ProjectionTyCandidate::Closure(ref data) =>
format!("Closure({})", data.repr(tcx)),
ProjectionTyCandidate::FnPointer(a) =>
format!("FnPointer(({}))", a.repr(tcx)),
}
Expand Down
72 changes: 53 additions & 19 deletions src/librustc/middle/traits/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ use super::Selection;
use super::SelectionResult;
use super::{VtableBuiltin, VtableImpl, VtableParam, VtableClosure,
VtableFnPointer, VtableObject, VtableDefaultImpl};
use super::{VtableImplData, VtableObjectData, VtableBuiltinData, VtableDefaultImplData};
use super::{VtableImplData, VtableObjectData, VtableBuiltinData,
VtableClosureData, VtableDefaultImplData};
use super::object_safety;
use super::util;

Expand Down Expand Up @@ -355,7 +356,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
};
assert!(!substs.has_escaping_regions());

let closure_trait_ref = self.closure_trait_ref(obligation, closure_def_id, substs);
// It is OK to call the unnormalized variant here - this is only
// reached for TyClosure: Fn inputs where the closure kind is
// still unknown, which should only occur in typeck where the
// closure type is already normalized.
let closure_trait_ref = self.closure_trait_ref_unnormalized(obligation,
closure_def_id,
substs);

match self.confirm_poly_trait_refs(obligation.cause.clone(),
obligation.predicate.to_poly_trait_ref(),
closure_trait_ref) {
Expand Down Expand Up @@ -2001,8 +2009,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}

ClosureCandidate(closure_def_id, substs) => {
try!(self.confirm_closure_candidate(obligation, closure_def_id, &substs));
Ok(VtableClosure(closure_def_id, substs))
let vtable_closure =
try!(self.confirm_closure_candidate(obligation, closure_def_id, &substs));
Ok(VtableClosure(vtable_closure))
}

BuiltinObjectCandidate => {
Expand Down Expand Up @@ -2343,24 +2352,33 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation: &TraitObligation<'tcx>,
closure_def_id: ast::DefId,
substs: &Substs<'tcx>)
-> Result<(),SelectionError<'tcx>>
-> Result<VtableClosureData<'tcx, PredicateObligation<'tcx>>,
SelectionError<'tcx>>
{
debug!("confirm_closure_candidate({},{},{})",
obligation.repr(self.tcx()),
closure_def_id.repr(self.tcx()),
substs.repr(self.tcx()));

let trait_ref = self.closure_trait_ref(obligation,
closure_def_id,
substs);
let Normalized {
value: trait_ref,
obligations
} = self.closure_trait_ref(obligation, closure_def_id, substs);

debug!("confirm_closure_candidate(closure_def_id={}, trait_ref={})",
debug!("confirm_closure_candidate(closure_def_id={}, trait_ref={}, obligations={})",
closure_def_id.repr(self.tcx()),
trait_ref.repr(self.tcx()));
trait_ref.repr(self.tcx()),
obligations.repr(self.tcx()));

try!(self.confirm_poly_trait_refs(obligation.cause.clone(),
obligation.predicate.to_poly_trait_ref(),
trait_ref));

self.confirm_poly_trait_refs(obligation.cause.clone(),
obligation.predicate.to_poly_trait_ref(),
trait_ref)
Ok(VtableClosureData {
closure_def_id: closure_def_id,
substs: substs.clone(),
nested: obligations
})
}

/// In the case of closure types and fn pointers,
Expand Down Expand Up @@ -2819,11 +2837,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
}

fn closure_trait_ref(&self,
obligation: &TraitObligation<'tcx>,
closure_def_id: ast::DefId,
substs: &Substs<'tcx>)
-> ty::PolyTraitRef<'tcx>
fn closure_trait_ref_unnormalized(&mut self,
obligation: &TraitObligation<'tcx>,
closure_def_id: ast::DefId,
substs: &Substs<'tcx>)
-> ty::PolyTraitRef<'tcx>
{
let closure_type = self.closure_typer.closure_type(closure_def_id, substs);
let ty::Binder((trait_ref, _)) =
Expand All @@ -2832,7 +2850,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation.predicate.0.self_ty(), // (1)
&closure_type.sig,
util::TupleArgumentsFlag::No);

// (1) Feels icky to skip the binder here, but OTOH we know
// that the self-type is an unboxed closure type and hence is
// in fact unparameterized (or at least does not reference any
Expand All @@ -2842,6 +2859,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ty::Binder(trait_ref)
}

fn closure_trait_ref(&mut self,
obligation: &TraitObligation<'tcx>,
closure_def_id: ast::DefId,
substs: &Substs<'tcx>)
-> Normalized<'tcx, ty::PolyTraitRef<'tcx>>
{
let trait_ref = self.closure_trait_ref_unnormalized(
obligation, closure_def_id, substs);

// A closure signature can contain associated types which
// must be normalized.
normalize_with_depth(self,
obligation.cause.clone(),
obligation.recursion_depth+1,
&trait_ref)
}

/// Returns the obligations that are implied by instantiating an
/// impl or trait. The obligations are substituted and fully
/// normalized. This is used when confirming an impl or default
Expand Down
Loading