Skip to content

Normalize parameter environment with its own substitution #22338

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

Closed
wants to merge 5 commits into from
Closed
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
6 changes: 6 additions & 0 deletions src/librustc/middle/subst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,12 @@ impl<'tcx> Substs<'tcx> {
|r, m_regions| r.with_vec(FnSpace, m_regions));
Substs { types: types, regions: regions }
}

pub fn with_method_from(self, other: &Substs<'tcx>) -> Substs<'tcx> {
let types = other.types.get_slice(FnSpace).to_vec();
let regions = other.regions().get_slice(FnSpace).to_vec();
self.with_method(types, regions)
}
}

impl RegionSubsts {
Expand Down
8 changes: 4 additions & 4 deletions src/librustc/middle/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -413,10 +413,10 @@ pub fn normalize_param_env_or_error<'a,'tcx>(unnormalized_env: ty::ParameterEnvi
}
}

pub fn normalize_param_env<'a,'tcx>(param_env: &ty::ParameterEnvironment<'a,'tcx>,
cause: ObligationCause<'tcx>)
-> Result<ty::ParameterEnvironment<'a,'tcx>,
Vec<FulfillmentError<'tcx>>>
fn normalize_param_env<'a,'tcx>(param_env: &ty::ParameterEnvironment<'a,'tcx>,
cause: ObligationCause<'tcx>)
-> Result<ty::ParameterEnvironment<'a,'tcx>,
Vec<FulfillmentError<'tcx>>>
{
let tcx = param_env.tcx;

Expand Down
57 changes: 29 additions & 28 deletions src/librustc/middle/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use super::VtableImplData;
use super::util;

use middle::infer;
use middle::subst::{Subst, Substs};
use middle::subst::Substs;
use middle::ty::{self, AsPredicate, ReferencesError, RegionEscape,
HasProjectionTypes, ToPolyTraitRef, Ty};
use middle::ty_fold::{self, TypeFoldable, TypeFolder};
Expand Down Expand Up @@ -561,8 +561,7 @@ fn assemble_candidates_from_trait_def<'cx,'tcx>(
};

// If so, extract what we know from the trait and try to come up with a good answer.
let trait_predicates = ty::lookup_predicates(selcx.tcx(), trait_ref.def_id);
let bounds = trait_predicates.instantiate(selcx.tcx(), trait_ref.substs);
let bounds = selcx.instantiate_trait_predicates(&trait_ref);
assemble_candidates_from_predicates(selcx, obligation, obligation_trait_ref,
candidate_set, bounds.predicates.into_vec());
}
Expand Down Expand Up @@ -849,36 +848,38 @@ fn confirm_impl_candidate<'cx,'tcx>(
impl_vtable: VtableImplData<'tcx, PredicateObligation<'tcx>>)
-> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
{
let tcx = selcx.tcx();
// there don't seem to be nicer accessors to these:
let impl_items_map = selcx.tcx().impl_items.borrow();
let impl_or_trait_items_map = selcx.tcx().impl_or_trait_items.borrow();
let impl_items_map = tcx.impl_items.borrow();
let impl_or_trait_items_map = tcx.impl_or_trait_items.borrow();

let impl_items = &impl_items_map[impl_vtable.impl_def_id];
let mut impl_ty = None;
for impl_item in impl_items {
let assoc_type = match impl_or_trait_items_map[impl_item.def_id()] {
ty::TypeTraitItem(ref assoc_type) => assoc_type.clone(),
ty::MethodTraitItem(..) => { continue; }
};

if assoc_type.name != obligation.predicate.item_name {
continue;
}

let impl_poly_ty = ty::lookup_item_type(selcx.tcx(), assoc_type.def_id);
impl_ty = Some(impl_poly_ty.ty.subst(selcx.tcx(), &impl_vtable.substs));
break;
}
let assoc_type =
impl_items
.iter()
.filter_map(|item| {
match impl_or_trait_items_map[item.def_id()] {
ty::TypeTraitItem(ref assoc_type)
if assoc_type.name == obligation.predicate.item_name => {
Some(assoc_type)
}
_ => None
}
})
.next();

match impl_ty {
Some(ty) => (ty, impl_vtable.nested.into_vec()),
match assoc_type {
Some(assoc_type) => {
let impl_ty = selcx.instantiate_assoc_type(assoc_type,
&impl_vtable.substs);
(impl_ty, impl_vtable.nested.into_vec())
},
None => {
// This means that the impl is missing a
// definition for the associated type. This error
// ought to be reported by the type checker method
// `check_impl_items_against_trait`, so here we
// just return ty_err.
(selcx.tcx().types.err, vec!())
// This means that the impl is missing a definition for the
// associated type. This error ought to be reported by the
// type checker method `check_impl_items_against_trait`, so
// here we just return ty_err.
(tcx.types.err, vec![])
}
}
}
Expand Down
38 changes: 36 additions & 2 deletions src/librustc/middle/traits/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,15 @@ use super::{util};

use middle::fast_reject;
use middle::subst::{Subst, Substs, TypeSpace, VecPerParamSpace};
use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty};
use middle::ty::{self, AssociatedType, RegionEscape, ToPolyTraitRef, TraitRef, Ty};
use middle::infer;
use middle::infer::{InferCtxt, TypeFreshener};
use middle::ty_fold::TypeFoldable;
use std::cell::RefCell;
use std::collections::hash_map::HashMap;
use std::rc::Rc;
use syntax::{abi, ast};
use syntax::abi;
use syntax::ast::{self, DefId};
use util::common::ErrorReported;
use util::ppaux::Repr;

Expand Down Expand Up @@ -2195,6 +2196,39 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
///////////////////////////////////////////////////////////////////////////
// Miscellany

pub fn instantiate_assoc_type(&self,
assoc_ty: &AssociatedType,
impl_substs: &Substs<'tcx>)
-> Ty<'tcx>
{
let poly_ty = ty::lookup_item_type(self.tcx(), assoc_ty.def_id);
let substs = self.maybe_pick_free_substs(assoc_ty.container.id(), impl_substs);
poly_ty.ty.subst(self.tcx(), substs)
}

pub fn instantiate_trait_predicates(&self,
trait_ref: &Rc<TraitRef<'tcx>>)
-> ty::InstantiatedPredicates<'tcx>
{
let trait_predicates = ty::lookup_predicates(self.tcx(), trait_ref.def_id);
let substs = self.maybe_pick_free_substs(trait_ref.def_id, trait_ref.substs);
trait_predicates.instantiate(self.tcx(), substs)
}

fn maybe_pick_free_substs(&self,
target_def_id: DefId,
substs: &'cx Substs<'tcx>)
-> &'cx Substs<'tcx>
{
// The free substitutions take precedence over the given one if
// current parameter environment is associated with `target_def_id`.
if self.param_env().def_id == target_def_id {
&self.param_env().free_substs
} else {
substs
}
}

fn push_stack<'o,'s:'o>(&mut self,
previous_stack: Option<&'s TraitObligationStack<'s, 'tcx>>,
obligation: &'o TraitObligation<'tcx>)
Expand Down
36 changes: 19 additions & 17 deletions src/librustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ use std::vec::{CowVec, IntoIter};
use collections::enum_set::{EnumSet, CLike};
use std::collections::{HashMap, HashSet};
use syntax::abi;
use syntax::ast::{CrateNum, DefId, Ident, ItemTrait, LOCAL_CRATE};
use syntax::ast::{CrateNum, DefId, Ident, ItemTrait, DUMMY_NODE_ID, LOCAL_CRATE};
use syntax::ast::{MutImmutable, MutMutable, Name, NamedField, NodeId};
use syntax::ast::{StmtExpr, StmtSemi, StructField, UnnamedField, Visibility};
use syntax::ast_util::{self, is_local, lit_is_str, local_def, PostExpansionMethod};
Expand Down Expand Up @@ -2135,6 +2135,13 @@ impl<'tcx> TraitRef<'tcx> {
pub struct ParameterEnvironment<'a, 'tcx:'a> {
pub tcx: &'a ctxt<'tcx>,

/// Item the parameter environment is associated with. For `ItemImpl` or
/// `ItemFn`, this is the item itself; for `MethodImplItem`, however, this
/// is the implementation (container) it is in. A certain method may make
/// use of associated types, which are at the container level. So we need
/// to know this when instantiating associated types for methods.
pub def_id: DefId,

/// See `construct_free_substs` for details.
pub free_substs: Substs<'tcx>,

Expand All @@ -2161,6 +2168,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
{
ParameterEnvironment {
tcx: self.tcx,
def_id: self.def_id,
free_substs: self.free_substs.clone(),
implicit_region_bound: self.implicit_region_bound,
caller_bounds: caller_bounds,
Expand All @@ -2180,6 +2188,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
let method_bounds = &method_ty.predicates;
construct_parameter_environment(
cx,
method_ty.container.id(),
method.span,
method_generics,
method_bounds,
Expand Down Expand Up @@ -2217,6 +2226,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
let method_bounds = &method_ty.predicates;
construct_parameter_environment(
cx,
method_ty.container.id(),
method.span,
method_generics,
method_bounds,
Expand Down Expand Up @@ -2246,6 +2256,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
let fn_predicates = lookup_predicates(cx, fn_def_id);

construct_parameter_environment(cx,
fn_def_id,
item.span,
&fn_scheme.generics,
&fn_predicates,
Expand All @@ -2260,6 +2271,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
let scheme = lookup_item_type(cx, def_id);
let predicates = lookup_predicates(cx, def_id);
construct_parameter_environment(cx,
def_id,
item.span,
&scheme.generics,
&predicates,
Expand Down Expand Up @@ -4295,8 +4307,8 @@ pub fn ty_region(tcx: &ctxt,
}
}

pub fn free_region_from_def(outlives_extent: region::DestructionScopeData,
def: &RegionParameterDef)
fn free_region_from_def(outlives_extent: region::DestructionScopeData,
def: &RegionParameterDef)
-> ty::Region
{
let ret =
Expand Down Expand Up @@ -5116,19 +5128,6 @@ pub fn is_associated_type(cx: &ctxt, id: ast::DefId) -> bool {
})
}

/// Returns the parameter index that the given associated type corresponds to.
pub fn associated_type_parameter_index(cx: &ctxt,
trait_def: &TraitDef,
associated_type_id: ast::DefId)
-> uint {
for type_parameter_def in trait_def.generics.types.iter() {
if type_parameter_def.def_id == associated_type_id {
return type_parameter_def.index as uint
}
}
cx.sess.bug("couldn't find associated type parameter index")
}

pub fn trait_item_def_ids(cx: &ctxt, id: ast::DefId)
-> Rc<Vec<ImplOrTraitItemId>> {
lookup_locally_or_in_crate_store("trait_item_def_ids",
Expand Down Expand Up @@ -6318,6 +6317,7 @@ impl Variance {
/// are no free type/lifetime parameters in scope.
pub fn empty_parameter_environment<'a,'tcx>(cx: &'a ctxt<'tcx>) -> ParameterEnvironment<'a,'tcx> {
ty::ParameterEnvironment { tcx: cx,
def_id: local_def(DUMMY_NODE_ID),
free_substs: Substs::empty(),
caller_bounds: Vec::new(),
implicit_region_bound: ty::ReEmpty,
Expand Down Expand Up @@ -6355,7 +6355,7 @@ pub fn construct_free_substs<'a,'tcx>(
region_params: &[RegionParameterDef])
{
for r in region_params {
regions.push(r.space, ty::free_region_from_def(all_outlive_extent, r));
regions.push(r.space, free_region_from_def(all_outlive_extent, r));
}
}

Expand All @@ -6374,6 +6374,7 @@ pub fn construct_free_substs<'a,'tcx>(
/// See `ParameterEnvironment` struct def'n for details
pub fn construct_parameter_environment<'a,'tcx>(
tcx: &'a ctxt<'tcx>,
def_id: DefId,
span: Span,
generics: &ty::Generics<'tcx>,
generic_predicates: &ty::GenericPredicates<'tcx>,
Expand Down Expand Up @@ -6424,6 +6425,7 @@ pub fn construct_parameter_environment<'a,'tcx>(

let unnormalized_env = ty::ParameterEnvironment {
tcx: tcx,
def_id: def_id,
free_substs: free_substs,
implicit_region_bound: ty::ReScope(free_id_outlive.to_code_extent()),
caller_bounds: predicates,
Expand Down
12 changes: 0 additions & 12 deletions src/librustc/middle/ty_fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -575,18 +575,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ClosureUpvar<'tcx> {
}
}

impl<'a, 'tcx> TypeFoldable<'tcx> for ty::ParameterEnvironment<'a, 'tcx> where 'tcx: 'a {
fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ParameterEnvironment<'a, 'tcx> {
ty::ParameterEnvironment {
tcx: self.tcx,
free_substs: self.free_substs.fold_with(folder),
implicit_region_bound: self.implicit_region_bound.fold_with(folder),
caller_bounds: self.caller_bounds.fold_with(folder),
selection_cache: traits::SelectionCache::new(),
}
}
}

///////////////////////////////////////////////////////////////////////////
// "super" routines: these are the default implementations for TypeFolder.
//
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_typeck/check/assoc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ pub fn normalize_associated_types_in<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
debug!("normalize_associated_types_in(value={})", value.repr(infcx.tcx));
let mut selcx = SelectionContext::new(infcx, typer);
let cause = ObligationCause::new(span, body_id, MiscObligation);
let Normalized { value: result, obligations } = traits::normalize(&mut selcx, cause, value);
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));
Expand Down
27 changes: 6 additions & 21 deletions src/librustc_typeck/check/compare_method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,6 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
debug!("compare_impl_method(impl_trait_ref={})",
impl_trait_ref.repr(tcx));

debug!("compare_impl_method: impl_trait_ref (liberated) = {}",
impl_trait_ref.repr(tcx));

let infcx = infer::new_infer_ctxt(tcx);
let mut fulfillment_cx = traits::FulfillmentContext::new();

Expand Down Expand Up @@ -180,10 +177,8 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,

// Create mapping from trait to skolemized.
let trait_to_skol_substs =
trait_to_impl_substs
.subst(tcx, impl_to_skol_substs)
.with_method(impl_to_skol_substs.types.get_slice(subst::FnSpace).to_vec(),
impl_to_skol_substs.regions().get_slice(subst::FnSpace).to_vec());
trait_to_impl_substs.subst(tcx, impl_to_skol_substs)
.with_method_from(impl_to_skol_substs);
debug!("compare_impl_method: trait_to_skol_substs={}",
trait_to_skol_substs.repr(tcx));

Expand All @@ -208,10 +203,9 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
impl_m.predicates.instantiate(tcx, impl_to_skol_substs);

let (impl_bounds, _) =
infcx.replace_late_bound_regions_with_fresh_var(
impl_m_span,
infer::HigherRankedType,
&ty::Binder(impl_bounds));
infcx.replace_late_bound_regions_with_fresh_var(impl_m_span,
infer::HigherRankedType,
&ty::Binder(impl_bounds));
debug!("compare_impl_method: impl_bounds={}",
impl_bounds.repr(tcx));

Expand Down Expand Up @@ -243,7 +237,7 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
let trait_param_env = traits::normalize_param_env_or_error(trait_param_env,
normalize_cause.clone());

debug!("compare_impl_method: trait_bounds={}",
debug!("compare_impl_method: trait_param_env.caller_bounds={}",
trait_param_env.caller_bounds.repr(tcx));

let mut selcx = traits::SelectionContext::new(&infcx, &trait_param_env);
Expand Down Expand Up @@ -276,12 +270,6 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
// any associated types appearing in the fn arguments or return
// type.

// Compute skolemized form of impl and trait method tys.
let impl_fty = ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(impl_m.fty.clone()));
let impl_fty = impl_fty.subst(tcx, impl_to_skol_substs);
let trait_fty = ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(trait_m.fty.clone()));
let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs);

let err = infcx.try(|snapshot| {
let origin = infer::MethodCompatCheck(impl_m_span);

Expand Down Expand Up @@ -336,9 +324,6 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
match err {
Ok(()) => { }
Err(terr) => {
debug!("checking trait method for compatibility: impl ty {}, trait ty {}",
impl_fty.repr(tcx),
trait_fty.repr(tcx));
span_err!(tcx.sess, impl_m_span, E0053,
"method `{}` has an incompatible type for trait: {}",
token::get_name(trait_m.name),
Expand Down
Loading