When checking associated type bounds, use bound vars for GAT params in param_env

This commit is contained in:
jackh726 2021-08-09 19:26:13 -04:00
parent 9583fd1bdd
commit d9242ff0aa
3 changed files with 84 additions and 12 deletions

View File

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

View File

@ -1225,6 +1225,7 @@ fn compare_type_predicate_entailment<'tcx>(
/// For default associated types the normalization is not possible (the value /// For default associated types the normalization is not possible (the value
/// from the impl could be overridden). We also can't normalize generic /// from the impl could be overridden). We also can't normalize generic
/// associated types (yet) because they contain bound parameters. /// associated types (yet) because they contain bound parameters.
#[tracing::instrument(level = "debug", skip(tcx))]
pub fn check_type_bounds<'tcx>( pub fn check_type_bounds<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
trait_ty: &ty::AssocItem, trait_ty: &ty::AssocItem,
@ -1238,10 +1239,57 @@ pub fn check_type_bounds<'tcx>(
// type Bar<C> =... // type Bar<C> =...
// } // }
// //
// - `impl_substs` would be `[A, B, C]` // - `impl_trait_ref` would be `<(A, B) as Foo<u32>>
// - `rebased_substs` would be `[(A, B), u32, C]`, combining the substs from // - `impl_ty_substs` would be `[A, B, ^0.0]`
// the *trait* with the generic associated type parameters. // - `rebased_substs` would be `[(A, B), u32, ^0.0]`, combining the substs from
let impl_ty_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id); // the *trait* with the generic associated type parameters (as bound vars).
let defs: &ty::Generics = tcx.generics_of(impl_ty.def_id);
let mut substs = smallvec::SmallVec::with_capacity(defs.count());
if let Some(def_id) = defs.parent {
let parent_defs = tcx.generics_of(def_id);
InternalSubsts::fill_item(&mut substs, tcx, parent_defs, &mut |param, _| {
tcx.mk_param_from_def(param)
});
}
let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> =
smallvec::SmallVec::with_capacity(defs.count());
InternalSubsts::fill_single(&mut substs, defs, &mut |param, _| match param.kind {
GenericParamDefKind::Type { .. } => {
let kind = ty::BoundTyKind::Param(param.name);
let bound_var = ty::BoundVariableKind::Ty(kind);
bound_vars.push(bound_var);
tcx.mk_ty(ty::Bound(
ty::INNERMOST,
ty::BoundTy { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
))
.into()
}
GenericParamDefKind::Lifetime => {
let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name);
let bound_var = ty::BoundVariableKind::Region(kind);
bound_vars.push(bound_var);
tcx.mk_region(ty::ReLateBound(
ty::INNERMOST,
ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
))
.into()
}
GenericParamDefKind::Const { .. } => {
let bound_var = ty::BoundVariableKind::Const;
bound_vars.push(bound_var);
tcx.mk_const(ty::Const {
ty: tcx.type_of(param.def_id),
val: ty::ConstKind::Bound(
ty::INNERMOST,
ty::BoundVar::from_usize(bound_vars.len() - 1),
),
})
.into()
}
});
let bound_vars = tcx.mk_bound_variable_kinds(bound_vars.into_iter());
let impl_ty_substs = tcx.intern_substs(&substs);
let rebased_substs = let rebased_substs =
impl_ty_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs); impl_ty_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs);
let impl_ty_value = tcx.type_of(impl_ty.def_id); let impl_ty_value = tcx.type_of(impl_ty.def_id);
@ -1270,18 +1318,26 @@ pub fn check_type_bounds<'tcx>(
// impl<T> X for T where T: X { type Y = <T as X>::Y; } // impl<T> X for T where T: X { type Y = <T as X>::Y; }
} }
_ => predicates.push( _ => predicates.push(
ty::Binder::dummy(ty::ProjectionPredicate { ty::Binder::bind_with_vars(
projection_ty: ty::ProjectionTy { ty::ProjectionPredicate {
item_def_id: trait_ty.def_id, projection_ty: ty::ProjectionTy {
substs: rebased_substs, item_def_id: trait_ty.def_id,
substs: rebased_substs,
},
ty: impl_ty_value,
}, },
ty: impl_ty_value, bound_vars,
}) )
.to_predicate(tcx), .to_predicate(tcx),
), ),
}; };
ty::ParamEnv::new(tcx.intern_predicates(&predicates), Reveal::UserFacing) ty::ParamEnv::new(tcx.intern_predicates(&predicates), Reveal::UserFacing)
}; };
debug!(?normalize_param_env);
let impl_ty_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id);
let rebased_substs =
impl_ty_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs);
tcx.infer_ctxt().enter(move |infcx| { tcx.infer_ctxt().enter(move |infcx| {
let constness = impl_ty let constness = impl_ty
@ -1308,6 +1364,7 @@ pub fn check_type_bounds<'tcx>(
.explicit_item_bounds(trait_ty.def_id) .explicit_item_bounds(trait_ty.def_id)
.iter() .iter()
.map(|&(bound, span)| { .map(|&(bound, span)| {
debug!(?bound);
let concrete_ty_bound = bound.subst(tcx, rebased_substs); let concrete_ty_bound = bound.subst(tcx, rebased_substs);
debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound); debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound);

View File

@ -0,0 +1,15 @@
// check-pass
#![feature(generic_associated_types)]
trait Family {
type Member<'a>: for<'b> PartialEq<Self::Member<'b>>;
}
struct I32;
impl Family for I32 {
type Member<'a> = i32;
}
fn main() {}