提交 b5fe3bc0 编写于 作者: B bors

Auto merge of #87900 - jackh726:issue-87429, r=nikomatsakis

Use bound vars for GAT params in param_env in check_type_bounds

Fixes #87429
......@@ -234,7 +234,7 @@ pub fn extend_to<F>(&self, tcx: TyCtxt<'tcx>, def_id: DefId, mut mk_kind: F) ->
})
}
fn fill_item<F>(
pub fn fill_item<F>(
substs: &mut SmallVec<[GenericArg<'tcx>; 8]>,
tcx: TyCtxt<'tcx>,
defs: &ty::Generics,
......@@ -249,7 +249,7 @@ fn fill_item<F>(
Self::fill_single(substs, defs, mk_kind)
}
fn fill_single<F>(
pub fn fill_single<F>(
substs: &mut SmallVec<[GenericArg<'tcx>; 8]>,
defs: &ty::Generics,
mk_kind: &mut F,
......
......@@ -1225,6 +1225,7 @@ fn compare_type_predicate_entailment<'tcx>(
/// For default associated types the normalization is not possible (the value
/// from the impl could be overridden). We also can't normalize generic
/// associated types (yet) because they contain bound parameters.
#[tracing::instrument(level = "debug", skip(tcx))]
pub fn check_type_bounds<'tcx>(
tcx: TyCtxt<'tcx>,
trait_ty: &ty::AssocItem,
......@@ -1238,10 +1239,83 @@ pub fn check_type_bounds<'tcx>(
// type Bar<C> =...
// }
//
// - `impl_substs` would be `[A, B, C]`
// - `rebased_substs` would be `[(A, B), u32, C]`, combining the substs from
// the *trait* with the generic associated type parameters.
let impl_ty_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id);
// - `impl_trait_ref` would be `<(A, B) as Foo<u32>>
// - `impl_ty_substs` would be `[A, B, ^0.0]` (`^0.0` here is the bound var with db 0 and index 0)
// - `rebased_substs` would be `[(A, B), u32, ^0.0]`, combining the substs from
// the *trait* with the generic associated type parameters (as bound vars).
//
// A note regarding the use of bound vars here:
// Imagine as an example
// ```
// trait Family {
// type Member<C: Eq>;
// }
//
// impl Family for VecFamily {
// type Member<C: Eq> = i32;
// }
// ```
// Here, we would generate
// ```notrust
// forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) }
// ```
// when we really would like to generate
// ```notrust
// forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) :- Implemented(C: Eq) }
// ```
// But, this is probably fine, because although the first clause can be used with types C that
// do not implement Eq, for it to cause some kind of problem, there would have to be a
// VecFamily::Member<X> for some type X where !(X: Eq), that appears in the value of type
// Member<C: Eq> = .... That type would fail a well-formedness check that we ought to be doing
// elsewhere, which would check that any <T as Family>::Member<X> meets the bounds declared in
// the trait (notably, that X: Eq and T: Family).
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 =
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);
......@@ -1270,18 +1344,26 @@ pub fn check_type_bounds<'tcx>(
// impl<T> X for T where T: X { type Y = <T as X>::Y; }
}
_ => predicates.push(
ty::Binder::dummy(ty::ProjectionPredicate {
projection_ty: ty::ProjectionTy {
item_def_id: trait_ty.def_id,
substs: rebased_substs,
ty::Binder::bind_with_vars(
ty::ProjectionPredicate {
projection_ty: ty::ProjectionTy {
item_def_id: trait_ty.def_id,
substs: rebased_substs,
},
ty: impl_ty_value,
},
ty: impl_ty_value,
})
bound_vars,
)
.to_predicate(tcx),
),
};
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| {
let constness = impl_ty
......@@ -1308,6 +1390,7 @@ pub fn check_type_bounds<'tcx>(
.explicit_item_bounds(trait_ty.def_id)
.iter()
.map(|&(bound, span)| {
debug!(?bound);
let concrete_ty_bound = bound.subst(tcx, rebased_substs);
debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound);
......
// Derived from `issue-87429`. A test that ensures that using bound vars in the
// predicates in the param env when checking that an associated type satisfies
// its bounds does not cause us to not be able to use the bounds on the parameters.
// check-pass
#![feature(generic_associated_types)]
trait Family {
type Member<'a, C: Eq>: for<'b> MyBound<'b, C>;
}
trait MyBound<'a, C> { }
impl<'a, C: Eq> MyBound<'a, C> for i32 { }
impl Family for () {
type Member<'a, C: Eq> = i32;
}
fn main() {}
// check-fail
#![feature(associated_type_defaults)]
#![feature(generic_associated_types)]
trait Family {
// Fine, i32: PartialEq<i32>
type Member<'a>: for<'b> PartialEq<Self::Member<'b>> = i32;
}
struct Foo;
trait Family2 {
// Not fine, not Foo: PartialEq<Foo>
type Member<'a>: for<'b> PartialEq<Self::Member<'b>> = Foo;
//~^ ERROR can't compare
}
fn main() {}
error[E0277]: can't compare `Foo` with `Foo`
--> $DIR/issue-87429-associated-type-default.rs:14:5
|
LL | type Member<'a>: for<'b> PartialEq<Self::Member<'b>> = Foo;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `Foo == Foo`
|
= help: the trait `PartialEq` is not implemented for `Foo`
note: required by a bound in `Family2::Member`
--> $DIR/issue-87429-associated-type-default.rs:14:22
|
LL | type Member<'a>: for<'b> PartialEq<Self::Member<'b>> = Foo;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Family2::Member`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.
// check-fail
#![feature(specialization)]
//~^ WARN incomplete
#![feature(generic_associated_types)]
trait Family {
type Member<'a>: for<'b> PartialEq<Self::Member<'b>>;
}
struct I32Family;
impl Family for I32Family {
default type Member<'a> = i32;
}
struct Foo;
struct FooFamily;
impl Family for FooFamily {
default type Member<'a> = Foo;
//~^ ERROR can't compare
}
fn main() {}
warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/issue-87429-specialization.rs:3:12
|
LL | #![feature(specialization)]
| ^^^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
= help: consider using `min_specialization` instead, which is more stable and complete
error[E0277]: can't compare `Foo` with `Foo`
--> $DIR/issue-87429-specialization.rs:21:5
|
LL | default type Member<'a> = Foo;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `Foo == Foo`
|
= help: the trait `PartialEq` is not implemented for `Foo`
note: required by a bound in `Family::Member`
--> $DIR/issue-87429-specialization.rs:8:22
|
LL | type Member<'a>: for<'b> PartialEq<Self::Member<'b>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Family::Member`
error: aborting due to previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0277`.
// 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() {}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册