Skip to content

Commit 8303441

Browse files
committed
Normalize parameter environment with its own substitution
Otherwise, the substitution is carried out from outside perspective, which would be against the very purpose of `ParameterEnvironment`. Closes rust-lang#21750 Closes rust-lang#22077
1 parent a87e37d commit 8303441

File tree

8 files changed

+133
-33
lines changed

8 files changed

+133
-33
lines changed

src/librustc/middle/traits/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -413,10 +413,10 @@ pub fn normalize_param_env_or_error<'a,'tcx>(unnormalized_env: ty::ParameterEnvi
413413
}
414414
}
415415

416-
pub fn normalize_param_env<'a,'tcx>(param_env: &ty::ParameterEnvironment<'a,'tcx>,
417-
cause: ObligationCause<'tcx>)
418-
-> Result<ty::ParameterEnvironment<'a,'tcx>,
419-
Vec<FulfillmentError<'tcx>>>
416+
fn normalize_param_env<'a,'tcx>(param_env: &ty::ParameterEnvironment<'a,'tcx>,
417+
cause: ObligationCause<'tcx>)
418+
-> Result<ty::ParameterEnvironment<'a,'tcx>,
419+
Vec<FulfillmentError<'tcx>>>
420420
{
421421
let tcx = param_env.tcx;
422422

src/librustc/middle/traits/project.rs

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use super::VtableImplData;
2121
use super::util;
2222

2323
use middle::infer;
24-
use middle::subst::{Subst, Substs};
24+
use middle::subst::Substs;
2525
use middle::ty::{self, AsPredicate, ReferencesError, RegionEscape,
2626
HasProjectionTypes, ToPolyTraitRef, Ty};
2727
use middle::ty_fold::{self, TypeFoldable, TypeFolder};
@@ -849,36 +849,38 @@ fn confirm_impl_candidate<'cx,'tcx>(
849849
impl_vtable: VtableImplData<'tcx, PredicateObligation<'tcx>>)
850850
-> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
851851
{
852+
let tcx = selcx.tcx();
852853
// there don't seem to be nicer accessors to these:
853-
let impl_items_map = selcx.tcx().impl_items.borrow();
854-
let impl_or_trait_items_map = selcx.tcx().impl_or_trait_items.borrow();
854+
let impl_items_map = tcx.impl_items.borrow();
855+
let impl_or_trait_items_map = tcx.impl_or_trait_items.borrow();
855856

856857
let impl_items = &impl_items_map[impl_vtable.impl_def_id];
857-
let mut impl_ty = None;
858-
for impl_item in impl_items {
859-
let assoc_type = match impl_or_trait_items_map[impl_item.def_id()] {
860-
ty::TypeTraitItem(ref assoc_type) => assoc_type.clone(),
861-
ty::MethodTraitItem(..) => { continue; }
862-
};
863-
864-
if assoc_type.name != obligation.predicate.item_name {
865-
continue;
866-
}
867-
868-
let impl_poly_ty = ty::lookup_item_type(selcx.tcx(), assoc_type.def_id);
869-
impl_ty = Some(impl_poly_ty.ty.subst(selcx.tcx(), &impl_vtable.substs));
870-
break;
871-
}
858+
let assoc_type =
859+
impl_items
860+
.iter()
861+
.filter_map(|item| {
862+
match impl_or_trait_items_map[item.def_id()] {
863+
ty::TypeTraitItem(ref assoc_type)
864+
if assoc_type.name == obligation.predicate.item_name => {
865+
Some(assoc_type)
866+
}
867+
_ => None
868+
}
869+
})
870+
.next();
872871

873-
match impl_ty {
874-
Some(ty) => (ty, impl_vtable.nested.into_vec()),
872+
match assoc_type {
873+
Some(assoc_type) => {
874+
let impl_ty = selcx.instantiate_assoc_type(assoc_type,
875+
&impl_vtable.substs);
876+
(impl_ty, impl_vtable.nested.into_vec())
877+
},
875878
None => {
876-
// This means that the impl is missing a
877-
// definition for the associated type. This error
878-
// ought to be reported by the type checker method
879-
// `check_impl_items_against_trait`, so here we
880-
// just return ty_err.
881-
(selcx.tcx().types.err, vec!())
879+
// This means that the impl is missing a definition for the
880+
// associated type. This error ought to be reported by the
881+
// type checker method `check_impl_items_against_trait`, so
882+
// here we just return ty_err.
883+
(tcx.types.err, vec![])
882884
}
883885
}
884886
}

src/librustc/middle/traits/select.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use super::{util};
3333

3434
use middle::fast_reject;
3535
use middle::subst::{Subst, Substs, TypeSpace, VecPerParamSpace};
36-
use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty};
36+
use middle::ty::{self, AssociatedType, RegionEscape, ToPolyTraitRef, Ty};
3737
use middle::infer;
3838
use middle::infer::{InferCtxt, TypeFreshener};
3939
use middle::ty_fold::TypeFoldable;
@@ -2195,6 +2195,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
21952195
///////////////////////////////////////////////////////////////////////////
21962196
// Miscellany
21972197

2198+
pub fn instantiate_assoc_type(&self,
2199+
assoc_ty: &AssociatedType,
2200+
impl_substs: &Substs<'tcx>)
2201+
-> Ty<'tcx>
2202+
{
2203+
let poly_ty = ty::lookup_item_type(self.tcx(), assoc_ty.def_id);
2204+
let substs =
2205+
if self.param_env().def_id == assoc_ty.container.id() {
2206+
// If the associated type we are about to instantiate is
2207+
// defined in the item current parameter environment is
2208+
// associated with, we are obliged to use free substitutions.
2209+
&self.param_env().free_substs
2210+
} else {
2211+
impl_substs
2212+
};
2213+
2214+
poly_ty.ty.subst(self.tcx(), substs)
2215+
}
2216+
21982217
fn push_stack<'o,'s:'o>(&mut self,
21992218
previous_stack: Option<&'s TraitObligationStack<'s, 'tcx>>,
22002219
obligation: &'o TraitObligation<'tcx>)

src/librustc/middle/ty.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ use std::vec::{CowVec, IntoIter};
8080
use collections::enum_set::{EnumSet, CLike};
8181
use std::collections::{HashMap, HashSet};
8282
use syntax::abi;
83-
use syntax::ast::{CrateNum, DefId, Ident, ItemTrait, LOCAL_CRATE};
83+
use syntax::ast::{CrateNum, DefId, Ident, ItemTrait, DUMMY_NODE_ID, LOCAL_CRATE};
8484
use syntax::ast::{MutImmutable, MutMutable, Name, NamedField, NodeId};
8585
use syntax::ast::{StmtExpr, StmtSemi, StructField, UnnamedField, Visibility};
8686
use syntax::ast_util::{self, is_local, lit_is_str, local_def, PostExpansionMethod};
@@ -2135,6 +2135,13 @@ impl<'tcx> TraitRef<'tcx> {
21352135
pub struct ParameterEnvironment<'a, 'tcx:'a> {
21362136
pub tcx: &'a ctxt<'tcx>,
21372137

2138+
/// Item the parameter environment is associated with. For `ItemImpl` or
2139+
/// `ItemFn`, this is the item itself; for `MethodImplItem`, however, this
2140+
/// is the implementation (container) it is in. A certain method may make
2141+
/// use of associated types, which are at the container level. So we need
2142+
/// to know this when instantiating associated types for methods.
2143+
pub def_id: DefId,
2144+
21382145
/// See `construct_free_substs` for details.
21392146
pub free_substs: Substs<'tcx>,
21402147

@@ -2161,6 +2168,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
21612168
{
21622169
ParameterEnvironment {
21632170
tcx: self.tcx,
2171+
def_id: self.def_id,
21642172
free_substs: self.free_substs.clone(),
21652173
implicit_region_bound: self.implicit_region_bound,
21662174
caller_bounds: caller_bounds,
@@ -2180,6 +2188,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
21802188
let method_bounds = &method_ty.predicates;
21812189
construct_parameter_environment(
21822190
cx,
2191+
method_ty.container.id(),
21832192
method.span,
21842193
method_generics,
21852194
method_bounds,
@@ -2217,6 +2226,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
22172226
let method_bounds = &method_ty.predicates;
22182227
construct_parameter_environment(
22192228
cx,
2229+
method_ty.container.id(),
22202230
method.span,
22212231
method_generics,
22222232
method_bounds,
@@ -2246,6 +2256,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
22462256
let fn_predicates = lookup_predicates(cx, fn_def_id);
22472257

22482258
construct_parameter_environment(cx,
2259+
fn_def_id,
22492260
item.span,
22502261
&fn_scheme.generics,
22512262
&fn_predicates,
@@ -2260,6 +2271,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
22602271
let scheme = lookup_item_type(cx, def_id);
22612272
let predicates = lookup_predicates(cx, def_id);
22622273
construct_parameter_environment(cx,
2274+
def_id,
22632275
item.span,
22642276
&scheme.generics,
22652277
&predicates,
@@ -6305,6 +6317,7 @@ impl Variance {
63056317
/// are no free type/lifetime parameters in scope.
63066318
pub fn empty_parameter_environment<'a,'tcx>(cx: &'a ctxt<'tcx>) -> ParameterEnvironment<'a,'tcx> {
63076319
ty::ParameterEnvironment { tcx: cx,
6320+
def_id: local_def(DUMMY_NODE_ID),
63086321
free_substs: Substs::empty(),
63096322
caller_bounds: Vec::new(),
63106323
implicit_region_bound: ty::ReEmpty,
@@ -6361,6 +6374,7 @@ pub fn construct_free_substs<'a,'tcx>(
63616374
/// See `ParameterEnvironment` struct def'n for details
63626375
pub fn construct_parameter_environment<'a,'tcx>(
63636376
tcx: &'a ctxt<'tcx>,
6377+
def_id: DefId,
63646378
span: Span,
63656379
generics: &ty::Generics<'tcx>,
63666380
generic_predicates: &ty::GenericPredicates<'tcx>,
@@ -6411,6 +6425,7 @@ pub fn construct_parameter_environment<'a,'tcx>(
64116425

64126426
let unnormalized_env = ty::ParameterEnvironment {
64136427
tcx: tcx,
6428+
def_id: def_id,
64146429
free_substs: free_substs,
64156430
implicit_region_bound: ty::ReScope(free_id_outlive.to_code_extent()),
64166431
caller_bounds: predicates,

src/librustc_typeck/check/assoc.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ pub fn normalize_associated_types_in<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
2929
debug!("normalize_associated_types_in(value={})", value.repr(infcx.tcx));
3030
let mut selcx = SelectionContext::new(infcx, typer);
3131
let cause = ObligationCause::new(span, body_id, MiscObligation);
32-
let Normalized { value: result, obligations } = traits::normalize(&mut selcx, cause, value);
32+
let Normalized { value: result,
33+
obligations } = traits::normalize(&mut selcx, cause, value);
3334
debug!("normalize_associated_types_in: result={} predicates={}",
3435
result.repr(infcx.tcx),
3536
obligations.repr(infcx.tcx));

src/librustc_typeck/check/wf.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
139139
reject_non_type_param_bounds(ccx.tcx, item.span, &type_predicates);
140140
let param_env =
141141
ty::construct_parameter_environment(ccx.tcx,
142+
item_def_id,
142143
item.span,
143144
&type_scheme.generics,
144145
&type_predicates,

src/test/compile-fail/issue-22077.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
trait Fun {
12+
type Output;
13+
fn call<'x>(&'x self) -> Self::Output;
14+
}
15+
16+
struct Holder { x: String }
17+
18+
impl<'a> Fun for Holder {
19+
type Output = &'a str;
20+
fn call<'b>(&'b self) -> &'b str {
21+
//~^ ERROR method `call` has an incompatible type for trait
22+
&self.x[..]
23+
}
24+
}
25+
26+
fn main() {}

src/test/run-pass/issue-21750.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
pub trait Arg<A> {
12+
fn arg(&self) -> A;
13+
}
14+
15+
pub trait Traversal {
16+
type Item;
17+
fn foreach<F: Arg<Self::Item>>(F);
18+
}
19+
20+
impl<'a> Traversal for i32 {
21+
type Item = &'a i32;
22+
fn foreach<F: Arg<&'a i32>>(f: F) {
23+
f.arg();
24+
}
25+
}
26+
27+
impl<'a> Traversal for u8 {
28+
type Item = &'a u8;
29+
// A more verbose way to refer to the associated type. Should also work
30+
// nonetheless.
31+
fn foreach<F: Arg<<Self as Traversal>::Item>>(f: F) {
32+
let _ = f.arg();
33+
}
34+
}
35+
36+
fn main() {}

0 commit comments

Comments
 (0)