Add term to ExistentialProjection

Also prevent ICE when adding a const in associated const equality.
This commit is contained in:
kadmin 2022-01-13 07:39:58 +00:00
parent f396888c4d
commit 1c1ce2fbda
35 changed files with 213 additions and 71 deletions

View file

@ -724,6 +724,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
gate_all!(half_open_range_patterns, "half-open range patterns are unstable");
gate_all!(inline_const, "inline-const is experimental");
gate_all!(inline_const_pat, "inline-const in pattern position is experimental");
gate_all!(associated_const_equality, "associated const equality is incomplete");
// All uses of `gate_all!` below this point were added in #65742,
// and subsequently disabled (with the non-early gating readded).

View file

@ -203,8 +203,9 @@ fn push_debuginfo_type_name<'tcx>(
let projection_bounds: SmallVec<[_; 4]> = trait_data
.projection_bounds()
.map(|bound| {
let ExistentialProjection { item_def_id, ty, .. } = bound.skip_binder();
(item_def_id, ty)
let ExistentialProjection { item_def_id, term, .. } = bound.skip_binder();
// FIXME(associated_const_equality): allow for consts here
(item_def_id, term.ty().unwrap())
})
.collect();

View file

@ -288,6 +288,8 @@ declare_features! (
(active, asm_sym, "1.58.0", Some(72016), None),
/// Allows the `may_unwind` option in inline assembly.
(active, asm_unwind, "1.58.0", Some(72016), None),
/// Allows users to enforce equality of associated constants `TraitImpl<AssocConst=3>`.
(active, associated_const_equality, "1.58.0", Some(92827), None),
/// Allows the user of associated type bounds.
(active, associated_type_bounds, "1.34.0", Some(52662), None),
/// Allows associated type defaults.

View file

@ -69,7 +69,7 @@ use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::{
self,
subst::{GenericArgKind, Subst, SubstsRef},
Region, Term, Ty, TyCtxt, TypeFoldable,
Region, Ty, TyCtxt, TypeFoldable,
};
use rustc_span::{sym, BytePos, DesugaringKind, MultiSpan, Pos, Span};
use rustc_target::spec::abi;
@ -1780,11 +1780,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
{
if projection_predicate.projection_ty.item_def_id == item_def_id {
// We don't account for multiple `Future::Output = Ty` contraints.
match projection_predicate.term {
Term::Ty(ty) => return Some(ty),
// Can return None, but not sure if that makes sense?
Term::Const(_c) => todo!(),
}
return projection_predicate.term.ty();
}
}
}

View file

@ -4,7 +4,7 @@ use crate::ty::subst::{GenericArg, GenericArgKind};
use crate::ty::TyKind::*;
use crate::ty::{
ConstKind, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, InferTy,
ProjectionTy, TyCtxt, TyS, TypeAndMut,
ProjectionTy, Term, TyCtxt, TyS, TypeAndMut,
};
use rustc_errors::{Applicability, DiagnosticBuilder};
@ -105,8 +105,14 @@ impl<'tcx> TyS<'tcx> {
ExistentialPredicate::Trait(ExistentialTraitRef { substs, .. }) => {
substs.iter().all(generic_arg_is_suggestible)
}
ExistentialPredicate::Projection(ExistentialProjection { substs, ty, .. }) => {
ty.is_suggestable() && substs.iter().all(generic_arg_is_suggestible)
ExistentialPredicate::Projection(ExistentialProjection {
substs, term, ..
}) => {
let term_is_suggestable = match term {
Term::Ty(ty) => ty.is_suggestable(),
Term::Const(c) => const_is_suggestable(c.val),
};
term_is_suggestable && substs.iter().all(generic_arg_is_suggestible)
}
_ => true,
}),

View file

@ -320,7 +320,10 @@ impl FlagComputation {
fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<'_>) {
self.add_substs(projection.substs);
self.add_ty(projection.ty);
match projection.term {
ty::Term::Ty(ty) => self.add_ty(ty),
ty::Term::Const(ct) => self.add_const(ct),
}
}
fn add_projection_ty(&mut self, projection_ty: ty::ProjectionTy<'_>) {

View file

@ -795,7 +795,7 @@ pub struct CoercePredicate<'tcx> {
}
pub type PolyCoercePredicate<'tcx> = ty::Binder<'tcx, CoercePredicate<'tcx>>;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)]
#[derive(HashStable, TypeFoldable)]
pub enum Term<'tcx> {
Ty(Ty<'tcx>),

View file

@ -905,29 +905,27 @@ pub trait PrettyPrinter<'tcx>:
}
for (assoc_item_def_id, term) in assoc_items {
let ty = match term.skip_binder() {
Term::Ty(ty) => ty,
Term::Const(c) => {
p!(print(c));
continue;
}
};
if !first {
p!(", ");
}
p!(write("{} = ", self.tcx().associated_item(assoc_item_def_id).ident));
// Skip printing `<[generator@] as Generator<_>>::Return` from async blocks
match ty.kind() {
ty::Projection(ty::ProjectionTy { item_def_id, .. })
if Some(*item_def_id) == self.tcx().lang_items().generator_return() =>
{
p!("[async output]")
match term.skip_binder() {
Term::Ty(ty) => {
// Skip printing `<[generator@] as Generator<_>>::Return` from async blocks
if matches!(
ty.kind(), ty::Projection(ty::ProjectionTy { item_def_id, .. })
if Some(*item_def_id) == self.tcx().lang_items().generator_return()
) {
p!("[async output]")
} else {
p!(print(ty))
}
}
_ => {
p!(print(ty))
Term::Const(c) => {
p!(print(c));
}
}
};
first = false;
}
@ -1031,7 +1029,11 @@ pub trait PrettyPrinter<'tcx>:
let mut projections = predicates.projection_bounds();
if let (Some(proj), None) = (projections.next(), projections.next()) {
let tys: Vec<_> = args.iter().map(|k| k.expect_ty()).collect();
p!(pretty_fn_sig(&tys, false, proj.skip_binder().ty));
p!(pretty_fn_sig(
&tys,
false,
proj.skip_binder().term.ty().expect("Return type was a const")
));
resugared = true;
}
}
@ -2454,7 +2456,7 @@ define_print_and_forward_display! {
ty::ExistentialProjection<'tcx> {
let name = cx.tcx().associated_item(self.item_def_id).ident;
p!(write("{} = ", name), print(self.ty))
p!(write("{} = ", name), print(self.term))
}
ty::ExistentialPredicate<'tcx> {

View file

@ -291,11 +291,11 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialProjection<'tcx> {
b.item_def_id,
)))
} else {
let ty = relation.relate_with_variance(
let term = relation.relate_with_variance(
ty::Invariant,
ty::VarianceDiagInfo::default(),
a.ty,
b.ty,
a.term,
b.term,
)?;
let substs = relation.relate_with_variance(
ty::Invariant,
@ -303,7 +303,7 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialProjection<'tcx> {
a.substs,
b.substs,
)?;
Ok(ty::ExistentialProjection { item_def_id: a.item_def_id, substs, ty })
Ok(ty::ExistentialProjection { item_def_id: a.item_def_id, substs, term })
}
}
}

View file

@ -423,7 +423,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialProjection<'a> {
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
tcx.lift(self.substs).map(|substs| ty::ExistentialProjection {
substs,
ty: tcx.lift(self.ty).expect("type must lift when substs do"),
term: tcx.lift(self.term).expect("type must lift when substs do"),
item_def_id: self.item_def_id,
})
}

View file

@ -1540,7 +1540,7 @@ impl From<BoundVar> for BoundTy {
pub struct ExistentialProjection<'tcx> {
pub item_def_id: DefId,
pub substs: SubstsRef<'tcx>,
pub ty: Ty<'tcx>,
pub term: Term<'tcx>,
}
pub type PolyExistentialProjection<'tcx> = Binder<'tcx, ExistentialProjection<'tcx>>;
@ -1570,7 +1570,7 @@ impl<'tcx> ExistentialProjection<'tcx> {
item_def_id: self.item_def_id,
substs: tcx.mk_substs_trait(self_ty, self.substs),
},
term: self.ty.into(),
term: self.term,
}
}
@ -1580,15 +1580,11 @@ impl<'tcx> ExistentialProjection<'tcx> {
) -> Self {
// Assert there is a Self.
projection_predicate.projection_ty.substs.type_at(0);
let ty = match projection_predicate.term {
Term::Ty(ty) => ty,
Term::Const(_c) => unimplemented!(),
};
Self {
item_def_id: projection_predicate.projection_ty.item_def_id,
substs: tcx.intern_substs(&projection_predicate.projection_ty.substs[1..]),
ty,
term: projection_predicate.term,
}
}
}

View file

@ -157,7 +157,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
stack.extend(obj.iter().rev().flat_map(|predicate| {
let (substs, opt_ty) = match predicate.skip_binder() {
ty::ExistentialPredicate::Trait(tr) => (tr.substs, None),
ty::ExistentialPredicate::Projection(p) => (p.substs, Some(p.ty)),
ty::ExistentialPredicate::Projection(p) => (p.substs, Some(p.term)),
ty::ExistentialPredicate::AutoTrait(_) =>
// Empty iterator
{
@ -165,7 +165,10 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
}
};
substs.iter().rev().chain(opt_ty.map(|ty| ty.into()))
substs.iter().rev().chain(opt_ty.map(|term| match term {
ty::Term::Ty(ty) => ty.into(),
ty::Term::Const(ct) => ct.into(),
}))
}));
}
ty::Adt(_, substs)

View file

@ -505,7 +505,10 @@ impl<'a> Parser<'a> {
let span = ident.span.to(self.prev_token.span);
let term = match arg {
Some(GenericArg::Type(ty)) => ty.into(),
Some(GenericArg::Const(c)) => c.into(),
Some(GenericArg::Const(c)) => {
self.sess.gated_spans.gate(sym::associated_const_equality, span);
c.into()
}
Some(GenericArg::Lifetime(lt)) => {
self.struct_span_err(span, "associated lifetimes are not supported")
.span_label(lt.ident.span, "the lifetime is given here")

View file

@ -343,6 +343,7 @@ symbols! {
assert_receiver_is_total_eq,
assert_uninit_valid,
assert_zero_valid,
associated_const_equality,
associated_consts,
associated_type_bounds,
associated_type_defaults,

View file

@ -559,7 +559,10 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> {
let name = cx.tcx.associated_item(projection.item_def_id).ident;
cx.push("p");
cx.push_ident(name.as_str());
cx = projection.ty.print(cx)?;
cx = match projection.term {
ty::Term::Ty(ty) => ty.print(cx),
ty::Term::Const(c) => c.print(cx),
}?;
}
ty::ExistentialPredicate::AutoTrait(def_id) => {
cx = cx.print_def_path(*def_id, &[])?;

View file

@ -756,8 +756,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
// when we started out trying to unify
// some inference variables. See the comment above
// for more infomration
if p.term().skip_binder().ty().map_or(false, |ty| ty.has_infer_types())
{
if p.term().skip_binder().ty().has_infer_types() {
if !self.evaluate_nested_obligations(
ty,
v.into_iter(),
@ -779,7 +778,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
// However, we should always make progress (either by generating
// subobligations or getting an error) when we started off with
// inference variables
if p.term().skip_binder().ty().has_infer_types() {
if p.term().skip_binder().has_infer_types() {
panic!("Unexpected result when selecting {:?} {:?}", ty, obligation)
}
}

View file

@ -1314,7 +1314,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
| ObligationCauseCode::ObjectCastObligation(_)
| ObligationCauseCode::OpaqueType
);
// FIXME(...): Handle Consts here
// FIXME(associated_const_equality): Handle Consts here
let data_ty = data.term.ty().unwrap();
if let Err(error) = self.at(&obligation.cause, obligation.param_env).eq_exp(
is_normalized_ty_expected,

View file

@ -571,7 +571,7 @@ fn object_ty_for_trait<'tcx>(
// `trait MyTrait: for<'s> OtherTrait<&'s T, Output=bool>`.
super_trait_ref.map_bound(|super_trait_ref| {
ty::ExistentialPredicate::Projection(ty::ExistentialProjection {
ty: tcx.mk_projection(item.def_id, super_trait_ref.substs),
term: tcx.mk_projection(item.def_id, super_trait_ref.substs).into(),
item_def_id: item.def_id,
substs: super_trait_ref.substs,
})

View file

@ -212,7 +212,7 @@ fn project_and_unify_type<'cx, 'tcx>(
debug!(?normalized_ty, ?obligations, "project_and_unify_type result");
let infcx = selcx.infcx();
// FIXME(...): Handle consts here as well as types.
// FIXME(associated_const_equality): Handle consts here as well as types.
let obligation_pred_ty = obligation.predicate.term.ty().unwrap();
match infcx.at(&obligation.cause, obligation.param_env).eq(normalized_ty, obligation_pred_ty) {
Ok(InferOk { obligations: inferred_obligations, value: () }) => {

View file

@ -226,6 +226,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::AliasEq<RustInterner<'tcx>>>
for rustc_middle::ty::ProjectionPredicate<'tcx>
{
fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::AliasEq<RustInterner<'tcx>> {
// FIXME(associated_const_equality): teach chalk about terms for alias eq.
chalk_ir::AliasEq {
ty: self.term.ty().unwrap().lower_into(interner),
alias: self.projection_ty.lower_into(interner),
@ -663,7 +664,8 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Binders<chalk_ir::QuantifiedWhereClauses<Ru
.mk_substs_trait(self_ty, predicate.substs)
.lower_into(interner),
}),
ty: predicate.ty.lower_into(interner),
// FIXME(associated_const_equality): teach chalk about terms for alias eq.
ty: predicate.term.ty().unwrap().lower_into(interner),
}),
),
ty::ExistentialPredicate::AutoTrait(def_id) => chalk_ir::Binders::new(

View file

@ -1136,9 +1136,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.associated_items(candidate.def_id())
.filter_by_name_unhygienic(assoc_ident.name)
.find(|i| {
i.kind == ty::AssocKind::Type && i.ident.normalize_to_macros_2_0() == assoc_ident
(i.kind == ty::AssocKind::Type || i.kind == ty::AssocKind::Const)
&& i.ident.normalize_to_macros_2_0() == assoc_ident
})
.expect("missing associated type");
// FIXME(associated_const_equality): need to handle assoc_consts here as well.
if assoc_ty.kind == ty::AssocKind::Const {
tcx.sess
.struct_span_err(path_span, &format!("associated const equality is incomplete"))
.span_label(path_span, "cannot yet relate associated const")
.emit();
return Err(ErrorReported);
}
if !assoc_ty.vis.is_accessible_from(def_scope, tcx) {
tcx.sess

View file

@ -308,11 +308,14 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
}
for projection in data.projection_bounds() {
self.add_constraints_from_ty(
current,
projection.skip_binder().ty,
self.invariant,
);
match projection.skip_binder().term {
ty::Term::Ty(ty) => {
self.add_constraints_from_ty(current, ty, self.invariant);
}
ty::Term::Const(c) => {
self.add_constraints_from_const(current, c, self.invariant)
}
}
}
}

View file

@ -83,7 +83,9 @@ def check_type(ty):
check_type(arg["const"]["type"])
for binding in args["angle_bracketed"]["bindings"]:
if "equality" in binding["binding"]:
check_type(binding["binding"]["equality"])
term = binding["binding"]["equality"]
if "type" in term: check_type(term["type"])
elif "const" in term: check_type(term["const"])
elif "constraint" in binding["binding"]:
for bound in binding["binding"]["constraint"]:
check_generic_bound(bound)

View file

@ -1523,7 +1523,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
bindings.push(TypeBinding {
name: cx.tcx.associated_item(pb.item_def_id()).ident.name,
kind: TypeBindingKind::Equality {
term: pb.skip_binder().ty.clean(cx).into(),
term: pb.skip_binder().term.clean(cx).into(),
},
});
}

View file

@ -1,5 +1,3 @@
// run-pass
pub trait Foo {
const N: usize;
}
@ -14,6 +12,10 @@ const TEST:usize = 3;
fn foo<F: Foo<N=3>>() {}
//~^ ERROR associated const equality is incomplete
//~| ERROR associated const equality is incomplete
fn bar<F: Foo<N={TEST}>>() {}
//~^ ERROR associated const equality is incomplete
//~| ERROR associated const equality is incomplete
fn main() {}

View file

@ -0,0 +1,33 @@
error[E0658]: associated const equality is incomplete
--> $DIR/assoc-const.rs:14:15
|
LL | fn foo<F: Foo<N=3>>() {}
| ^^^
|
= note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
= help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
error[E0658]: associated const equality is incomplete
--> $DIR/assoc-const.rs:17:15
|
LL | fn bar<F: Foo<N={TEST}>>() {}
| ^^^^^^^^
|
= note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
= help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
error: associated const equality is incomplete
--> $DIR/assoc-const.rs:14:15
|
LL | fn foo<F: Foo<N=3>>() {}
| ^^^ cannot yet relate associated const
error: associated const equality is incomplete
--> $DIR/assoc-const.rs:17:15
|
LL | fn bar<F: Foo<N={TEST}>>() {}
| ^^^^^^^^ cannot yet relate associated const
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0658`.

View file

@ -9,6 +9,7 @@ const T: usize = 42;
impl Foo<N = 3> for Bar {
//~^ ERROR this trait takes 1 generic argument but 0 generic arguments were supplied
//~| ERROR associated type bindings are not allowed here
//~| ERROR associated const equality is incomplete
fn do_x(&self) -> [u8; 3] {
[0u8; 3]
}

View file

@ -1,3 +1,12 @@
error[E0658]: associated const equality is incomplete
--> $DIR/issue-89013-no-kw.rs:9:10
|
LL | impl Foo<N = 3> for Bar {
| ^^^^^
|
= note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
= help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
--> $DIR/issue-89013-no-kw.rs:9:6
|
@ -20,7 +29,7 @@ error[E0229]: associated type bindings are not allowed here
LL | impl Foo<N = 3> for Bar {
| ^^^^^ associated type not allowed here
error: aborting due to 2 previous errors
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0107, E0229.
Some errors have detailed explanations: E0107, E0229, E0658.
For more information about an error, try `rustc --explain E0107`.

View file

@ -10,6 +10,7 @@ impl Foo<N = const 3> for Bar {
//~^ ERROR expected lifetime, type, or constant, found keyword `const`
//~| ERROR this trait takes 1 generic
//~| ERROR associated type bindings are not allowed here
//~| ERROR associated const equality is incomplete
fn do_x(&self) -> [u8; 3] {
[0u8; 3]
}

View file

@ -10,6 +10,15 @@ LL - impl Foo<N = const 3> for Bar {
LL + impl Foo<N = 3> for Bar {
|
error[E0658]: associated const equality is incomplete
--> $DIR/issue-89013.rs:9:10
|
LL | impl Foo<N = const 3> for Bar {
| ^^^^^^^^^^^
|
= note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
= help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
--> $DIR/issue-89013.rs:9:6
|
@ -32,7 +41,7 @@ error[E0229]: associated type bindings are not allowed here
LL | impl Foo<N = const 3> for Bar {
| ^^^^^^^^^^^ associated type not allowed here
error: aborting due to 3 previous errors
error: aborting due to 4 previous errors
Some errors have detailed explanations: E0107, E0229.
Some errors have detailed explanations: E0107, E0229, E0658.
For more information about an error, try `rustc --explain E0107`.

View file

@ -0,0 +1,16 @@
pub trait TraitWAssocConst {
const A: usize;
}
pub struct Demo {}
impl TraitWAssocConst for Demo {
const A: usize = 32;
}
fn foo<A: TraitWAssocConst<A=32>>() {}
//~^ ERROR associated const equality
//~| ERROR associated const equality
fn main() {
foo::<Demo>();
}

View file

@ -0,0 +1,18 @@
error[E0658]: associated const equality is incomplete
--> $DIR/feature-gate-associated_const_equality.rs:10:28
|
LL | fn foo<A: TraitWAssocConst<A=32>>() {}
| ^^^^
|
= note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
= help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
error: associated const equality is incomplete
--> $DIR/feature-gate-associated_const_equality.rs:10:28
|
LL | fn foo<A: TraitWAssocConst<A=32>>() {}
| ^^^^ cannot yet relate associated const
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0658`.

View file

@ -1,9 +1,9 @@
// run-pass
#[cfg(FALSE)]
fn syntax() {
bar::<Item = 42>();
//~^ ERROR associated const equality is incomplete
bar::<Item = { 42 }>();
//~^ ERROR associated const equality is incomplete
}
fn main() {}

View file

@ -0,0 +1,21 @@
error[E0658]: associated const equality is incomplete
--> $DIR/recover-assoc-const-constraint.rs:3:11
|
LL | bar::<Item = 42>();
| ^^^^^^^^^
|
= note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
= help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
error[E0658]: associated const equality is incomplete
--> $DIR/recover-assoc-const-constraint.rs:5:11
|
LL | bar::<Item = { 42 }>();
| ^^^^^^^^^^^^^
|
= note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
= help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0658`.

View file

@ -211,7 +211,7 @@ impl Rewrite for ast::AssocConstraintKind {
match self {
ast::AssocConstraintKind::Equality { term } => match term {
Term::Ty(ty) => ty.rewrite(context, shape),
Term::Const(c) => c.rewrite(context,shape),
Term::Const(c) => c.rewrite(context, shape),
},
ast::AssocConstraintKind::Bound { bounds } => bounds.rewrite(context, shape),
}