Skip to content

Commit b5fe3bc

Browse files
committed
Auto merge of #87900 - jackh726:issue-87429, r=nikomatsakis
Use bound vars for GAT params in param_env in check_type_bounds Fixes #87429
2 parents 47ab5f7 + b017077 commit b5fe3bc

File tree

8 files changed

+215
-12
lines changed

8 files changed

+215
-12
lines changed

Diff for: compiler/rustc_middle/src/ty/subst.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ impl<'a, 'tcx> InternalSubsts<'tcx> {
234234
})
235235
}
236236

237-
fn fill_item<F>(
237+
pub fn fill_item<F>(
238238
substs: &mut SmallVec<[GenericArg<'tcx>; 8]>,
239239
tcx: TyCtxt<'tcx>,
240240
defs: &ty::Generics,
@@ -249,7 +249,7 @@ impl<'a, 'tcx> InternalSubsts<'tcx> {
249249
Self::fill_single(substs, defs, mk_kind)
250250
}
251251

252-
fn fill_single<F>(
252+
pub fn fill_single<F>(
253253
substs: &mut SmallVec<[GenericArg<'tcx>; 8]>,
254254
defs: &ty::Generics,
255255
mk_kind: &mut F,

Diff for: compiler/rustc_typeck/src/check/compare_method.rs

+93-10
Original file line numberDiff line numberDiff line change
@@ -1225,6 +1225,7 @@ fn compare_type_predicate_entailment<'tcx>(
12251225
/// For default associated types the normalization is not possible (the value
12261226
/// from the impl could be overridden). We also can't normalize generic
12271227
/// associated types (yet) because they contain bound parameters.
1228+
#[tracing::instrument(level = "debug", skip(tcx))]
12281229
pub fn check_type_bounds<'tcx>(
12291230
tcx: TyCtxt<'tcx>,
12301231
trait_ty: &ty::AssocItem,
@@ -1238,10 +1239,83 @@ pub fn check_type_bounds<'tcx>(
12381239
// type Bar<C> =...
12391240
// }
12401241
//
1241-
// - `impl_substs` would be `[A, B, C]`
1242-
// - `rebased_substs` would be `[(A, B), u32, C]`, combining the substs from
1243-
// the *trait* with the generic associated type parameters.
1244-
let impl_ty_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id);
1242+
// - `impl_trait_ref` would be `<(A, B) as Foo<u32>>
1243+
// - `impl_ty_substs` would be `[A, B, ^0.0]` (`^0.0` here is the bound var with db 0 and index 0)
1244+
// - `rebased_substs` would be `[(A, B), u32, ^0.0]`, combining the substs from
1245+
// the *trait* with the generic associated type parameters (as bound vars).
1246+
//
1247+
// A note regarding the use of bound vars here:
1248+
// Imagine as an example
1249+
// ```
1250+
// trait Family {
1251+
// type Member<C: Eq>;
1252+
// }
1253+
//
1254+
// impl Family for VecFamily {
1255+
// type Member<C: Eq> = i32;
1256+
// }
1257+
// ```
1258+
// Here, we would generate
1259+
// ```notrust
1260+
// forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) }
1261+
// ```
1262+
// when we really would like to generate
1263+
// ```notrust
1264+
// forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) :- Implemented(C: Eq) }
1265+
// ```
1266+
// But, this is probably fine, because although the first clause can be used with types C that
1267+
// do not implement Eq, for it to cause some kind of problem, there would have to be a
1268+
// VecFamily::Member<X> for some type X where !(X: Eq), that appears in the value of type
1269+
// Member<C: Eq> = .... That type would fail a well-formedness check that we ought to be doing
1270+
// elsewhere, which would check that any <T as Family>::Member<X> meets the bounds declared in
1271+
// the trait (notably, that X: Eq and T: Family).
1272+
let defs: &ty::Generics = tcx.generics_of(impl_ty.def_id);
1273+
let mut substs = smallvec::SmallVec::with_capacity(defs.count());
1274+
if let Some(def_id) = defs.parent {
1275+
let parent_defs = tcx.generics_of(def_id);
1276+
InternalSubsts::fill_item(&mut substs, tcx, parent_defs, &mut |param, _| {
1277+
tcx.mk_param_from_def(param)
1278+
});
1279+
}
1280+
let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> =
1281+
smallvec::SmallVec::with_capacity(defs.count());
1282+
InternalSubsts::fill_single(&mut substs, defs, &mut |param, _| match param.kind {
1283+
GenericParamDefKind::Type { .. } => {
1284+
let kind = ty::BoundTyKind::Param(param.name);
1285+
let bound_var = ty::BoundVariableKind::Ty(kind);
1286+
bound_vars.push(bound_var);
1287+
tcx.mk_ty(ty::Bound(
1288+
ty::INNERMOST,
1289+
ty::BoundTy { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
1290+
))
1291+
.into()
1292+
}
1293+
GenericParamDefKind::Lifetime => {
1294+
let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name);
1295+
let bound_var = ty::BoundVariableKind::Region(kind);
1296+
bound_vars.push(bound_var);
1297+
tcx.mk_region(ty::ReLateBound(
1298+
ty::INNERMOST,
1299+
ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
1300+
))
1301+
.into()
1302+
}
1303+
GenericParamDefKind::Const { .. } => {
1304+
let bound_var = ty::BoundVariableKind::Const;
1305+
bound_vars.push(bound_var);
1306+
tcx.mk_const(ty::Const {
1307+
ty: tcx.type_of(param.def_id),
1308+
val: ty::ConstKind::Bound(
1309+
ty::INNERMOST,
1310+
ty::BoundVar::from_usize(bound_vars.len() - 1),
1311+
),
1312+
})
1313+
.into()
1314+
}
1315+
});
1316+
let bound_vars = tcx.mk_bound_variable_kinds(bound_vars.into_iter());
1317+
let impl_ty_substs = tcx.intern_substs(&substs);
1318+
12451319
let rebased_substs =
12461320
impl_ty_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs);
12471321
let impl_ty_value = tcx.type_of(impl_ty.def_id);
@@ -1270,18 +1344,26 @@ pub fn check_type_bounds<'tcx>(
12701344
// impl<T> X for T where T: X { type Y = <T as X>::Y; }
12711345
}
12721346
_ => predicates.push(
1273-
ty::Binder::dummy(ty::ProjectionPredicate {
1274-
projection_ty: ty::ProjectionTy {
1275-
item_def_id: trait_ty.def_id,
1276-
substs: rebased_substs,
1347+
ty::Binder::bind_with_vars(
1348+
ty::ProjectionPredicate {
1349+
projection_ty: ty::ProjectionTy {
1350+
item_def_id: trait_ty.def_id,
1351+
substs: rebased_substs,
1352+
},
1353+
ty: impl_ty_value,
12771354
},
1278-
ty: impl_ty_value,
1279-
})
1355+
bound_vars,
1356+
)
12801357
.to_predicate(tcx),
12811358
),
12821359
};
12831360
ty::ParamEnv::new(tcx.intern_predicates(&predicates), Reveal::UserFacing)
12841361
};
1362+
debug!(?normalize_param_env);
1363+
1364+
let impl_ty_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id);
1365+
let rebased_substs =
1366+
impl_ty_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs);
12851367

12861368
tcx.infer_ctxt().enter(move |infcx| {
12871369
let constness = impl_ty
@@ -1308,6 +1390,7 @@ pub fn check_type_bounds<'tcx>(
13081390
.explicit_item_bounds(trait_ty.def_id)
13091391
.iter()
13101392
.map(|&(bound, span)| {
1393+
debug!(?bound);
13111394
let concrete_ty_bound = bound.subst(tcx, rebased_substs);
13121395
debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound);
13131396

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Derived from `issue-87429`. A test that ensures that using bound vars in the
2+
// predicates in the param env when checking that an associated type satisfies
3+
// its bounds does not cause us to not be able to use the bounds on the parameters.
4+
5+
// check-pass
6+
7+
#![feature(generic_associated_types)]
8+
9+
trait Family {
10+
type Member<'a, C: Eq>: for<'b> MyBound<'b, C>;
11+
}
12+
13+
trait MyBound<'a, C> { }
14+
impl<'a, C: Eq> MyBound<'a, C> for i32 { }
15+
16+
impl Family for () {
17+
type Member<'a, C: Eq> = i32;
18+
}
19+
20+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// check-fail
2+
3+
#![feature(associated_type_defaults)]
4+
#![feature(generic_associated_types)]
5+
6+
trait Family {
7+
// Fine, i32: PartialEq<i32>
8+
type Member<'a>: for<'b> PartialEq<Self::Member<'b>> = i32;
9+
}
10+
11+
struct Foo;
12+
trait Family2 {
13+
// Not fine, not Foo: PartialEq<Foo>
14+
type Member<'a>: for<'b> PartialEq<Self::Member<'b>> = Foo;
15+
//~^ ERROR can't compare
16+
}
17+
18+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error[E0277]: can't compare `Foo` with `Foo`
2+
--> $DIR/issue-87429-associated-type-default.rs:14:5
3+
|
4+
LL | type Member<'a>: for<'b> PartialEq<Self::Member<'b>> = Foo;
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `Foo == Foo`
6+
|
7+
= help: the trait `PartialEq` is not implemented for `Foo`
8+
note: required by a bound in `Family2::Member`
9+
--> $DIR/issue-87429-associated-type-default.rs:14:22
10+
|
11+
LL | type Member<'a>: for<'b> PartialEq<Self::Member<'b>> = Foo;
12+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Family2::Member`
13+
14+
error: aborting due to previous error
15+
16+
For more information about this error, try `rustc --explain E0277`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// check-fail
2+
3+
#![feature(specialization)]
4+
//~^ WARN incomplete
5+
#![feature(generic_associated_types)]
6+
7+
trait Family {
8+
type Member<'a>: for<'b> PartialEq<Self::Member<'b>>;
9+
}
10+
11+
struct I32Family;
12+
13+
impl Family for I32Family {
14+
default type Member<'a> = i32;
15+
}
16+
17+
struct Foo;
18+
struct FooFamily;
19+
20+
impl Family for FooFamily {
21+
default type Member<'a> = Foo;
22+
//~^ ERROR can't compare
23+
}
24+
25+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/issue-87429-specialization.rs:3:12
3+
|
4+
LL | #![feature(specialization)]
5+
| ^^^^^^^^^^^^^^
6+
|
7+
= note: `#[warn(incomplete_features)]` on by default
8+
= note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
9+
= help: consider using `min_specialization` instead, which is more stable and complete
10+
11+
error[E0277]: can't compare `Foo` with `Foo`
12+
--> $DIR/issue-87429-specialization.rs:21:5
13+
|
14+
LL | default type Member<'a> = Foo;
15+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `Foo == Foo`
16+
|
17+
= help: the trait `PartialEq` is not implemented for `Foo`
18+
note: required by a bound in `Family::Member`
19+
--> $DIR/issue-87429-specialization.rs:8:22
20+
|
21+
LL | type Member<'a>: for<'b> PartialEq<Self::Member<'b>>;
22+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Family::Member`
23+
24+
error: aborting due to previous error; 1 warning emitted
25+
26+
For more information about this error, try `rustc --explain E0277`.

Diff for: src/test/ui/generic-associated-types/issue-87429.rs

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// check-pass
2+
3+
#![feature(generic_associated_types)]
4+
5+
trait Family {
6+
type Member<'a>: for<'b> PartialEq<Self::Member<'b>>;
7+
}
8+
9+
struct I32;
10+
11+
impl Family for I32 {
12+
type Member<'a> = i32;
13+
}
14+
15+
fn main() {}

0 commit comments

Comments
 (0)