Skip to content

Commit ebb560a

Browse files
committed
Auto merge of #29934 - arielb1:constrained-projection-2, r=nikomatsakis
Fixes #29861 - it was a bug I accidentally introduced in #26275. r? @nikomatsakis
2 parents 9cf0e3c + 3c0d55c commit ebb560a

File tree

3 files changed

+85
-19
lines changed

3 files changed

+85
-19
lines changed

src/librustc_typeck/collect.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -2387,9 +2387,9 @@ fn enforce_impl_params_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>,
23872387
// reachable from there, to start (if this is an inherent impl,
23882388
// then just examine the self type).
23892389
let mut input_parameters: HashSet<_> =
2390-
ctp::parameters_for_type(impl_scheme.ty).into_iter().collect();
2390+
ctp::parameters_for_type(impl_scheme.ty, false).into_iter().collect();
23912391
if let Some(ref trait_ref) = impl_trait_ref {
2392-
input_parameters.extend(ctp::parameters_for_trait_ref(trait_ref));
2392+
input_parameters.extend(ctp::parameters_for_trait_ref(trait_ref, false));
23932393
}
23942394

23952395
ctp::setup_constraining_predicates(tcx,
@@ -2418,9 +2418,9 @@ fn enforce_impl_lifetimes_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>,
24182418
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
24192419

24202420
let mut input_parameters: HashSet<_> =
2421-
ctp::parameters_for_type(impl_scheme.ty).into_iter().collect();
2421+
ctp::parameters_for_type(impl_scheme.ty, false).into_iter().collect();
24222422
if let Some(ref trait_ref) = impl_trait_ref {
2423-
input_parameters.extend(ctp::parameters_for_trait_ref(trait_ref));
2423+
input_parameters.extend(ctp::parameters_for_trait_ref(trait_ref, false));
24242424
}
24252425
ctp::identify_constrained_type_params(tcx,
24262426
&impl_predicates.predicates.as_slice(), impl_trait_ref, &mut input_parameters);
@@ -2432,7 +2432,7 @@ fn enforce_impl_lifetimes_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>,
24322432
ty::TypeTraitItem(ref assoc_ty) => assoc_ty.ty,
24332433
ty::ConstTraitItem(..) | ty::MethodTraitItem(..) => None
24342434
})
2435-
.flat_map(|ty| ctp::parameters_for_type(ty))
2435+
.flat_map(|ty| ctp::parameters_for_type(ty, true))
24362436
.filter_map(|p| match p {
24372437
ctp::Parameter::Type(_) => None,
24382438
ctp::Parameter::Region(r) => Some(r),

src/librustc_typeck/constrained_type_params.rs

+50-14
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,20 @@ pub enum Parameter {
1919
Region(ty::EarlyBoundRegion),
2020
}
2121

22-
/// Returns the list of parameters that are constrained by the type `ty`
23-
/// - i.e. the value of each parameter in the list is uniquely determined
24-
/// by `ty` (see RFC 447).
25-
pub fn parameters_for_type<'tcx>(ty: Ty<'tcx>) -> Vec<Parameter> {
22+
/// If `include_projections` is false, returns the list of parameters that are
23+
/// constrained by the type `ty` - i.e. the value of each parameter in the list is
24+
/// uniquely determined by `ty` (see RFC 447). If it is true, return the list
25+
/// of parameters whose values are needed in order to constrain `ty` - these
26+
/// differ, with the latter being a superset, in the presence of projections.
27+
pub fn parameters_for_type<'tcx>(ty: Ty<'tcx>,
28+
include_projections: bool) -> Vec<Parameter> {
2629
let mut result = vec![];
27-
ty.maybe_walk(|t| {
28-
if let ty::TyProjection(..) = t.sty {
30+
ty.maybe_walk(|t| match t.sty {
31+
ty::TyProjection(..) if !include_projections => {
32+
2933
false // projections are not injective.
30-
} else {
34+
}
35+
_ => {
3136
result.append(&mut parameters_for_type_shallow(t));
3237
// non-projection type constructors are injective.
3338
true
@@ -36,13 +41,16 @@ pub fn parameters_for_type<'tcx>(ty: Ty<'tcx>) -> Vec<Parameter> {
3641
result
3742
}
3843

39-
pub fn parameters_for_trait_ref<'tcx>(trait_ref: &ty::TraitRef<'tcx>) -> Vec<Parameter> {
44+
pub fn parameters_for_trait_ref<'tcx>(trait_ref: &ty::TraitRef<'tcx>,
45+
include_projections: bool) -> Vec<Parameter> {
4046
let mut region_parameters =
4147
parameters_for_regions_in_substs(&trait_ref.substs);
4248

4349
let type_parameters =
44-
trait_ref.substs.types.iter()
45-
.flat_map(|ty| parameters_for_type(ty));
50+
trait_ref.substs
51+
.types
52+
.iter()
53+
.flat_map(|ty| parameters_for_type(ty, include_projections));
4654

4755
region_parameters.extend(type_parameters);
4856

@@ -60,8 +68,14 @@ fn parameters_for_type_shallow<'tcx>(ty: Ty<'tcx>) -> Vec<Parameter> {
6068
parameters_for_regions_in_substs(substs),
6169
ty::TyTrait(ref data) =>
6270
parameters_for_regions_in_substs(&data.principal.skip_binder().substs),
63-
_ =>
64-
vec![],
71+
ty::TyProjection(ref pi) =>
72+
parameters_for_regions_in_substs(&pi.trait_ref.substs),
73+
ty::TyBool | ty::TyChar | ty::TyInt(..) | ty::TyUint(..) |
74+
ty::TyFloat(..) | ty::TyBox(..) | ty::TyStr |
75+
ty::TyArray(..) | ty::TySlice(..) | ty::TyBareFn(..) |
76+
ty::TyTuple(..) | ty::TyRawPtr(..) |
77+
ty::TyInfer(..) | ty::TyClosure(..) | ty::TyError =>
78+
vec![]
6579
}
6680
}
6781

@@ -113,6 +127,22 @@ pub fn identify_constrained_type_params<'tcx>(_tcx: &ty::ctxt<'tcx>,
113127
/// pass, we want the projection to come first. In fact, as projections
114128
/// can (acyclically) depend on one another - see RFC447 for details - we
115129
/// need to topologically sort them.
130+
///
131+
/// We *do* have to be somewhat careful when projection targets contain
132+
/// projections themselves, for example in
133+
/// impl<S,U,V,W> Trait for U where
134+
/// /* 0 */ S: Iterator<Item=U>,
135+
/// /* - */ U: Iterator,
136+
/// /* 1 */ <U as Iterator>::Item: ToOwned<Owned=(W,<V as Iterator>::Item)>
137+
/// /* 2 */ W: Iterator<Item=V>
138+
/// /* 3 */ V: Debug
139+
/// we have to evaluate the projections in the order I wrote them:
140+
/// `V: Debug` requires `V` to be evaluated. The only projection that
141+
/// *determines* `V` is 2 (1 contains it, but *does not determine it*,
142+
/// as it is only contained within a projection), but that requires `W`
143+
/// which is determined by 1, which requires `U`, that is determined
144+
/// by 0. I should probably pick a less tangled example, but I can't
145+
/// think of any.
116146
pub fn setup_constraining_predicates<'tcx>(_tcx: &ty::ctxt<'tcx>,
117147
predicates: &mut [ty::Predicate<'tcx>],
118148
impl_trait_ref: Option<ty::TraitRef<'tcx>>,
@@ -157,12 +187,18 @@ pub fn setup_constraining_predicates<'tcx>(_tcx: &ty::ctxt<'tcx>,
157187
continue;
158188
}
159189

160-
let inputs = parameters_for_trait_ref(&projection.projection_ty.trait_ref);
190+
// A projection depends on its input types and determines its output
191+
// type. For example, if we have
192+
// `<<T as Bar>::Baz as Iterator>::Output = <U as Iterator>::Output`
193+
// Then the projection only applies if `T` is known, but it still
194+
// does not determine `U`.
195+
196+
let inputs = parameters_for_trait_ref(&projection.projection_ty.trait_ref, true);
161197
let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(&p));
162198
if !relies_only_on_inputs {
163199
continue;
164200
}
165-
input_parameters.extend(parameters_for_type(projection.ty));
201+
input_parameters.extend(parameters_for_type(projection.ty, false));
166202
} else {
167203
continue;
168204
}

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

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
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 MakeRef<'a> {
12+
type Ref;
13+
}
14+
impl<'a, T: 'a> MakeRef<'a> for T {
15+
type Ref = &'a T;
16+
}
17+
18+
pub trait MakeRef2 {
19+
type Ref2;
20+
}
21+
impl<'a, T: 'a> MakeRef2 for T {
22+
//~^ ERROR the lifetime parameter `'a` is not constrained
23+
type Ref2 = <T as MakeRef<'a>>::Ref;
24+
}
25+
26+
fn foo() -> <String as MakeRef2>::Ref2 { &String::from("foo") }
27+
28+
fn main() {
29+
println!("{}", foo());
30+
}

0 commit comments

Comments
 (0)