Auto merge of #87648 - JulianKnodt:const_eq_constrain, r=oli-obk

allow eq constraints on associated constants

Updates #70256

(cc `@varkor,` `@Centril)`
This commit is contained in:
bors 2022-01-18 09:58:39 +00:00
commit 7bc7be860f
83 changed files with 776 additions and 382 deletions

View File

@ -335,7 +335,7 @@ dependencies = [
"cargo-test-macro",
"cargo-test-support",
"cargo-util",
"clap 3.0.6",
"clap",
"crates-io",
"crossbeam-utils",
"curl",
@ -615,28 +615,13 @@ dependencies = [
"ansi_term 0.12.1",
"atty",
"bitflags",
"strsim 0.8.0",
"textwrap 0.11.0",
"strsim",
"textwrap",
"unicode-width",
"vec_map",
"yaml-rust 0.3.5",
]
[[package]]
name = "clap"
version = "3.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1957aa4a5fb388f0a0a73ce7556c5b42025b874e5cdc2c670775e346e97adec0"
dependencies = [
"atty",
"bitflags",
"indexmap",
"os_str_bytes",
"strsim 0.10.0",
"termcolor",
"textwrap 0.14.2",
]
[[package]]
name = "clippy"
version = "0.1.60"
@ -669,7 +654,7 @@ version = "0.0.1"
dependencies = [
"bytecount",
"cargo_metadata 0.14.0",
"clap 2.34.0",
"clap",
"indoc",
"itertools 0.10.1",
"opener",
@ -1751,7 +1736,7 @@ name = "installer"
version = "0.0.0"
dependencies = [
"anyhow",
"clap 2.34.0",
"clap",
"flate2",
"lazy_static",
"num_cpus",
@ -2190,7 +2175,7 @@ dependencies = [
"ammonia",
"anyhow",
"chrono",
"clap 2.34.0",
"clap",
"elasticlunr-rs",
"env_logger 0.7.1",
"handlebars",
@ -2521,15 +2506,6 @@ dependencies = [
"winapi",
]
[[package]]
name = "os_str_bytes"
version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
dependencies = [
"memchr",
]
[[package]]
name = "output_vt100"
version = "0.1.2"
@ -2934,7 +2910,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0b4b5faaf07040474e8af74a9e19ff167d5d204df5db5c5c765edecfb900358"
dependencies = [
"bitflags",
"clap 2.34.0",
"clap",
"derive_more",
"env_logger 0.7.1",
"humantime 2.0.1",
@ -3282,7 +3258,7 @@ dependencies = [
name = "rustbook"
version = "0.1.0"
dependencies = [
"clap 2.34.0",
"clap",
"env_logger 0.7.1",
"mdbook",
]
@ -4898,19 +4874,13 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "structopt"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40b9788f4202aa75c240ecc9c15c65185e6a39ccdeb0fd5d008b98825464c87c"
dependencies = [
"clap 2.34.0",
"clap",
"lazy_static",
"structopt-derive",
]
@ -5081,12 +5051,6 @@ dependencies = [
"unicode-width",
]
[[package]]
name = "textwrap"
version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
[[package]]
name = "thiserror"
version = "1.0.30"

View File

@ -224,7 +224,7 @@ pub enum AngleBracketedArg {
/// Argument for a generic parameter.
Arg(GenericArg),
/// Constraint for an associated item.
Constraint(AssocTyConstraint),
Constraint(AssocConstraint),
}
impl AngleBracketedArg {
@ -1843,19 +1843,38 @@ impl UintTy {
/// A constraint on an associated type (e.g., `A = Bar` in `Foo<A = Bar>` or
/// `A: TraitA + TraitB` in `Foo<A: TraitA + TraitB>`).
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct AssocTyConstraint {
pub struct AssocConstraint {
pub id: NodeId,
pub ident: Ident,
pub gen_args: Option<GenericArgs>,
pub kind: AssocTyConstraintKind,
pub kind: AssocConstraintKind,
pub span: Span,
}
/// The kinds of an `AssocTyConstraint`.
/// The kinds of an `AssocConstraint`.
#[derive(Clone, Encodable, Decodable, Debug)]
pub enum AssocTyConstraintKind {
/// E.g., `A = Bar` in `Foo<A = Bar>`.
Equality { ty: P<Ty> },
pub enum Term {
Ty(P<Ty>),
Const(AnonConst),
}
impl From<P<Ty>> for Term {
fn from(v: P<Ty>) -> Self {
Term::Ty(v)
}
}
impl From<AnonConst> for Term {
fn from(v: AnonConst) -> Self {
Term::Const(v)
}
}
/// The kinds of an `AssocConstraint`.
#[derive(Clone, Encodable, Decodable, Debug)]
pub enum AssocConstraintKind {
/// E.g., `A = Bar`, `A = 3` in `Foo<A = Bar>` where A is an associated type.
Equality { term: Term },
/// E.g. `A: TraitA + TraitB` in `Foo<A: TraitA + TraitB>`.
Bound { bounds: GenericBounds },
}

View File

@ -165,8 +165,8 @@ pub trait MutVisitor: Sized {
noop_visit_lifetime(l, self);
}
fn visit_ty_constraint(&mut self, t: &mut AssocTyConstraint) {
noop_visit_ty_constraint(t, self);
fn visit_constraint(&mut self, t: &mut AssocConstraint) {
noop_visit_constraint(t, self);
}
fn visit_foreign_mod(&mut self, nm: &mut ForeignMod) {
@ -430,8 +430,8 @@ pub fn noop_flat_map_arm<T: MutVisitor>(mut arm: Arm, vis: &mut T) -> SmallVec<[
smallvec![arm]
}
pub fn noop_visit_ty_constraint<T: MutVisitor>(
AssocTyConstraint { id, ident, gen_args, kind, span }: &mut AssocTyConstraint,
pub fn noop_visit_constraint<T: MutVisitor>(
AssocConstraint { id, ident, gen_args, kind, span }: &mut AssocConstraint,
vis: &mut T,
) {
vis.visit_id(id);
@ -440,12 +440,11 @@ pub fn noop_visit_ty_constraint<T: MutVisitor>(
vis.visit_generic_args(gen_args);
}
match kind {
AssocTyConstraintKind::Equality { ref mut ty } => {
vis.visit_ty(ty);
}
AssocTyConstraintKind::Bound { ref mut bounds } => {
visit_bounds(bounds, vis);
}
AssocConstraintKind::Equality { ref mut term } => match term {
Term::Ty(ty) => vis.visit_ty(ty),
Term::Const(c) => vis.visit_anon_const(c),
},
AssocConstraintKind::Bound { ref mut bounds } => visit_bounds(bounds, vis),
}
vis.visit_span(span);
}
@ -555,7 +554,7 @@ pub fn noop_visit_angle_bracketed_parameter_data<T: MutVisitor>(
let AngleBracketedArgs { args, span } = data;
visit_vec(args, |arg| match arg {
AngleBracketedArg::Arg(arg) => vis.visit_generic_arg(arg),
AngleBracketedArg::Constraint(constraint) => vis.visit_ty_constraint(constraint),
AngleBracketedArg::Constraint(constraint) => vis.visit_constraint(constraint),
});
vis.visit_span(span);
}

View File

@ -190,8 +190,8 @@ pub trait Visitor<'ast>: Sized {
fn visit_generic_arg(&mut self, generic_arg: &'ast GenericArg) {
walk_generic_arg(self, generic_arg)
}
fn visit_assoc_ty_constraint(&mut self, constraint: &'ast AssocTyConstraint) {
walk_assoc_ty_constraint(self, constraint)
fn visit_assoc_constraint(&mut self, constraint: &'ast AssocConstraint) {
walk_assoc_constraint(self, constraint)
}
fn visit_attribute(&mut self, attr: &'ast Attribute) {
walk_attribute(self, attr)
@ -464,7 +464,7 @@ where
for arg in &data.args {
match arg {
AngleBracketedArg::Arg(a) => visitor.visit_generic_arg(a),
AngleBracketedArg::Constraint(c) => visitor.visit_assoc_ty_constraint(c),
AngleBracketedArg::Constraint(c) => visitor.visit_assoc_constraint(c),
}
}
}
@ -486,19 +486,17 @@ where
}
}
pub fn walk_assoc_ty_constraint<'a, V: Visitor<'a>>(
visitor: &mut V,
constraint: &'a AssocTyConstraint,
) {
pub fn walk_assoc_constraint<'a, V: Visitor<'a>>(visitor: &mut V, constraint: &'a AssocConstraint) {
visitor.visit_ident(constraint.ident);
if let Some(ref gen_args) = constraint.gen_args {
visitor.visit_generic_args(gen_args.span(), gen_args);
}
match constraint.kind {
AssocTyConstraintKind::Equality { ref ty } => {
visitor.visit_ty(ty);
}
AssocTyConstraintKind::Bound { ref bounds } => {
AssocConstraintKind::Equality { ref term } => match term {
Term::Ty(ty) => visitor.visit_ty(ty),
Term::Const(c) => visitor.visit_anon_const(c),
},
AssocConstraintKind::Bound { ref bounds } => {
walk_list!(visitor, visit_param_bound, bounds);
}
}

View File

@ -960,7 +960,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
/// returns a `hir::TypeBinding` representing `Item`.
fn lower_assoc_ty_constraint(
&mut self,
constraint: &AssocTyConstraint,
constraint: &AssocConstraint,
mut itctx: ImplTraitContext<'_, 'hir>,
) -> hir::TypeBinding<'hir> {
debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx);
@ -997,10 +997,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
};
let kind = match constraint.kind {
AssocTyConstraintKind::Equality { ref ty } => {
hir::TypeBindingKind::Equality { ty: self.lower_ty(ty, itctx) }
AssocConstraintKind::Equality { ref term } => {
let term = match term {
Term::Ty(ref ty) => self.lower_ty(ty, itctx).into(),
Term::Const(ref c) => self.lower_anon_const(c).into(),
};
hir::TypeBindingKind::Equality { term }
}
AssocTyConstraintKind::Bound { ref bounds } => {
AssocConstraintKind::Bound { ref bounds } => {
let mut capturable_lifetimes;
let mut parent_def_id = self.current_hir_id_owner;
// Piggy-back on the `impl Trait` context to figure out the correct behavior.
@ -1078,7 +1082,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
itctx,
);
hir::TypeBindingKind::Equality { ty }
hir::TypeBindingKind::Equality { term: ty.into() }
})
} else {
// Desugar `AssocTy: Bounds` into a type binding where the

View File

@ -420,7 +420,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
ty: &'hir hir::Ty<'hir>,
) -> hir::TypeBinding<'hir> {
let ident = Ident::with_dummy_span(hir::FN_OUTPUT_NAME);
let kind = hir::TypeBindingKind::Equality { ty };
let kind = hir::TypeBindingKind::Equality { term: ty.into() };
let args = arena_vec![self;];
let bindings = arena_vec![self;];
let gen_args = self.arena.alloc(hir::GenericArgs {

View File

@ -138,10 +138,10 @@ impl<'a> AstValidator<'a> {
self.outer_impl_trait = old;
}
fn visit_assoc_ty_constraint_from_generic_args(&mut self, constraint: &'a AssocTyConstraint) {
fn visit_assoc_constraint_from_generic_args(&mut self, constraint: &'a AssocConstraint) {
match constraint.kind {
AssocTyConstraintKind::Equality { .. } => {}
AssocTyConstraintKind::Bound { .. } => {
AssocConstraintKind::Equality { .. } => {}
AssocConstraintKind::Bound { .. } => {
if self.is_assoc_ty_bound_banned {
self.err_handler().span_err(
constraint.span,
@ -150,7 +150,7 @@ impl<'a> AstValidator<'a> {
}
}
}
self.visit_assoc_ty_constraint(constraint);
self.visit_assoc_constraint(constraint);
}
// Mirrors `visit::walk_ty`, but tracks relevant state.
@ -1277,7 +1277,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
// are allowed to contain nested `impl Trait`.
AngleBracketedArg::Constraint(constraint) => {
self.with_impl_trait(None, |this| {
this.visit_assoc_ty_constraint_from_generic_args(constraint);
this.visit_assoc_constraint_from_generic_args(constraint);
});
}
}
@ -1586,12 +1586,12 @@ fn deny_equality_constraints(
let len = assoc_path.segments.len() - 1;
let gen_args = args.as_ref().map(|p| (**p).clone());
// Build `<Bar = RhsTy>`.
let arg = AngleBracketedArg::Constraint(AssocTyConstraint {
let arg = AngleBracketedArg::Constraint(AssocConstraint {
id: rustc_ast::node_id::DUMMY_NODE_ID,
ident: *ident,
gen_args,
kind: AssocTyConstraintKind::Equality {
ty: predicate.rhs_ty.clone(),
kind: AssocConstraintKind::Equality {
term: predicate.rhs_ty.clone().into(),
},
span: ident.span,
});

View File

@ -1,6 +1,6 @@
use rustc_ast as ast;
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
use rustc_ast::{AssocTyConstraint, AssocTyConstraintKind, NodeId};
use rustc_ast::{AssocConstraint, AssocConstraintKind, NodeId};
use rustc_ast::{PatKind, RangeEnd, VariantData};
use rustc_errors::struct_span_err;
use rustc_feature::{AttributeGate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
@ -622,8 +622,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
visit::walk_fn(self, fn_kind, span)
}
fn visit_assoc_ty_constraint(&mut self, constraint: &'a AssocTyConstraint) {
if let AssocTyConstraintKind::Bound { .. } = constraint.kind {
fn visit_assoc_constraint(&mut self, constraint: &'a AssocConstraint) {
if let AssocConstraintKind::Bound { .. } = constraint.kind {
gate_feature_post!(
&self,
associated_type_bounds,
@ -631,7 +631,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
"associated type bounds are unstable"
)
}
visit::walk_assoc_ty_constraint(self, constraint)
visit::walk_assoc_constraint(self, constraint)
}
fn visit_assoc_item(&mut self, i: &'a ast::AssocItem, ctxt: AssocCtxt) {
@ -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

@ -126,9 +126,9 @@ impl<'ast> Visitor<'ast> for NodeCounter {
self.count += 1;
walk_generic_args(self, path_span, generic_args)
}
fn visit_assoc_ty_constraint(&mut self, constraint: &AssocTyConstraint) {
fn visit_assoc_constraint(&mut self, constraint: &AssocConstraint) {
self.count += 1;
walk_assoc_ty_constraint(self, constraint)
walk_assoc_constraint(self, constraint)
}
fn visit_attribute(&mut self, _attr: &Attribute) {
self.count += 1;

View File

@ -1,7 +1,6 @@
use crate::pp::Breaks::{Consistent, Inconsistent};
use crate::pp::{self, Breaks};
use rustc_ast::attr;
use rustc_ast::ptr::P;
use rustc_ast::token::{self, BinOpToken, CommentKind, DelimToken, Nonterminal, Token, TokenKind};
use rustc_ast::tokenstream::{TokenStream, TokenTree};
@ -9,6 +8,7 @@ use rustc_ast::util::classify;
use rustc_ast::util::comments::{gather_comments, Comment, CommentStyle};
use rustc_ast::util::parser::{self, AssocOp, Fixity};
use rustc_ast::{self as ast, BlockCheckMode, PatKind, RangeEnd, RangeSyntax};
use rustc_ast::{attr, Term};
use rustc_ast::{GenericArg, MacArgs, ModKind};
use rustc_ast::{GenericBound, SelfKind, TraitBoundModifier};
use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass};
@ -952,18 +952,19 @@ impl<'a> State<'a> {
}
}
pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocTyConstraint) {
pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocConstraint) {
self.print_ident(constraint.ident);
constraint.gen_args.as_ref().map(|args| self.print_generic_args(args, false));
self.space();
match &constraint.kind {
ast::AssocTyConstraintKind::Equality { ty } => {
ast::AssocConstraintKind::Equality { term } => {
self.word_space("=");
self.print_type(ty);
}
ast::AssocTyConstraintKind::Bound { bounds } => {
self.print_type_bounds(":", &*bounds);
match term {
Term::Ty(ty) => self.print_type(ty),
Term::Const(c) => self.print_expr_anon_const(c),
}
}
ast::AssocConstraintKind::Bound { bounds } => self.print_type_bounds(":", &*bounds),
}
}

View File

@ -779,7 +779,10 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
[
hir::TypeBinding {
ident: Ident { name: sym::Output, .. },
kind: hir::TypeBindingKind::Equality { ty },
kind:
hir::TypeBindingKind::Equality {
term: hir::Term::Ty(ty),
},
..
},
],

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

@ -377,7 +377,7 @@ impl GenericArgs<'_> {
GenericArg::Type(ty) => matches!(ty.kind, TyKind::Err),
_ => false,
}) || self.bindings.iter().any(|arg| match arg.kind {
TypeBindingKind::Equality { ty } => matches!(ty.kind, TyKind::Err),
TypeBindingKind::Equality { term: Term::Ty(ty) } => matches!(ty.kind, TyKind::Err),
_ => false,
})
}
@ -2129,19 +2129,37 @@ pub struct TypeBinding<'hir> {
pub span: Span,
}
#[derive(Debug, HashStable_Generic)]
pub enum Term<'hir> {
Ty(&'hir Ty<'hir>),
Const(AnonConst),
}
impl<'hir> From<&'hir Ty<'hir>> for Term<'hir> {
fn from(ty: &'hir Ty<'hir>) -> Self {
Term::Ty(ty)
}
}
impl<'hir> From<AnonConst> for Term<'hir> {
fn from(c: AnonConst) -> Self {
Term::Const(c)
}
}
// Represents the two kinds of type bindings.
#[derive(Debug, HashStable_Generic)]
pub enum TypeBindingKind<'hir> {
/// E.g., `Foo<Bar: Send>`.
Constraint { bounds: &'hir [GenericBound<'hir>] },
/// E.g., `Foo<Bar = ()>`.
Equality { ty: &'hir Ty<'hir> },
/// E.g., `Foo<Bar = ()>`, `Foo<Bar = ()>`
Equality { term: Term<'hir> },
}
impl TypeBinding<'_> {
pub fn ty(&self) -> &Ty<'_> {
match self.kind {
TypeBindingKind::Equality { ref ty } => ty,
TypeBindingKind::Equality { term: Term::Ty(ref ty) } => ty,
_ => panic!("expected equality type binding for parenthesized generic args"),
}
}

View File

@ -801,12 +801,11 @@ pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(
visitor.visit_ident(type_binding.ident);
visitor.visit_generic_args(type_binding.span, type_binding.gen_args);
match type_binding.kind {
TypeBindingKind::Equality { ref ty } => {
visitor.visit_ty(ty);
}
TypeBindingKind::Constraint { bounds } => {
walk_list!(visitor, visit_param_bound, bounds);
}
TypeBindingKind::Equality { ref term } => match term {
Term::Ty(ref ty) => visitor.visit_ty(ty),
Term::Const(ref c) => visitor.visit_anon_const(c),
},
TypeBindingKind::Constraint { bounds } => walk_list!(visitor, visit_param_bound, bounds),
}
}

View File

@ -6,7 +6,7 @@ use rustc_ast_pretty::pp::Breaks::{Consistent, Inconsistent};
use rustc_ast_pretty::pp::{self, Breaks};
use rustc_ast_pretty::pprust::{Comments, PrintState};
use rustc_hir as hir;
use rustc_hir::{GenericArg, GenericParam, GenericParamKind, Node};
use rustc_hir::{GenericArg, GenericParam, GenericParamKind, Node, Term};
use rustc_hir::{GenericBound, PatKind, RangeEnd, TraitBoundModifier};
use rustc_span::source_map::{SourceMap, Spanned};
use rustc_span::symbol::{kw, Ident, IdentPrinter, Symbol};
@ -1752,9 +1752,12 @@ impl<'a> State<'a> {
self.print_generic_args(binding.gen_args, false, false);
self.space();
match generic_args.bindings[0].kind {
hir::TypeBindingKind::Equality { ref ty } => {
hir::TypeBindingKind::Equality { ref term } => {
self.word_space("=");
self.print_type(ty);
match term {
Term::Ty(ref ty) => self.print_type(ty),
Term::Const(ref c) => self.print_anon_const(c),
}
}
hir::TypeBindingKind::Constraint { bounds } => {
self.print_bounds(":", bounds);

View File

@ -1780,7 +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.
return Some(projection_predicate.ty);
return projection_predicate.term.ty();
}
}
}

View File

@ -122,8 +122,9 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
{
for type_binding in generic_args.bindings.iter() {
if type_binding.ident.name == rustc_span::sym::Output {
if let hir::TypeBindingKind::Equality { ty } =
type_binding.kind
if let hir::TypeBindingKind::Equality {
term: hir::Term::Ty(ty),
} = type_binding.kind
{
return Some(ty);
}

View File

@ -584,8 +584,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
debug!(?predicate);
if let ty::PredicateKind::Projection(projection) = predicate.kind().skip_binder() {
if projection.ty.references_error() {
// No point on adding these obligations since there's a type error involved.
if projection.term.references_error() {
return tcx.ty_error();
}
}

View File

@ -26,7 +26,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
kind: TypeVariableOriginKind::NormalizeProjectionType,
span: self.tcx.def_span(def_id),
});
let projection = ty::Binder::dummy(ty::ProjectionPredicate { projection_ty, ty: ty_var });
let projection =
ty::Binder::dummy(ty::ProjectionPredicate { projection_ty, term: ty_var.into() });
let obligation = Obligation::with_depth(
cause,
recursion_depth,

View File

@ -1,7 +1,7 @@
use libloading::Library;
use rustc_ast::mut_visit::{visit_clobber, MutVisitor, *};
use rustc_ast::ptr::P;
use rustc_ast::{self as ast, AttrVec, BlockCheckMode};
use rustc_ast::{self as ast, AttrVec, BlockCheckMode, Term};
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
#[cfg(parallel_compiler)]
@ -738,9 +738,14 @@ impl<'a, 'b> ReplaceBodyWithLoop<'a, 'b> {
| ast::GenericArg::Const(_) => false,
},
ast::AngleBracketedArg::Constraint(c) => match c.kind {
ast::AssocTyConstraintKind::Bound { .. } => true,
ast::AssocTyConstraintKind::Equality { ref ty } => {
involves_impl_trait(ty)
ast::AssocConstraintKind::Bound { .. } => true,
ast::AssocConstraintKind::Equality { ref term } => {
match term {
Term::Ty(ty) => involves_impl_trait(ty),
// FIXME(...): This should check if the constant
// involves a trait impl, but for now ignore.
Term::Const(_) => false,
}
}
},
})

View File

@ -152,6 +152,19 @@ impl<'tcx> AssocItems<'tcx> {
.find(|item| tcx.hygienic_eq(ident, item.ident, parent_def_id))
}
/// Returns the associated item with the given name and any of `AssocKind`, if one exists.
pub fn find_by_name_and_kinds(
&self,
tcx: TyCtxt<'_>,
ident: Ident,
kinds: &[AssocKind],
parent_def_id: DefId,
) -> Option<&ty::AssocItem> {
self.filter_by_name_unhygienic(ident.name)
.filter(|item| kinds.contains(&item.kind))
.find(|item| tcx.hygienic_eq(ident, item.ident, parent_def_id))
}
/// Returns the associated item with the given name in the given `Namespace`, if one exists.
pub fn find_by_name_and_namespace(
&self,

View File

@ -86,10 +86,14 @@ impl<'tcx> Const<'tcx> {
if let Some(lit_input) = lit_input {
// If an error occurred, ignore that it's a literal and leave reporting the error up to
// mir.
if let Ok(c) = tcx.at(expr.span).lit_to_const(lit_input) {
return Some(c);
} else {
tcx.sess.delay_span_bug(expr.span, "Const::from_anon_const: couldn't lit_to_const");
match tcx.at(expr.span).lit_to_const(lit_input) {
Ok(c) => return Some(c),
Err(e) => {
tcx.sess.delay_span_bug(
expr.span,
&format!("Const::from_anon_const: couldn't lit_to_const {:?}", e),
);
}
}
}

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

@ -1,5 +1,5 @@
use crate::ty::subst::{GenericArg, GenericArgKind};
use crate::ty::{self, InferConst, Ty, TypeFlags};
use crate::ty::{self, InferConst, Term, Ty, TypeFlags};
use std::slice;
#[derive(Debug)]
@ -241,9 +241,12 @@ impl FlagComputation {
self.add_ty(a);
self.add_ty(b);
}
ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => {
self.add_projection_ty(projection_ty);
self.add_ty(ty);
match term {
Term::Ty(ty) => self.add_ty(ty),
Term::Const(c) => self.add_const(c),
}
}
ty::PredicateKind::WellFormed(arg) => {
self.add_substs(slice::from_ref(&arg));
@ -317,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

@ -484,7 +484,7 @@ crate struct PredicateInner<'tcx> {
}
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
static_assert_size!(PredicateInner<'_>, 48);
static_assert_size!(PredicateInner<'_>, 56);
#[derive(Clone, Copy, Lift)]
pub struct Predicate<'tcx> {
@ -795,6 +795,31 @@ pub struct CoercePredicate<'tcx> {
}
pub type PolyCoercePredicate<'tcx> = ty::Binder<'tcx, CoercePredicate<'tcx>>;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)]
#[derive(HashStable, TypeFoldable)]
pub enum Term<'tcx> {
Ty(Ty<'tcx>),
Const(&'tcx Const<'tcx>),
}
impl<'tcx> From<Ty<'tcx>> for Term<'tcx> {
fn from(ty: Ty<'tcx>) -> Self {
Term::Ty(ty)
}
}
impl<'tcx> From<&'tcx Const<'tcx>> for Term<'tcx> {
fn from(c: &'tcx Const<'tcx>) -> Self {
Term::Const(c)
}
}
impl<'tcx> Term<'tcx> {
pub fn ty(&self) -> Option<Ty<'tcx>> {
if let Term::Ty(ty) = self { Some(ty) } else { None }
}
}
/// This kind of predicate has no *direct* correspondent in the
/// syntax, but it roughly corresponds to the syntactic forms:
///
@ -811,7 +836,7 @@ pub type PolyCoercePredicate<'tcx> = ty::Binder<'tcx, CoercePredicate<'tcx>>;
#[derive(HashStable, TypeFoldable)]
pub struct ProjectionPredicate<'tcx> {
pub projection_ty: ProjectionTy<'tcx>,
pub ty: Ty<'tcx>,
pub term: Term<'tcx>,
}
pub type PolyProjectionPredicate<'tcx> = Binder<'tcx, ProjectionPredicate<'tcx>>;
@ -836,8 +861,8 @@ impl<'tcx> PolyProjectionPredicate<'tcx> {
self.map_bound(|predicate| predicate.projection_ty.trait_ref(tcx))
}
pub fn ty(&self) -> Binder<'tcx, Ty<'tcx>> {
self.map_bound(|predicate| predicate.ty)
pub fn term(&self) -> Binder<'tcx, Term<'tcx>> {
self.map_bound(|predicate| predicate.term)
}
/// The `DefId` of the `TraitItem` for the associated type.

View File

@ -1,6 +1,6 @@
use crate::mir::interpret::{AllocRange, ConstValue, GlobalAlloc, Pointer, Provenance, Scalar};
use crate::ty::subst::{GenericArg, GenericArgKind, Subst};
use crate::ty::{self, ConstInt, DefIdTree, ParamConst, ScalarInt, Ty, TyCtxt, TypeFoldable};
use crate::ty::{self, ConstInt, DefIdTree, ParamConst, ScalarInt, Term, Ty, TyCtxt, TypeFoldable};
use rustc_apfloat::ieee::{Double, Single};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sso::SsoHashSet;
@ -799,7 +799,7 @@ pub trait PrettyPrinter<'tcx>:
let trait_ref = proj_ref.required_poly_trait_ref(self.tcx());
// Projection type entry -- the def-id for naming, and the ty.
let proj_ty = (proj_ref.projection_def_id(), proj_ref.ty());
let proj_ty = (proj_ref.projection_def_id(), proj_ref.term());
self.insert_trait_and_projection(
trait_ref,
@ -850,8 +850,10 @@ pub trait PrettyPrinter<'tcx>:
}
p!(")");
if !return_ty.skip_binder().is_unit() {
p!("-> ", print(return_ty));
if let Term::Ty(ty) = return_ty.skip_binder() {
if !ty.is_unit() {
p!("-> ", print(return_ty));
}
}
p!(write("{}", if paren_needed { ")" } else { "" }));
@ -902,23 +904,28 @@ pub trait PrettyPrinter<'tcx>:
first = false;
}
for (assoc_item_def_id, ty) in assoc_items {
for (assoc_item_def_id, term) in assoc_items {
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.skip_binder().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;
}
@ -943,8 +950,11 @@ pub trait PrettyPrinter<'tcx>:
fn insert_trait_and_projection(
&mut self,
trait_ref: ty::PolyTraitRef<'tcx>,
proj_ty: Option<(DefId, ty::Binder<'tcx, Ty<'tcx>>)>,
traits: &mut BTreeMap<ty::PolyTraitRef<'tcx>, BTreeMap<DefId, ty::Binder<'tcx, Ty<'tcx>>>>,
proj_ty: Option<(DefId, ty::Binder<'tcx, Term<'tcx>>)>,
traits: &mut BTreeMap<
ty::PolyTraitRef<'tcx>,
BTreeMap<DefId, ty::Binder<'tcx, Term<'tcx>>>,
>,
fn_traits: &mut BTreeMap<ty::PolyTraitRef<'tcx>, OpaqueFnEntry<'tcx>>,
) {
let trait_def_id = trait_ref.def_id();
@ -1019,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;
}
}
@ -2442,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> {
@ -2499,7 +2513,14 @@ define_print_and_forward_display! {
}
ty::ProjectionPredicate<'tcx> {
p!(print(self.projection_ty), " == ", print(self.ty))
p!(print(self.projection_ty), " == ", print(self.term))
}
ty::Term<'tcx> {
match self {
ty::Term::Ty(ty) => p!(print(ty)),
ty::Term::Const(c) => p!(print(c)),
}
}
ty::ProjectionTy<'tcx> {
@ -2709,5 +2730,5 @@ pub struct OpaqueFnEntry<'tcx> {
has_fn_once: bool,
fn_mut_trait_ref: Option<ty::PolyTraitRef<'tcx>>,
fn_trait_ref: Option<ty::PolyTraitRef<'tcx>>,
return_ty: Option<ty::Binder<'tcx, Ty<'tcx>>>,
return_ty: Option<ty::Binder<'tcx, Term<'tcx>>>,
}

View File

@ -7,7 +7,7 @@
use crate::mir::interpret::{get_slice_bytes, ConstValue, GlobalAlloc, Scalar};
use crate::ty::error::{ExpectedFound, TypeError};
use crate::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
use crate::ty::{self, Term, Ty, TyCtxt, TypeFoldable};
use rustc_hir as ast;
use rustc_hir::def_id::DefId;
use rustc_span::DUMMY_SP;
@ -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 })
}
}
}
@ -833,6 +833,20 @@ impl<'tcx> Relate<'tcx> for ty::TraitPredicate<'tcx> {
}
}
impl<'tcx> Relate<'tcx> for ty::Term<'tcx> {
fn relate<R: TypeRelation<'tcx>>(
relation: &mut R,
a: Self,
b: Self,
) -> RelateResult<'tcx, Self> {
Ok(match (a, b) {
(Term::Ty(a), Term::Ty(b)) => relation.relate(a, b)?.into(),
(Term::Const(a), Term::Const(b)) => relation.relate(a, b)?.into(),
_ => return Err(TypeError::Mismatch),
})
}
}
impl<'tcx> Relate<'tcx> for ty::ProjectionPredicate<'tcx> {
fn relate<R: TypeRelation<'tcx>>(
relation: &mut R,
@ -841,7 +855,7 @@ impl<'tcx> Relate<'tcx> for ty::ProjectionPredicate<'tcx> {
) -> RelateResult<'tcx, ty::ProjectionPredicate<'tcx>> {
Ok(ty::ProjectionPredicate {
projection_ty: relation.relate(a.projection_ty, b.projection_ty)?,
ty: relation.relate(a.ty, b.ty)?,
term: relation.relate(a.term, b.term)?.into(),
})
}
}

View File

@ -6,7 +6,7 @@ use crate::mir::interpret;
use crate::mir::ProjectionKind;
use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeVisitor};
use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer};
use crate::ty::{self, InferConst, Lift, Ty, TyCtxt};
use crate::ty::{self, InferConst, Lift, Term, Ty, TyCtxt};
use rustc_data_structures::functor::IdFunctor;
use rustc_hir::def::Namespace;
use rustc_hir::def_id::CRATE_DEF_INDEX;
@ -158,7 +158,7 @@ impl<'tcx> fmt::Debug for ty::TraitPredicate<'tcx> {
impl<'tcx> fmt::Debug for ty::ProjectionPredicate<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "ProjectionPredicate({:?}, {:?})", self.projection_ty, self.ty)
write!(f, "ProjectionPredicate({:?}, {:?})", self.projection_ty, self.term)
}
}
@ -356,6 +356,16 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialPredicate<'a> {
}
}
impl<'a, 'tcx> Lift<'tcx> for Term<'a> {
type Lifted = ty::Term<'tcx>;
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
Some(match self {
Term::Ty(ty) => Term::Ty(tcx.lift(ty)?),
Term::Const(c) => Term::Const(tcx.lift(c)?),
})
}
}
impl<'a, 'tcx> Lift<'tcx> for ty::TraitPredicate<'a> {
type Lifted = ty::TraitPredicate<'tcx>;
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ty::TraitPredicate<'tcx>> {
@ -403,8 +413,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ProjectionTy<'a> {
impl<'a, 'tcx> Lift<'tcx> for ty::ProjectionPredicate<'a> {
type Lifted = ty::ProjectionPredicate<'tcx>;
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ty::ProjectionPredicate<'tcx>> {
tcx.lift((self.projection_ty, self.ty))
.map(|(projection_ty, ty)| ty::ProjectionPredicate { projection_ty, ty })
tcx.lift((self.projection_ty, self.term))
.map(|(projection_ty, term)| ty::ProjectionPredicate { projection_ty, term })
}
}
@ -413,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

@ -8,7 +8,7 @@ use crate::infer::canonical::Canonical;
use crate::ty::fold::ValidateBoundVars;
use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
use crate::ty::InferTy::{self, *};
use crate::ty::{self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable};
use crate::ty::{self, AdtDef, DefIdTree, Discr, Term, Ty, TyCtxt, TypeFlags, TypeFoldable};
use crate::ty::{DelaySpanBugEmitted, List, ParamEnv, TyS};
use polonius_engine::Atom;
use rustc_data_structures::captures::Captures;
@ -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),
},
ty: self.ty,
term: self.term,
}
}
@ -1584,7 +1584,7 @@ impl<'tcx> ExistentialProjection<'tcx> {
Self {
item_def_id: projection_predicate.projection_ty.item_def_id,
substs: tcx.intern_substs(&projection_predicate.projection_ty.substs[1..]),
ty: projection_predicate.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

@ -4,8 +4,8 @@ use crate::maybe_whole;
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Token};
use rustc_ast::{
self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocTyConstraint,
AssocTyConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs,
self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocConstraint,
AssocConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs,
Path, PathSegment, QSelf,
};
use rustc_errors::{pluralize, Applicability, PResult};
@ -469,12 +469,9 @@ impl<'a> Parser<'a> {
// Parse associated type constraint bound.
let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?;
AssocTyConstraintKind::Bound { bounds }
AssocConstraintKind::Bound { bounds }
} else if self.eat(&token::Eq) {
// Parse associated type equality constraint
let ty = self.parse_assoc_equality_term(ident, self.prev_token.span)?;
AssocTyConstraintKind::Equality { ty }
self.parse_assoc_equality_term(ident, self.prev_token.span)?
} else {
unreachable!();
};
@ -482,11 +479,11 @@ impl<'a> Parser<'a> {
let span = lo.to(self.prev_token.span);
// Gate associated type bounds, e.g., `Iterator<Item: Ord>`.
if let AssocTyConstraintKind::Bound { .. } = kind {
if let AssocConstraintKind::Bound { .. } = kind {
self.sess.gated_spans.gate(sym::associated_type_bounds, span);
}
let constraint =
AssocTyConstraint { id: ast::DUMMY_NODE_ID, ident, gen_args, kind, span };
AssocConstraint { id: ast::DUMMY_NODE_ID, ident, gen_args, kind, span };
Ok(Some(AngleBracketedArg::Constraint(constraint)))
} else {
Ok(Some(AngleBracketedArg::Arg(arg)))
@ -499,22 +496,25 @@ impl<'a> Parser<'a> {
/// Parse the term to the right of an associated item equality constraint.
/// That is, parse `<term>` in `Item = <term>`.
/// Right now, this only admits types in `<term>`.
fn parse_assoc_equality_term(&mut self, ident: Ident, eq: Span) -> PResult<'a, P<ast::Ty>> {
fn parse_assoc_equality_term(
&mut self,
ident: Ident,
eq: Span,
) -> PResult<'a, AssocConstraintKind> {
let arg = self.parse_generic_arg(None)?;
let span = ident.span.to(self.prev_token.span);
match arg {
Some(GenericArg::Type(ty)) => return Ok(ty),
Some(GenericArg::Const(expr)) => {
self.struct_span_err(span, "cannot constrain an associated constant to a value")
.span_label(ident.span, "this associated constant...")
.span_label(expr.value.span, "...cannot be constrained to this value")
.emit();
let term = match arg {
Some(GenericArg::Type(ty)) => ty.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")
.help("if you meant to specify a trait object, write `dyn Trait + 'lifetime`")
.emit();
self.mk_ty(span, ast::TyKind::Err).into()
}
None => {
let after_eq = eq.shrink_to_hi();
@ -542,8 +542,8 @@ impl<'a> Parser<'a> {
};
return Err(err);
}
}
Ok(self.mk_ty(span, ast::TyKind::Err))
};
Ok(AssocConstraintKind::Equality { term })
}
/// We do not permit arbitrary expressions as const arguments. They must be one of:

View File

@ -332,9 +332,9 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
ast_visit::walk_path_segment(self, path_span, path_segment)
}
fn visit_assoc_ty_constraint(&mut self, constraint: &'v ast::AssocTyConstraint) {
self.record("AssocTyConstraint", Id::None, constraint);
ast_visit::walk_assoc_ty_constraint(self, constraint)
fn visit_assoc_constraint(&mut self, constraint: &'v ast::AssocConstraint) {
self.record("AssocConstraint", Id::None, constraint);
ast_visit::walk_assoc_constraint(self, constraint)
}
fn visit_attribute(&mut self, attr: &'v ast::Attribute) {

View File

@ -127,8 +127,8 @@ where
constness: _,
polarity: _,
}) => self.visit_trait(trait_ref),
ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
ty.visit_with(self)?;
ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => {
term.visit_with(self)?;
self.visit_projection_ty(projection_ty)
}
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, _region)) => {
@ -1185,10 +1185,10 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
}
for (poly_predicate, _) in bounds.projection_bounds {
if self.visit(poly_predicate.skip_binder().ty).is_break()
|| self
.visit_projection_ty(poly_predicate.skip_binder().projection_ty)
.is_break()
let pred = poly_predicate.skip_binder();
let poly_pred_term = self.visit(pred.term);
if poly_pred_term.is_break()
|| self.visit_projection_ty(pred.projection_ty).is_break()
{
return;
}

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

@ -6,7 +6,7 @@ use super::*;
use crate::infer::region_constraints::{Constraint, RegionConstraintData};
use crate::infer::InferCtxt;
use rustc_middle::ty::fold::TypeFolder;
use rustc_middle::ty::{Region, RegionVid};
use rustc_middle::ty::{Region, RegionVid, Term};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@ -606,7 +606,11 @@ impl<'tcx> AutoTraitFinder<'tcx> {
}
fn is_self_referential_projection(&self, p: ty::PolyProjectionPredicate<'_>) -> bool {
matches!(*p.ty().skip_binder().kind(), ty::Projection(proj) if proj == p.skip_binder().projection_ty)
if let Term::Ty(ty) = p.term().skip_binder() {
matches!(ty.kind(), ty::Projection(proj) if proj == &p.skip_binder().projection_ty)
} else {
false
}
}
fn evaluate_nested_obligations(
@ -663,7 +667,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
// Additionally, we check if we've seen this predicate before,
// to avoid rendering duplicate bounds to the user.
if self.is_param_no_infer(p.skip_binder().projection_ty.substs)
&& !p.ty().skip_binder().has_infer_types()
&& !p.term().skip_binder().has_infer_types()
&& is_new_pred
{
debug!(
@ -752,7 +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.ty().skip_binder().has_infer_types() {
if p.term().skip_binder().has_infer_types() {
if !self.evaluate_nested_obligations(
ty,
v.into_iter(),
@ -774,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.ty().skip_binder().has_infer_types() {
if p.term().skip_binder().has_infer_types() {
panic!("Unexpected result when selecting {:?} {:?}", ty, obligation)
}
}

View File

@ -1304,7 +1304,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
debug!(
"report_projection_error normalized_ty={:?} data.ty={:?}",
normalized_ty, data.ty
normalized_ty, data.term,
);
let is_normalized_ty_expected = !matches!(
@ -1314,16 +1314,17 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
| ObligationCauseCode::ObjectCastObligation(_)
| ObligationCauseCode::OpaqueType
);
// 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,
normalized_ty,
data.ty,
data_ty,
) {
values = Some(infer::ValuePairs::Types(ExpectedFound::new(
is_normalized_ty_expected,
normalized_ty,
data.ty,
data_ty,
)));
err_buf = error;
@ -1803,11 +1804,11 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
}
ty::PredicateKind::Projection(data) => {
let self_ty = data.projection_ty.self_ty();
let ty = data.ty;
let term = data.term;
if predicate.references_error() || self.is_tainted_by_errors() {
return;
}
if self_ty.needs_infer() && ty.needs_infer() {
if self_ty.needs_infer() && term.needs_infer() {
// We do this for the `foo.collect()?` case to produce a suggestion.
let mut err = self.emit_inference_failure_err(
body_id,

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,10 +212,9 @@ fn project_and_unify_type<'cx, 'tcx>(
debug!(?normalized_ty, ?obligations, "project_and_unify_type result");
let infcx = selcx.infcx();
match infcx
.at(&obligation.cause, obligation.param_env)
.eq(normalized_ty, obligation.predicate.ty)
{
// 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: () }) => {
obligations.extend(inferred_obligations);
Ok(Ok(Some(obligations)))
@ -1615,7 +1614,7 @@ fn confirm_generator_candidate<'cx, 'tcx>(
substs: trait_ref.substs,
item_def_id: obligation.predicate.item_def_id,
},
ty,
term: ty.into(),
}
});
@ -1641,7 +1640,7 @@ fn confirm_discriminant_kind_candidate<'cx, 'tcx>(
let predicate = ty::ProjectionPredicate {
projection_ty: ty::ProjectionTy { substs, item_def_id: discriminant_def_id },
ty: self_ty.discriminant_ty(tcx),
term: self_ty.discriminant_ty(tcx).into(),
};
// We get here from `poly_project_and_unify_type` which replaces bound vars
@ -1674,7 +1673,7 @@ fn confirm_pointee_candidate<'cx, 'tcx>(
let predicate = ty::ProjectionPredicate {
projection_ty: ty::ProjectionTy { substs, item_def_id: metadata_def_id },
ty: metadata_ty,
term: metadata_ty.into(),
};
confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false)
@ -1747,7 +1746,7 @@ fn confirm_callable_candidate<'cx, 'tcx>(
substs: trait_ref.substs,
item_def_id: fn_once_output_def_id,
},
ty: ret_type,
term: ret_type.into(),
});
confirm_param_env_candidate(selcx, obligation, predicate, true)
@ -1803,7 +1802,9 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
Ok(InferOk { value: _, obligations }) => {
nested_obligations.extend(obligations);
assoc_ty_own_obligations(selcx, obligation, &mut nested_obligations);
Progress { ty: cache_entry.ty, obligations: nested_obligations }
// FIXME(associated_const_equality): Handle consts here as well? Maybe this progress type should just take
// a term instead.
Progress { ty: cache_entry.term.ty().unwrap(), obligations: nested_obligations }
}
Err(e) => {
let msg = format!(

View File

@ -62,7 +62,7 @@ pub(crate) fn update<'tcx, T>(
if let ty::PredicateKind::Projection(predicate) = obligation.predicate.kind().skip_binder() {
// If the projection predicate (Foo::Bar == X) has X as a non-TyVid,
// we need to make it into one.
if let Some(vid) = predicate.ty.ty_vid() {
if let Some(vid) = predicate.term.ty().and_then(|ty| ty.ty_vid()) {
debug!("relationship: {:?}.output = true", vid);
engine.relationships().entry(vid).or_default().output = true;
}

View File

@ -116,7 +116,10 @@ pub fn predicate_obligations<'a, 'tcx>(
}
ty::PredicateKind::Projection(t) => {
wf.compute_projection(t.projection_ty);
wf.compute(t.ty.into());
wf.compute(match t.term {
ty::Term::Ty(ty) => ty.into(),
ty::Term::Const(c) => c.into(),
})
}
ty::PredicateKind::WellFormed(arg) => {
wf.compute(arg);
@ -219,7 +222,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>(
// projection coming from another associated type. See
// `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs` and
// `traits-assoc-type-in-supertrait-bad.rs`.
if let ty::Projection(projection_ty) = proj.ty.kind() {
if let Some(ty::Projection(projection_ty)) = proj.term.ty().map(|ty| ty.kind()) {
if let Some(&impl_item_id) =
tcx.impl_item_implementor_ids(impl_def_id).get(&projection_ty.item_def_id)
{

View File

@ -226,13 +226,26 @@ 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.ty.lower_into(interner),
ty: self.term.ty().unwrap().lower_into(interner),
alias: self.projection_ty.lower_into(interner),
}
}
}
/*
// FIXME(...): Where do I add this to Chalk? I can't find it in the rustc repo anywhere.
impl<'tcx> LowerInto<'tcx, chalk_ir::Term<RustInterner<'tcx>>> for rustc_middle::ty::Term<'tcx> {
fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::Term<RustInterner<'tcx>> {
match self {
ty::Term::Ty(ty) => ty.lower_into(interner).into(),
ty::Term::Const(c) => c.lower_into(interner).into(),
}
}
}
*/
impl<'tcx> LowerInto<'tcx, chalk_ir::Ty<RustInterner<'tcx>>> for Ty<'tcx> {
fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::Ty<RustInterner<'tcx>> {
let int = |i| chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Int(i));
@ -651,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(
@ -787,7 +801,7 @@ impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::AliasEqBound<RustInterner<'tcx>
trait_bound: trait_ref.lower_into(interner),
associated_ty_id: chalk_ir::AssocTypeId(self.projection_ty.item_def_id),
parameters: own_substs.iter().map(|arg| arg.lower_into(interner)).collect(),
value: self.ty.lower_into(interner),
value: self.term.ty().unwrap().lower_into(interner),
}
}
}

View File

@ -151,8 +151,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.bindings
.iter()
.find_map(|b| match (b.ident.name == sym::Output, &b.kind) {
(true, hir::TypeBindingKind::Equality { ty }) => {
sess.source_map().span_to_snippet(ty.span).ok()
(true, hir::TypeBindingKind::Equality { term }) => {
let span = match term {
hir::Term::Ty(ty) => ty.span,
hir::Term::Const(c) => self.tcx().hir().span(c.hir_id),
};
sess.source_map().span_to_snippet(span).ok()
}
_ => None,
})

View File

@ -123,7 +123,7 @@ struct ConvertedBinding<'a, 'tcx> {
#[derive(Debug)]
enum ConvertedBindingKind<'a, 'tcx> {
Equality(Ty<'tcx>),
Equality(ty::Term<'tcx>),
Constraint(&'a [hir::GenericBound<'a>]),
}
@ -601,10 +601,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.iter()
.map(|binding| {
let kind = match binding.kind {
hir::TypeBindingKind::Equality { ty } => {
ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty))
}
hir::TypeBindingKind::Constraint { bounds } => {
hir::TypeBindingKind::Equality { ref term } => match term {
hir::Term::Ty(ref ty) => {
ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty).into())
}
hir::Term::Const(ref c) => {
let local_did = self.tcx().hir().local_def_id(c.hir_id);
let c = Const::from_anon_const(self.tcx(), local_did);
ConvertedBindingKind::Equality(c.into())
}
},
hir::TypeBindingKind::Constraint { ref bounds } => {
ConvertedBindingKind::Constraint(bounds)
}
};
@ -867,6 +874,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.find_by_name_and_kind(self.tcx(), assoc_name, ty::AssocKind::Type, trait_def_id)
.is_some()
}
fn trait_defines_associated_named(&self, trait_def_id: DefId, assoc_name: Ident) -> bool {
self.tcx()
.associated_items(trait_def_id)
.find_by_name_and_kinds(
self.tcx(),
assoc_name,
&[ty::AssocKind::Type, ty::AssocKind::Const],
trait_def_id,
)
.is_some()
}
// Sets `implicitly_sized` to true on `Bounds` if necessary
pub(crate) fn add_implicitly_sized<'hir>(
@ -1118,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
@ -1215,18 +1242,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
match binding.kind {
ConvertedBindingKind::Equality(ty) => {
ConvertedBindingKind::Equality(term) => {
// "Desugar" a constraint like `T: Iterator<Item = u32>` this to
// the "projection predicate" for:
//
// `<T as Iterator>::Item = u32`
bounds.projection_bounds.push((
projection_ty.map_bound(|projection_ty| {
debug!(
"add_predicates_for_ast_type_binding: projection_ty {:?}, substs: {:?}",
projection_ty, projection_ty.substs
);
ty::ProjectionPredicate { projection_ty, ty }
projection_ty.map_bound(|projection_ty| ty::ProjectionPredicate {
projection_ty,
term: term,
}),
binding.span,
));
@ -1377,8 +1401,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let pred = bound_predicate.rebind(pred);
// A `Self` within the original bound will be substituted with a
// `trait_object_dummy_self`, so check for that.
let references_self =
pred.skip_binder().ty.walk().any(|arg| arg == dummy_self.into());
let references_self = match pred.skip_binder().term {
ty::Term::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()),
ty::Term::Const(c) => c.ty.walk().any(|arg| arg == dummy_self.into()),
};
// If the projection output contains `Self`, force the user to
// elaborate it explicitly to avoid a lot of complexity.
@ -1601,7 +1627,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
{
let mut matching_candidates = all_candidates()
.filter(|r| self.trait_defines_associated_type_named(r.def_id(), assoc_name));
.filter(|r| self.trait_defines_associated_named(r.def_id(), assoc_name));
let bound = match matching_candidates.next() {
Some(bound) => bound,

View File

@ -48,14 +48,19 @@ impl<'tcx> Bounds<'tcx> {
/// where-clauses). Because some of our bounds listings (e.g.,
/// regions) don't include the self-type, you must supply the
/// self-type here (the `param_ty` parameter).
pub fn predicates(
&self,
pub fn predicates<'out, 's>(
&'s self,
tcx: TyCtxt<'tcx>,
param_ty: Ty<'tcx>,
) -> Vec<(ty::Predicate<'tcx>, Span)> {
// the output must live shorter than the duration of the borrow of self and 'tcx.
) -> impl Iterator<Item = (ty::Predicate<'tcx>, Span)> + 'out
where
'tcx: 'out,
's: 'out,
{
// If it could be sized, and is, add the `Sized` predicate.
let sized_predicate = self.implicitly_sized.and_then(|span| {
tcx.lang_items().sized_trait().map(|sized| {
tcx.lang_items().sized_trait().map(move |sized| {
let trait_ref = ty::Binder::dummy(ty::TraitRef {
def_id: sized,
substs: tcx.mk_substs_trait(param_ty, &[]),
@ -64,25 +69,22 @@ impl<'tcx> Bounds<'tcx> {
})
});
sized_predicate
.into_iter()
.chain(self.region_bounds.iter().map(|&(region_bound, span)| {
(
region_bound
.map_bound(|region_bound| ty::OutlivesPredicate(param_ty, region_bound))
.to_predicate(tcx),
span,
)
}))
.chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| {
let region_preds = self.region_bounds.iter().map(move |&(region_bound, span)| {
let pred = region_bound
.map_bound(|region_bound| ty::OutlivesPredicate(param_ty, region_bound))
.to_predicate(tcx);
(pred, span)
});
let trait_bounds =
self.trait_bounds.iter().map(move |&(bound_trait_ref, span, constness)| {
let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx);
(predicate, span)
}))
.chain(
self.projection_bounds
.iter()
.map(|&(projection, span)| (projection.to_predicate(tcx), span)),
)
.collect()
});
let projection_bounds = self
.projection_bounds
.iter()
.map(move |&(projection, span)| (projection.to_predicate(tcx), span));
sized_predicate.into_iter().chain(region_preds).chain(trait_bounds).chain(projection_bounds)
}
}

View File

@ -279,7 +279,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return None;
};
let ret_param_ty = projection.skip_binder().ty;
// Since this is a return parameter type it is safe to unwrap.
let ret_param_ty = projection.skip_binder().term.ty().unwrap();
let ret_param_ty = self.resolve_vars_if_possible(ret_param_ty);
debug!("deduce_sig_from_projection: ret_param_ty={:?}", ret_param_ty);
@ -706,9 +707,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Extract the type from the projection. Note that there can
// be no bound variables in this type because the "self type"
// does not have any regions in it.
let output_ty = self.resolve_vars_if_possible(predicate.ty);
let output_ty = self.resolve_vars_if_possible(predicate.term);
debug!("deduce_future_output_from_projection: output_ty={:?}", output_ty);
Some(output_ty)
// This is a projection on a Fn trait so will always be a type.
Some(output_ty.ty().unwrap())
}
/// Converts the types that the user supplied, in case that doing

View File

@ -1353,7 +1353,7 @@ pub fn check_type_bounds<'tcx>(
item_def_id: trait_ty.def_id,
substs: rebased_substs,
},
ty: impl_ty_value,
term: impl_ty_value.into(),
},
bound_vars,
)

View File

@ -789,10 +789,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
item_def_id: projection_ty.item_def_id,
};
let ty = pred.skip_binder().ty;
let term = pred.skip_binder().term;
let obligation = format!("{} = {}", projection_ty, ty);
let quiet = format!("{} = {}", quiet_projection_ty, ty);
let obligation = format!("{} = {}", projection_ty, term);
let quiet = format!("{} = {}", quiet_projection_ty, term);
bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
Some((obligation, projection_ty.self_ty()))

View File

@ -716,7 +716,11 @@ fn bounds_from_generic_predicates<'tcx>(
// insert the associated types where they correspond, but for now let's be "lazy" and
// propose this instead of the following valid resugaring:
// `T: Trait, Trait::Assoc = K` → `T: Trait<Assoc = K>`
where_clauses.push(format!("{} = {}", tcx.def_path_str(p.projection_ty.item_def_id), p.ty));
where_clauses.push(format!(
"{} = {}",
tcx.def_path_str(p.projection_ty.item_def_id),
p.term,
));
}
let where_clauses = if where_clauses.is_empty() {
String::new()

View File

@ -659,7 +659,11 @@ impl<'tcx> ItemCtxt<'tcx> {
.params
.iter()
.filter_map(|param| match param.kind {
GenericParamKind::Type { .. } if param.hir_id == param_id => Some(&param.bounds),
GenericParamKind::Type { .. } | GenericParamKind::Const { .. }
if param.hir_id == param_id =>
{
Some(&param.bounds)
}
_ => None,
})
.flat_map(|bounds| bounds.iter())
@ -2527,7 +2531,7 @@ fn predicates_from_bound<'tcx>(
) -> Vec<(ty::Predicate<'tcx>, Span)> {
let mut bounds = Bounds::default();
astconv.add_bounds(param_ty, [bound].into_iter(), &mut bounds, bound_vars);
bounds.predicates(astconv.tcx(), param_ty)
bounds.predicates(astconv.tcx(), param_ty).collect()
}
fn compute_sig_of_foreign_fn_decl<'tcx>(

View File

@ -67,11 +67,7 @@ fn opaque_type_bounds<'tcx>(
let mut bounds = <dyn AstConv<'_>>::compute_bounds(&icx, item_ty, ast_bounds);
// Opaque types are implicitly sized unless a `?Sized` bound is found
<dyn AstConv<'_>>::add_implicitly_sized(&icx, &mut bounds, ast_bounds, None, span);
let bounds = bounds.predicates(tcx, item_ty);
debug!("opaque_type_bounds({}) = {:?}", tcx.def_path_str(opaque_def_id), bounds);
tcx.arena.alloc_slice(&bounds)
tcx.arena.alloc_from_iter(bounds.predicates(tcx, item_ty))
})
}

View File

@ -203,7 +203,7 @@ pub fn setup_constraining_predicates<'tcx>(
if !relies_only_on_inputs {
continue;
}
input_parameters.extend(parameters_for(&projection.ty, false));
input_parameters.extend(parameters_for(&projection.term, false));
} else {
continue;
}

View File

@ -199,7 +199,7 @@ fn unconstrained_parent_impl_substs<'tcx>(
for (predicate, _) in impl_generic_predicates.predicates.iter() {
if let ty::PredicateKind::Projection(proj) = predicate.kind().skip_binder() {
let projection_ty = proj.projection_ty;
let projected_ty = proj.ty;
let projected_ty = proj.term;
let unbound_trait_ref = projection_ty.trait_ref(tcx);
if Some(unbound_trait_ref) == impl_trait_ref {

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

@ -553,8 +553,10 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
if self.is_fn_trait(trait_) && left_name == sym::Output {
ty_to_fn
.entry(*ty.clone())
.and_modify(|e| *e = (e.0.clone(), Some(rhs.clone())))
.or_insert((None, Some(rhs)));
.and_modify(|e| {
*e = (e.0.clone(), Some(rhs.ty().unwrap().clone()))
})
.or_insert((None, Some(rhs.ty().unwrap().clone())));
continue;
}
@ -570,7 +572,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
GenericArgs::AngleBracketed { ref mut bindings, .. } => {
bindings.push(TypeBinding {
name: left_name,
kind: TypeBindingKind::Equality { ty: rhs },
kind: TypeBindingKind::Equality { term: rhs },
});
}
GenericArgs::Parenthesized { .. } => {

View File

@ -272,9 +272,10 @@ impl Clean<WherePredicate> for hir::WherePredicate<'_> {
bounds: wrp.bounds.iter().filter_map(|x| x.clean(cx)).collect(),
},
hir::WherePredicate::EqPredicate(ref wrp) => {
WherePredicate::EqPredicate { lhs: wrp.lhs_ty.clean(cx), rhs: wrp.rhs_ty.clean(cx) }
}
hir::WherePredicate::EqPredicate(ref wrp) => WherePredicate::EqPredicate {
lhs: wrp.lhs_ty.clean(cx),
rhs: wrp.rhs_ty.clean(cx).into(),
},
}
}
}
@ -352,10 +353,31 @@ impl<'tcx> Clean<Option<WherePredicate>> for ty::OutlivesPredicate<Ty<'tcx>, ty:
}
}
impl<'tcx> Clean<Term> for ty::Term<'tcx> {
fn clean(&self, cx: &mut DocContext<'_>) -> Term {
match self {
ty::Term::Ty(ty) => Term::Type(ty.clean(cx)),
ty::Term::Const(c) => Term::Constant(c.clean(cx)),
}
}
}
impl<'tcx> Clean<Term> for hir::Term<'tcx> {
fn clean(&self, cx: &mut DocContext<'_>) -> Term {
match self {
hir::Term::Ty(ty) => Term::Type(ty.clean(cx)),
hir::Term::Const(c) => {
let def_id = cx.tcx.hir().local_def_id(c.hir_id);
Term::Constant(ty::Const::from_anon_const(cx.tcx, def_id).clean(cx))
}
}
}
}
impl<'tcx> Clean<WherePredicate> for ty::ProjectionPredicate<'tcx> {
fn clean(&self, cx: &mut DocContext<'_>) -> WherePredicate {
let ty::ProjectionPredicate { projection_ty, ty } = self;
WherePredicate::EqPredicate { lhs: projection_ty.clean(cx), rhs: ty.clean(cx) }
let ty::ProjectionPredicate { projection_ty, term } = self;
WherePredicate::EqPredicate { lhs: projection_ty.clean(cx), rhs: term.clean(cx) }
}
}
@ -613,7 +635,7 @@ fn clean_ty_generics(
if let Some(param_idx) = param_idx {
if let Some(b) = impl_trait.get_mut(&param_idx.into()) {
let p = p.clean(cx)?;
let p: WherePredicate = p.clean(cx)?;
b.extend(
p.get_bounds()
@ -624,11 +646,16 @@ fn clean_ty_generics(
);
let proj = projection
.map(|p| (p.skip_binder().projection_ty.clean(cx), p.skip_binder().ty));
.map(|p| (p.skip_binder().projection_ty.clean(cx), p.skip_binder().term));
if let Some(((_, trait_did, name), rhs)) =
proj.as_ref().and_then(|(lhs, rhs)| Some((lhs.projection()?, rhs)))
{
impl_trait_proj.entry(param_idx).or_default().push((trait_did, name, rhs));
// FIXME(...): Remove this unwrap()
impl_trait_proj.entry(param_idx).or_default().push((
trait_did,
name,
rhs.ty().unwrap(),
));
}
return None;
@ -647,7 +674,7 @@ fn clean_ty_generics(
if let Some(proj) = impl_trait_proj.remove(&idx) {
for (trait_did, name, rhs) in proj {
let rhs = rhs.clean(cx);
simplify::merge_bounds(cx, &mut bounds, trait_did, name, &rhs);
simplify::merge_bounds(cx, &mut bounds, trait_did, name, &Term::Type(rhs));
}
}
} else {
@ -1495,7 +1522,9 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
for pb in obj.projection_bounds() {
bindings.push(TypeBinding {
name: cx.tcx.associated_item(pb.item_def_id()).ident.name,
kind: TypeBindingKind::Equality { ty: pb.skip_binder().ty.clean(cx) },
kind: TypeBindingKind::Equality {
term: pb.skip_binder().term.clean(cx).into(),
},
});
}
@ -1566,7 +1595,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
.ident
.name,
kind: TypeBindingKind::Equality {
ty: proj.ty.clean(cx),
term: proj.term.clean(cx),
},
})
} else {
@ -2114,10 +2143,10 @@ impl Clean<TypeBinding> for hir::TypeBinding<'_> {
impl Clean<TypeBindingKind> for hir::TypeBindingKind<'_> {
fn clean(&self, cx: &mut DocContext<'_>) -> TypeBindingKind {
match *self {
hir::TypeBindingKind::Equality { ref ty } => {
TypeBindingKind::Equality { ty: ty.clean(cx) }
hir::TypeBindingKind::Equality { ref term } => {
TypeBindingKind::Equality { term: term.clean(cx) }
}
hir::TypeBindingKind::Constraint { bounds } => TypeBindingKind::Constraint {
hir::TypeBindingKind::Constraint { ref bounds } => TypeBindingKind::Constraint {
bounds: bounds.iter().filter_map(|b| b.clean(cx)).collect(),
},
}

View File

@ -92,7 +92,7 @@ crate fn merge_bounds(
bounds: &mut Vec<clean::GenericBound>,
trait_did: DefId,
name: Symbol,
rhs: &clean::Type,
rhs: &clean::Term,
) -> bool {
!bounds.iter_mut().any(|b| {
let trait_ref = match *b {
@ -110,14 +110,14 @@ crate fn merge_bounds(
PP::AngleBracketed { ref mut bindings, .. } => {
bindings.push(clean::TypeBinding {
name,
kind: clean::TypeBindingKind::Equality { ty: rhs.clone() },
kind: clean::TypeBindingKind::Equality { term: rhs.clone() },
});
}
PP::Parenthesized { ref mut output, .. } => match output {
Some(o) => assert_eq!(o.as_ref(), rhs),
Some(o) => assert_eq!(&clean::Term::Type(o.as_ref().clone()), rhs),
None => {
if *rhs != clean::Type::Tuple(Vec::new()) {
*output = Some(Box::new(rhs.clone()));
if *rhs != clean::Term::Type(clean::Type::Tuple(Vec::new())) {
*output = Some(Box::new(rhs.ty().unwrap().clone()));
}
}
},

View File

@ -1212,7 +1212,7 @@ impl Lifetime {
crate enum WherePredicate {
BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<Lifetime> },
RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
EqPredicate { lhs: Type, rhs: Type },
EqPredicate { lhs: Type, rhs: Term },
}
impl WherePredicate {
@ -1308,7 +1308,9 @@ impl FnDecl {
FnRetTy::Return(Type::ImplTrait(bounds)) => match &bounds[0] {
GenericBound::TraitBound(PolyTrait { trait_, .. }, ..) => {
let bindings = trait_.bindings().unwrap();
FnRetTy::Return(bindings[0].ty().clone())
let ret_ty = bindings[0].term();
let ty = ret_ty.ty().expect("Unexpected constant return term");
FnRetTy::Return(ty.clone())
}
_ => panic!("unexpected desugaring of async function"),
},
@ -2121,6 +2123,24 @@ crate struct Constant {
crate kind: ConstantKind,
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
crate enum Term {
Type(Type),
Constant(Constant),
}
impl Term {
crate fn ty(&self) -> Option<&Type> {
if let Term::Type(ty) = self { Some(ty) } else { None }
}
}
impl From<Type> for Term {
fn from(ty: Type) -> Self {
Term::Type(ty)
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
crate enum ConstantKind {
/// This is the wrapper around `ty::Const` for a non-local constant. Because it doesn't have a
@ -2283,14 +2303,14 @@ crate struct TypeBinding {
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
crate enum TypeBindingKind {
Equality { ty: Type },
Equality { term: Term },
Constraint { bounds: Vec<GenericBound> },
}
impl TypeBinding {
crate fn ty(&self) -> &Type {
crate fn term(&self) -> &Term {
match self.kind {
TypeBindingKind::Equality { ref ty } => ty,
TypeBindingKind::Equality { ref term } => term,
_ => panic!("expected equality type binding for parenthesized generic args"),
}
}

View File

@ -1442,11 +1442,11 @@ impl clean::TypeBinding {
display_fn(move |f| {
f.write_str(self.name.as_str())?;
match self.kind {
clean::TypeBindingKind::Equality { ref ty } => {
clean::TypeBindingKind::Equality { ref term } => {
if f.alternate() {
write!(f, " = {:#}", ty.print(cx))?;
write!(f, " = {:#}", term.print(cx))?;
} else {
write!(f, " = {}", ty.print(cx))?;
write!(f, " = {}", term.print(cx))?;
}
}
clean::TypeBindingKind::Constraint { ref bounds } => {
@ -1492,6 +1492,18 @@ impl clean::GenericArg {
}
}
impl clean::types::Term {
crate fn print<'a, 'tcx: 'a>(
&'a self,
cx: &'a Context<'tcx>,
) -> impl fmt::Display + 'a + Captures<'tcx> {
match self {
clean::types::Term::Type(ty) => ty.print(cx),
_ => todo!(),
}
}
}
crate fn display_fn(f: impl FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl fmt::Display {
struct WithFormatter<F>(Cell<Option<F>>);

View File

@ -162,7 +162,7 @@ impl FromWithTcx<clean::TypeBindingKind> for TypeBindingKind {
fn from_tcx(kind: clean::TypeBindingKind, tcx: TyCtxt<'_>) -> Self {
use clean::TypeBindingKind::*;
match kind {
Equality { ty } => TypeBindingKind::Equality(ty.into_tcx(tcx)),
Equality { term } => TypeBindingKind::Equality(term.into_tcx(tcx)),
Constraint { bounds } => {
TypeBindingKind::Constraint(bounds.into_iter().map(|a| a.into_tcx(tcx)).collect())
}
@ -452,6 +452,15 @@ impl FromWithTcx<clean::Type> for Type {
}
}
impl FromWithTcx<clean::Term> for Term {
fn from_tcx(term: clean::Term, tcx: TyCtxt<'_>) -> Term {
match term {
clean::Term::Type(ty) => Term::Type(FromWithTcx::from_tcx(ty, tcx)),
clean::Term::Constant(c) => Term::Constant(FromWithTcx::from_tcx(c, tcx)),
}
}
}
impl FromWithTcx<clean::BareFunctionDecl> for FunctionPointer {
fn from_tcx(bare_decl: clean::BareFunctionDecl, tcx: TyCtxt<'_>) -> Self {
let clean::BareFunctionDecl { unsafety, generic_params, decl, abi } = bare_decl;

@ -1 +1 @@
Subproject commit 2abffbf977a9e8c6ca4174a08fe5c4d7781f0aac
Subproject commit 6b3dbcc81a470e5da84576d63fcfc19e3b1154cd

View File

@ -148,7 +148,7 @@ pub struct TypeBinding {
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum TypeBindingKind {
Equality(Type),
Equality(Term),
Constraint(Vec<GenericBound>),
}
@ -335,7 +335,7 @@ pub enum GenericParamDefKind {
pub enum WherePredicate {
BoundPredicate { ty: Type, bounds: Vec<GenericBound> },
RegionPredicate { lifetime: String, bounds: Vec<GenericBound> },
EqPredicate { lhs: Type, rhs: Type },
EqPredicate { lhs: Type, rhs: Term },
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
@ -359,6 +359,13 @@ pub enum TraitBoundModifier {
MaybeConst,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum Term {
Type(Type),
Constant(Constant),
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
#[serde(tag = "kind", content = "inner")]

View File

@ -0,0 +1,21 @@
#![feature(associated_const_equality)]
pub trait Foo {
const N: usize;
}
pub struct Bar;
impl Foo for Bar {
const N: usize = 3;
}
const TEST:usize = 3;
fn foo<F: Foo<N=3>>() {}
//~^ ERROR associated const equality is incomplete
fn bar<F: Foo<N={TEST}>>() {}
//~^ ERROR associated const equality is incomplete
fn main() {}

View File

@ -0,0 +1,14 @@
error: associated const equality is incomplete
--> $DIR/assoc-const.rs:16:15
|
LL | fn foo<F: Foo<N=3>>() {}
| ^^^ cannot yet relate associated const
error: associated const equality is incomplete
--> $DIR/assoc-const.rs:18:15
|
LL | fn bar<F: Foo<N={TEST}>>() {}
| ^^^^^^^^ cannot yet relate associated const
error: aborting due to 2 previous errors

View File

@ -7,8 +7,9 @@ struct Bar;
const T: usize = 42;
impl Foo<N = 3> for Bar {
//~^ ERROR cannot constrain an associated constant to a value
//~^ 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,11 +1,27 @@
error: cannot constrain an associated constant to a value
error[E0658]: associated const equality is incomplete
--> $DIR/issue-89013-no-kw.rs:9:10
|
LL | impl Foo<N = 3> for Bar {
| -^^^-
| | |
| | ...cannot be constrained to this value
| this associated constant...
| ^^^^^
|
= 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
|
LL | impl Foo<N = 3> for Bar {
| ^^^ expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `N`
--> $DIR/issue-89013-no-kw.rs:1:7
|
LL | trait Foo<const N: usize> {
| ^^^ -
help: add missing generic argument
|
LL | impl Foo<N, N = 3> for Bar {
| ++
error[E0229]: associated type bindings are not allowed here
--> $DIR/issue-89013-no-kw.rs:9:10
@ -13,6 +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
For more information about this error, try `rustc --explain E0229`.
Some errors have detailed explanations: E0107, E0229, E0658.
For more information about an error, try `rustc --explain E0107`.

View File

@ -8,8 +8,9 @@ const T: usize = 42;
impl Foo<N = const 3> for Bar {
//~^ ERROR expected lifetime, type, or constant, found keyword `const`
//~| ERROR cannot constrain an associated constant to a value
//~| 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,14 +10,30 @@ LL - impl Foo<N = const 3> for Bar {
LL + impl Foo<N = 3> for Bar {
|
error: cannot constrain an associated constant to a value
error[E0658]: associated const equality is incomplete
--> $DIR/issue-89013.rs:9:10
|
LL | impl Foo<N = const 3> for Bar {
| -^^^^^^^^^-
| | |
| | ...cannot be constrained to this value
| this associated constant...
| ^^^^^^^^^^^
|
= 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
|
LL | impl Foo<N = const 3> for Bar {
| ^^^ expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `N`
--> $DIR/issue-89013.rs:1:7
|
LL | trait Foo<const N: usize> {
| ^^^ -
help: add missing generic argument
|
LL | impl Foo<N, N = const 3> for Bar {
| ++
error[E0229]: associated type bindings are not allowed here
--> $DIR/issue-89013.rs:9:10
@ -25,6 +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
For more information about this error, try `rustc --explain 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,7 +1,9 @@
#[cfg(FALSE)]
fn syntax() {
bar::<Item = 42>(); //~ ERROR cannot constrain an associated constant to a value
bar::<Item = { 42 }>(); //~ ERROR cannot constrain an associated constant to a value
bar::<Item = 42>();
//~^ ERROR associated const equality is incomplete
bar::<Item = { 42 }>();
//~^ ERROR associated const equality is incomplete
}
fn main() {}

View File

@ -1,20 +1,21 @@
error: cannot constrain an associated constant to a value
error[E0658]: associated const equality is incomplete
--> $DIR/recover-assoc-const-constraint.rs:3:11
|
LL | bar::<Item = 42>();
| ----^^^--
| | |
| | ...cannot be constrained to this value
| this associated constant...
| ^^^^^^^^^
|
= 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: cannot constrain an associated constant to a value
--> $DIR/recover-assoc-const-constraint.rs:4:11
error[E0658]: associated const equality is incomplete
--> $DIR/recover-assoc-const-constraint.rs:5:11
|
LL | bar::<Item = { 42 }>();
| ----^^^------
| | |
| | ...cannot be constrained to this value
| this associated constant...
| ^^^^^^^^^^^^^
|
= 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

@ -1,4 +1,4 @@
error: cannot specialize on `Binder(ProjectionPredicate(ProjectionTy { substs: [V], item_def_id: DefId(0:6 ~ repeated_projection_type[HASH]::Id::This) }, (I,)), [])`
error: cannot specialize on `Binder(ProjectionPredicate(ProjectionTy { substs: [V], item_def_id: DefId(0:6 ~ repeated_projection_type[HASH]::Id::This) }, Ty((I,))), [])`
--> $DIR/repeated_projection_type.rs:19:1
|
LL | / impl<I, V: Id<This = (I,)>> X for V {

@ -1 +1 @@
Subproject commit 06b9d31743210b788b130c8a484c2838afa6fc27
Subproject commit 358e79fe56fe374649275ca7aebaafd57ade0e8d

View File

@ -6,7 +6,7 @@ use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{
AsyncGeneratorKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericArg, GenericBound, HirId,
Term, AsyncGeneratorKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericArg, GenericBound, HirId,
IsAsync, ItemKind, LifetimeName, TraitRef, Ty, TyKind, TypeBindingKind,
};
use rustc_lint::{LateContext, LateLintPass};
@ -140,7 +140,7 @@ fn future_output_ty<'tcx>(trait_ref: &'tcx TraitRef<'tcx>) -> Option<&'tcx Ty<'t
if args.bindings.len() == 1;
let binding = &args.bindings[0];
if binding.ident.name == sym::Output;
if let TypeBindingKind::Equality{ty: output} = binding.kind;
if let TypeBindingKind::Equality{term: Term::Ty(output)} = binding.kind;
then {
return Some(output)
}

View File

@ -2178,12 +2178,16 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
// one of the associated types must be Self
for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() {
let assoc_ty = match projection_predicate.term {
ty::Term::Ty(ty) => ty,
ty::Term::Const(_c) => continue,
};
// walk the associated type and check for Self
if let Some(self_adt) = self_ty.ty_adt_def() {
if contains_adt_constructor(projection_predicate.ty, self_adt) {
if contains_adt_constructor(assoc_ty, self_adt) {
return;
}
} else if contains_ty(projection_predicate.ty, self_ty) {
} else if contains_ty(assoc_ty, self_ty) {
return;
}
}

View File

@ -243,9 +243,10 @@ fn check_other_call_arg<'tcx>(
if if trait_predicate.def_id() == deref_trait_id {
if let [projection_predicate] = projection_predicates[..] {
let normalized_ty =
cx.tcx.subst_and_normalize_erasing_regions(call_substs, cx.param_env, projection_predicate.ty);
cx.tcx.subst_and_normalize_erasing_regions(call_substs, cx.param_env, projection_predicate.term);
implements_trait(cx, receiver_ty, deref_trait_id, &[])
&& get_associated_type(cx, receiver_ty, deref_trait_id, "Target") == Some(normalized_ty)
&& get_associated_type(cx, receiver_ty, deref_trait_id,
"Target").map_or(false, |ty| ty::Term::Ty(ty) == normalized_ty)
} else {
false
}

View File

@ -98,9 +98,10 @@ fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Ve
if trait_pred.self_ty() == inp;
if let Some(return_ty_pred) = get_projection_pred(cx, generics, *trait_pred);
then {
if ord_preds.iter().any(|ord| ord.self_ty() == return_ty_pred.ty) {
if ord_preds.iter().any(|ord| Some(ord.self_ty()) ==
return_ty_pred.term.ty()) {
args_to_check.push((i, "Ord".to_string()));
} else if partial_ord_preds.iter().any(|pord| pord.self_ty() == return_ty_pred.ty) {
} else if partial_ord_preds.iter().any(|pord| pord.self_ty() == return_ty_pred.term.ty().unwrap()) {
args_to_check.push((i, "PartialOrd".to_string()));
}
}

View File

@ -645,11 +645,19 @@ pub fn eq_generic_bound(l: &GenericBound, r: &GenericBound) -> bool {
}
}
pub fn eq_assoc_constraint(l: &AssocTyConstraint, r: &AssocTyConstraint) -> bool {
use AssocTyConstraintKind::*;
fn eq_term(l: &Term, r: &Term) -> bool {
match (l, r) {
(Term::Ty(l), Term::Ty(r)) => eq_ty(l,r),
(Term::Const(l), Term::Const(r)) => eq_anon_const(l,r),
_ => false,
}
}
pub fn eq_assoc_constraint(l: &AssocConstraint, r: &AssocConstraint) -> bool {
use AssocConstraintKind::*;
eq_id(l.ident, r.ident)
&& match (&l.kind, &r.kind) {
(Equality { ty: l }, Equality { ty: r }) => eq_ty(l, r),
(Equality { term: l }, Equality { term: r }) => eq_term(l, r),
(Bound { bounds: l }, Bound { bounds: r }) => over(l, r, eq_generic_bound),
_ => false,
}

@ -1 +1 @@
Subproject commit 0f8c96c92689af8378dbe9f466c6bf15a3a27458
Subproject commit 8e9ccbf97a70259b6c6576e8fd7d77d28238737e

View File

@ -1,7 +1,7 @@
use std::iter::ExactSizeIterator;
use std::ops::Deref;
use rustc_ast::ast::{self, FnRetTy, Mutability};
use rustc_ast::ast::{self, FnRetTy, Mutability, Term};
use rustc_ast::ptr;
use rustc_span::{symbol::kw, BytePos, Pos, Span};
@ -141,7 +141,7 @@ pub(crate) enum SegmentParam<'a> {
Const(&'a ast::AnonConst),
LifeTime(&'a ast::Lifetime),
Type(&'a ast::Ty),
Binding(&'a ast::AssocTyConstraint),
Binding(&'a ast::AssocConstraint),
}
impl<'a> SegmentParam<'a> {
@ -176,9 +176,9 @@ impl<'a> Rewrite for SegmentParam<'a> {
}
}
impl Rewrite for ast::AssocTyConstraint {
impl Rewrite for ast::AssocConstraint {
fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
use ast::AssocTyConstraintKind::{Bound, Equality};
use ast::AssocConstraintKind::{Bound, Equality};
let mut result = String::with_capacity(128);
result.push_str(rewrite_ident(context, self.ident));
@ -206,11 +206,14 @@ impl Rewrite for ast::AssocTyConstraint {
}
}
impl Rewrite for ast::AssocTyConstraintKind {
impl Rewrite for ast::AssocConstraintKind {
fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
match self {
ast::AssocTyConstraintKind::Equality { ty } => ty.rewrite(context, shape),
ast::AssocTyConstraintKind::Bound { bounds } => bounds.rewrite(context, shape),
ast::AssocConstraintKind::Equality { term } => match term {
Term::Ty(ty) => ty.rewrite(context, shape),
Term::Const(c) => c.rewrite(context, shape),
},
ast::AssocConstraintKind::Bound { bounds } => bounds.rewrite(context, shape),
}
}
}