1
Fork 0

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

View file

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

View file

@ -165,8 +165,8 @@ pub trait MutVisitor: Sized {
noop_visit_lifetime(l, self); noop_visit_lifetime(l, self);
} }
fn visit_ty_constraint(&mut self, t: &mut AssocTyConstraint) { fn visit_constraint(&mut self, t: &mut AssocConstraint) {
noop_visit_ty_constraint(t, self); noop_visit_constraint(t, self);
} }
fn visit_foreign_mod(&mut self, nm: &mut ForeignMod) { 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] smallvec![arm]
} }
pub fn noop_visit_ty_constraint<T: MutVisitor>( pub fn noop_visit_constraint<T: MutVisitor>(
AssocTyConstraint { id, ident, gen_args, kind, span }: &mut AssocTyConstraint, AssocConstraint { id, ident, gen_args, kind, span }: &mut AssocConstraint,
vis: &mut T, vis: &mut T,
) { ) {
vis.visit_id(id); vis.visit_id(id);
@ -440,12 +440,11 @@ pub fn noop_visit_ty_constraint<T: MutVisitor>(
vis.visit_generic_args(gen_args); vis.visit_generic_args(gen_args);
} }
match kind { match kind {
AssocTyConstraintKind::Equality { ref mut ty } => { AssocConstraintKind::Equality { ref mut term } => match term {
vis.visit_ty(ty); Term::Ty(ty) => vis.visit_ty(ty),
} Term::Const(c) => vis.visit_anon_const(c),
AssocTyConstraintKind::Bound { ref mut bounds } => { },
visit_bounds(bounds, vis); AssocConstraintKind::Bound { ref mut bounds } => visit_bounds(bounds, vis),
}
} }
vis.visit_span(span); vis.visit_span(span);
} }
@ -555,7 +554,7 @@ pub fn noop_visit_angle_bracketed_parameter_data<T: MutVisitor>(
let AngleBracketedArgs { args, span } = data; let AngleBracketedArgs { args, span } = data;
visit_vec(args, |arg| match arg { visit_vec(args, |arg| match arg {
AngleBracketedArg::Arg(arg) => vis.visit_generic_arg(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); 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) { fn visit_generic_arg(&mut self, generic_arg: &'ast GenericArg) {
walk_generic_arg(self, generic_arg) walk_generic_arg(self, generic_arg)
} }
fn visit_assoc_ty_constraint(&mut self, constraint: &'ast AssocTyConstraint) { fn visit_assoc_constraint(&mut self, constraint: &'ast AssocConstraint) {
walk_assoc_ty_constraint(self, constraint) walk_assoc_constraint(self, constraint)
} }
fn visit_attribute(&mut self, attr: &'ast Attribute) { fn visit_attribute(&mut self, attr: &'ast Attribute) {
walk_attribute(self, attr) walk_attribute(self, attr)
@ -464,7 +464,7 @@ where
for arg in &data.args { for arg in &data.args {
match arg { match arg {
AngleBracketedArg::Arg(a) => visitor.visit_generic_arg(a), 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>>( pub fn walk_assoc_constraint<'a, V: Visitor<'a>>(visitor: &mut V, constraint: &'a AssocConstraint) {
visitor: &mut V,
constraint: &'a AssocTyConstraint,
) {
visitor.visit_ident(constraint.ident); visitor.visit_ident(constraint.ident);
if let Some(ref gen_args) = constraint.gen_args { if let Some(ref gen_args) = constraint.gen_args {
visitor.visit_generic_args(gen_args.span(), gen_args); visitor.visit_generic_args(gen_args.span(), gen_args);
} }
match constraint.kind { match constraint.kind {
AssocTyConstraintKind::Equality { ref ty } => { AssocConstraintKind::Equality { ref term } => match term {
visitor.visit_ty(ty); Term::Ty(ty) => visitor.visit_ty(ty),
} Term::Const(c) => visitor.visit_anon_const(c),
AssocTyConstraintKind::Bound { ref bounds } => { },
AssocConstraintKind::Bound { ref bounds } => {
walk_list!(visitor, visit_param_bound, 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`. /// returns a `hir::TypeBinding` representing `Item`.
fn lower_assoc_ty_constraint( fn lower_assoc_ty_constraint(
&mut self, &mut self,
constraint: &AssocTyConstraint, constraint: &AssocConstraint,
mut itctx: ImplTraitContext<'_, 'hir>, mut itctx: ImplTraitContext<'_, 'hir>,
) -> hir::TypeBinding<'hir> { ) -> hir::TypeBinding<'hir> {
debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx); debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx);
@ -997,10 +997,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}; };
let kind = match constraint.kind { let kind = match constraint.kind {
AssocTyConstraintKind::Equality { ref ty } => { AssocConstraintKind::Equality { ref term } => {
hir::TypeBindingKind::Equality { ty: self.lower_ty(ty, itctx) } 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 capturable_lifetimes;
let mut parent_def_id = self.current_hir_id_owner; let mut parent_def_id = self.current_hir_id_owner;
// Piggy-back on the `impl Trait` context to figure out the correct behavior. // Piggy-back on the `impl Trait` context to figure out the correct behavior.
@ -1078,7 +1082,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
itctx, itctx,
); );
hir::TypeBindingKind::Equality { ty } hir::TypeBindingKind::Equality { term: ty.into() }
}) })
} else { } else {
// Desugar `AssocTy: Bounds` into a type binding where the // 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>, ty: &'hir hir::Ty<'hir>,
) -> hir::TypeBinding<'hir> { ) -> hir::TypeBinding<'hir> {
let ident = Ident::with_dummy_span(hir::FN_OUTPUT_NAME); 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 args = arena_vec![self;];
let bindings = arena_vec![self;]; let bindings = arena_vec![self;];
let gen_args = self.arena.alloc(hir::GenericArgs { let gen_args = self.arena.alloc(hir::GenericArgs {

View file

@ -138,10 +138,10 @@ impl<'a> AstValidator<'a> {
self.outer_impl_trait = old; 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 { match constraint.kind {
AssocTyConstraintKind::Equality { .. } => {} AssocConstraintKind::Equality { .. } => {}
AssocTyConstraintKind::Bound { .. } => { AssocConstraintKind::Bound { .. } => {
if self.is_assoc_ty_bound_banned { if self.is_assoc_ty_bound_banned {
self.err_handler().span_err( self.err_handler().span_err(
constraint.span, 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. // 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`. // are allowed to contain nested `impl Trait`.
AngleBracketedArg::Constraint(constraint) => { AngleBracketedArg::Constraint(constraint) => {
self.with_impl_trait(None, |this| { 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 len = assoc_path.segments.len() - 1;
let gen_args = args.as_ref().map(|p| (**p).clone()); let gen_args = args.as_ref().map(|p| (**p).clone());
// Build `<Bar = RhsTy>`. // Build `<Bar = RhsTy>`.
let arg = AngleBracketedArg::Constraint(AssocTyConstraint { let arg = AngleBracketedArg::Constraint(AssocConstraint {
id: rustc_ast::node_id::DUMMY_NODE_ID, id: rustc_ast::node_id::DUMMY_NODE_ID,
ident: *ident, ident: *ident,
gen_args, gen_args,
kind: AssocTyConstraintKind::Equality { kind: AssocConstraintKind::Equality {
ty: predicate.rhs_ty.clone(), term: predicate.rhs_ty.clone().into(),
}, },
span: ident.span, span: ident.span,
}); });

View file

@ -1,6 +1,6 @@
use rustc_ast as ast; use rustc_ast as ast;
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; 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_ast::{PatKind, RangeEnd, VariantData};
use rustc_errors::struct_span_err; use rustc_errors::struct_span_err;
use rustc_feature::{AttributeGate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; 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) visit::walk_fn(self, fn_kind, span)
} }
fn visit_assoc_ty_constraint(&mut self, constraint: &'a AssocTyConstraint) { fn visit_assoc_constraint(&mut self, constraint: &'a AssocConstraint) {
if let AssocTyConstraintKind::Bound { .. } = constraint.kind { if let AssocConstraintKind::Bound { .. } = constraint.kind {
gate_feature_post!( gate_feature_post!(
&self, &self,
associated_type_bounds, associated_type_bounds,
@ -631,7 +631,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
"associated type bounds are unstable" "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) { 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!(half_open_range_patterns, "half-open range patterns are unstable");
gate_all!(inline_const, "inline-const is experimental"); gate_all!(inline_const, "inline-const is experimental");
gate_all!(inline_const_pat, "inline-const in pattern position 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, // All uses of `gate_all!` below this point were added in #65742,
// and subsequently disabled (with the non-early gating readded). // and subsequently disabled (with the non-early gating readded).

View file

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

View file

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

View file

@ -779,7 +779,10 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
[ [
hir::TypeBinding { hir::TypeBinding {
ident: Ident { name: sym::Output, .. }, 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 let projection_bounds: SmallVec<[_; 4]> = trait_data
.projection_bounds() .projection_bounds()
.map(|bound| { .map(|bound| {
let ExistentialProjection { item_def_id, ty, .. } = bound.skip_binder(); let ExistentialProjection { item_def_id, term, .. } = bound.skip_binder();
(item_def_id, ty) // FIXME(associated_const_equality): allow for consts here
(item_def_id, term.ty().unwrap())
}) })
.collect(); .collect();

View file

@ -288,6 +288,8 @@ declare_features! (
(active, asm_sym, "1.58.0", Some(72016), None), (active, asm_sym, "1.58.0", Some(72016), None),
/// Allows the `may_unwind` option in inline assembly. /// Allows the `may_unwind` option in inline assembly.
(active, asm_unwind, "1.58.0", Some(72016), None), (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. /// Allows the user of associated type bounds.
(active, associated_type_bounds, "1.34.0", Some(52662), None), (active, associated_type_bounds, "1.34.0", Some(52662), None),
/// Allows associated type defaults. /// Allows associated type defaults.

View file

@ -377,7 +377,7 @@ impl GenericArgs<'_> {
GenericArg::Type(ty) => matches!(ty.kind, TyKind::Err), GenericArg::Type(ty) => matches!(ty.kind, TyKind::Err),
_ => false, _ => false,
}) || self.bindings.iter().any(|arg| match arg.kind { }) || 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, _ => false,
}) })
} }
@ -2129,19 +2129,37 @@ pub struct TypeBinding<'hir> {
pub span: Span, 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. // Represents the two kinds of type bindings.
#[derive(Debug, HashStable_Generic)] #[derive(Debug, HashStable_Generic)]
pub enum TypeBindingKind<'hir> { pub enum TypeBindingKind<'hir> {
/// E.g., `Foo<Bar: Send>`. /// E.g., `Foo<Bar: Send>`.
Constraint { bounds: &'hir [GenericBound<'hir>] }, Constraint { bounds: &'hir [GenericBound<'hir>] },
/// E.g., `Foo<Bar = ()>`. /// E.g., `Foo<Bar = ()>`, `Foo<Bar = ()>`
Equality { ty: &'hir Ty<'hir> }, Equality { term: Term<'hir> },
} }
impl TypeBinding<'_> { impl TypeBinding<'_> {
pub fn ty(&self) -> &Ty<'_> { pub fn ty(&self) -> &Ty<'_> {
match self.kind { 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"), _ => 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_ident(type_binding.ident);
visitor.visit_generic_args(type_binding.span, type_binding.gen_args); visitor.visit_generic_args(type_binding.span, type_binding.gen_args);
match type_binding.kind { match type_binding.kind {
TypeBindingKind::Equality { ref ty } => { TypeBindingKind::Equality { ref term } => match term {
visitor.visit_ty(ty); 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); 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::pp::{self, Breaks};
use rustc_ast_pretty::pprust::{Comments, PrintState}; use rustc_ast_pretty::pprust::{Comments, PrintState};
use rustc_hir as hir; 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_hir::{GenericBound, PatKind, RangeEnd, TraitBoundModifier};
use rustc_span::source_map::{SourceMap, Spanned}; use rustc_span::source_map::{SourceMap, Spanned};
use rustc_span::symbol::{kw, Ident, IdentPrinter, Symbol}; 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.print_generic_args(binding.gen_args, false, false);
self.space(); self.space();
match generic_args.bindings[0].kind { match generic_args.bindings[0].kind {
hir::TypeBindingKind::Equality { ref ty } => { hir::TypeBindingKind::Equality { ref term } => {
self.word_space("="); 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 } => { hir::TypeBindingKind::Constraint { bounds } => {
self.print_bounds(":", 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 { if projection_predicate.projection_ty.item_def_id == item_def_id {
// We don't account for multiple `Future::Output = Ty` contraints. // 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() { for type_binding in generic_args.bindings.iter() {
if type_binding.ident.name == rustc_span::sym::Output { if type_binding.ident.name == rustc_span::sym::Output {
if let hir::TypeBindingKind::Equality { ty } = if let hir::TypeBindingKind::Equality {
type_binding.kind term: hir::Term::Ty(ty),
} = type_binding.kind
{ {
return Some(ty); return Some(ty);
} }

View file

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

View file

@ -26,7 +26,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
kind: TypeVariableOriginKind::NormalizeProjectionType, kind: TypeVariableOriginKind::NormalizeProjectionType,
span: self.tcx.def_span(def_id), 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( let obligation = Obligation::with_depth(
cause, cause,
recursion_depth, recursion_depth,

View file

@ -1,7 +1,7 @@
use libloading::Library; use libloading::Library;
use rustc_ast::mut_visit::{visit_clobber, MutVisitor, *}; use rustc_ast::mut_visit::{visit_clobber, MutVisitor, *};
use rustc_ast::ptr::P; 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_codegen_ssa::traits::CodegenBackend;
use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::fx::{FxHashMap, FxHashSet};
#[cfg(parallel_compiler)] #[cfg(parallel_compiler)]
@ -738,9 +738,14 @@ impl<'a, 'b> ReplaceBodyWithLoop<'a, 'b> {
| ast::GenericArg::Const(_) => false, | ast::GenericArg::Const(_) => false,
}, },
ast::AngleBracketedArg::Constraint(c) => match c.kind { ast::AngleBracketedArg::Constraint(c) => match c.kind {
ast::AssocTyConstraintKind::Bound { .. } => true, ast::AssocConstraintKind::Bound { .. } => true,
ast::AssocTyConstraintKind::Equality { ref ty } => { ast::AssocConstraintKind::Equality { ref term } => {
involves_impl_trait(ty) 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)) .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. /// Returns the associated item with the given name in the given `Namespace`, if one exists.
pub fn find_by_name_and_namespace( pub fn find_by_name_and_namespace(
&self, &self,

View file

@ -86,10 +86,14 @@ impl<'tcx> Const<'tcx> {
if let Some(lit_input) = lit_input { if let Some(lit_input) = lit_input {
// If an error occurred, ignore that it's a literal and leave reporting the error up to // If an error occurred, ignore that it's a literal and leave reporting the error up to
// mir. // mir.
if let Ok(c) = tcx.at(expr.span).lit_to_const(lit_input) { match tcx.at(expr.span).lit_to_const(lit_input) {
return Some(c); Ok(c) => return Some(c),
} else { Err(e) => {
tcx.sess.delay_span_bug(expr.span, "Const::from_anon_const: couldn't lit_to_const"); 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::TyKind::*;
use crate::ty::{ use crate::ty::{
ConstKind, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, InferTy, ConstKind, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, InferTy,
ProjectionTy, TyCtxt, TyS, TypeAndMut, ProjectionTy, Term, TyCtxt, TyS, TypeAndMut,
}; };
use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_errors::{Applicability, DiagnosticBuilder};
@ -105,8 +105,14 @@ impl<'tcx> TyS<'tcx> {
ExistentialPredicate::Trait(ExistentialTraitRef { substs, .. }) => { ExistentialPredicate::Trait(ExistentialTraitRef { substs, .. }) => {
substs.iter().all(generic_arg_is_suggestible) substs.iter().all(generic_arg_is_suggestible)
} }
ExistentialPredicate::Projection(ExistentialProjection { substs, ty, .. }) => { ExistentialPredicate::Projection(ExistentialProjection {
ty.is_suggestable() && substs.iter().all(generic_arg_is_suggestible) 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, _ => true,
}), }),

View file

@ -1,5 +1,5 @@
use crate::ty::subst::{GenericArg, GenericArgKind}; use crate::ty::subst::{GenericArg, GenericArgKind};
use crate::ty::{self, InferConst, Ty, TypeFlags}; use crate::ty::{self, InferConst, Term, Ty, TypeFlags};
use std::slice; use std::slice;
#[derive(Debug)] #[derive(Debug)]
@ -241,9 +241,12 @@ impl FlagComputation {
self.add_ty(a); self.add_ty(a);
self.add_ty(b); 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_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) => { ty::PredicateKind::WellFormed(arg) => {
self.add_substs(slice::from_ref(&arg)); self.add_substs(slice::from_ref(&arg));
@ -317,7 +320,10 @@ impl FlagComputation {
fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<'_>) { fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<'_>) {
self.add_substs(projection.substs); 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<'_>) { 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"))] #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
static_assert_size!(PredicateInner<'_>, 48); static_assert_size!(PredicateInner<'_>, 56);
#[derive(Clone, Copy, Lift)] #[derive(Clone, Copy, Lift)]
pub struct Predicate<'tcx> { pub struct Predicate<'tcx> {
@ -795,6 +795,31 @@ pub struct CoercePredicate<'tcx> {
} }
pub type PolyCoercePredicate<'tcx> = ty::Binder<'tcx, 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 /// This kind of predicate has no *direct* correspondent in the
/// syntax, but it roughly corresponds to the syntactic forms: /// 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)] #[derive(HashStable, TypeFoldable)]
pub struct ProjectionPredicate<'tcx> { pub struct ProjectionPredicate<'tcx> {
pub projection_ty: ProjectionTy<'tcx>, pub projection_ty: ProjectionTy<'tcx>,
pub ty: Ty<'tcx>, pub term: Term<'tcx>,
} }
pub type PolyProjectionPredicate<'tcx> = Binder<'tcx, ProjectionPredicate<'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)) self.map_bound(|predicate| predicate.projection_ty.trait_ref(tcx))
} }
pub fn ty(&self) -> Binder<'tcx, Ty<'tcx>> { pub fn term(&self) -> Binder<'tcx, Term<'tcx>> {
self.map_bound(|predicate| predicate.ty) self.map_bound(|predicate| predicate.term)
} }
/// The `DefId` of the `TraitItem` for the associated type. /// 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::mir::interpret::{AllocRange, ConstValue, GlobalAlloc, Pointer, Provenance, Scalar};
use crate::ty::subst::{GenericArg, GenericArgKind, Subst}; 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_apfloat::ieee::{Double, Single};
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sso::SsoHashSet; 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()); let trait_ref = proj_ref.required_poly_trait_ref(self.tcx());
// Projection type entry -- the def-id for naming, and the ty. // 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( self.insert_trait_and_projection(
trait_ref, trait_ref,
@ -850,8 +850,10 @@ pub trait PrettyPrinter<'tcx>:
} }
p!(")"); p!(")");
if !return_ty.skip_binder().is_unit() { if let Term::Ty(ty) = return_ty.skip_binder() {
p!("-> ", print(return_ty)); if !ty.is_unit() {
p!("-> ", print(return_ty));
}
} }
p!(write("{}", if paren_needed { ")" } else { "" })); p!(write("{}", if paren_needed { ")" } else { "" }));
@ -902,23 +904,28 @@ pub trait PrettyPrinter<'tcx>:
first = false; first = false;
} }
for (assoc_item_def_id, ty) in assoc_items { for (assoc_item_def_id, term) in assoc_items {
if !first { if !first {
p!(", "); p!(", ");
} }
p!(write("{} = ", self.tcx().associated_item(assoc_item_def_id).ident)); p!(write("{} = ", self.tcx().associated_item(assoc_item_def_id).ident));
// Skip printing `<[generator@] as Generator<_>>::Return` from async blocks match term.skip_binder() {
match ty.skip_binder().kind() { Term::Ty(ty) => {
ty::Projection(ty::ProjectionTy { item_def_id, .. }) // Skip printing `<[generator@] as Generator<_>>::Return` from async blocks
if Some(*item_def_id) == self.tcx().lang_items().generator_return() => if matches!(
{ ty.kind(), ty::Projection(ty::ProjectionTy { item_def_id, .. })
p!("[async output]") if Some(*item_def_id) == self.tcx().lang_items().generator_return()
) {
p!("[async output]")
} else {
p!(print(ty))
}
} }
_ => { Term::Const(c) => {
p!(print(ty)) p!(print(c));
} }
} };
first = false; first = false;
} }
@ -943,8 +950,11 @@ pub trait PrettyPrinter<'tcx>:
fn insert_trait_and_projection( fn insert_trait_and_projection(
&mut self, &mut self,
trait_ref: ty::PolyTraitRef<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>,
proj_ty: Option<(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, Ty<'tcx>>>>, traits: &mut BTreeMap<
ty::PolyTraitRef<'tcx>,
BTreeMap<DefId, ty::Binder<'tcx, Term<'tcx>>>,
>,
fn_traits: &mut BTreeMap<ty::PolyTraitRef<'tcx>, OpaqueFnEntry<'tcx>>, fn_traits: &mut BTreeMap<ty::PolyTraitRef<'tcx>, OpaqueFnEntry<'tcx>>,
) { ) {
let trait_def_id = trait_ref.def_id(); let trait_def_id = trait_ref.def_id();
@ -1019,7 +1029,11 @@ pub trait PrettyPrinter<'tcx>:
let mut projections = predicates.projection_bounds(); let mut projections = predicates.projection_bounds();
if let (Some(proj), None) = (projections.next(), projections.next()) { if let (Some(proj), None) = (projections.next(), projections.next()) {
let tys: Vec<_> = args.iter().map(|k| k.expect_ty()).collect(); 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; resugared = true;
} }
} }
@ -2442,7 +2456,7 @@ define_print_and_forward_display! {
ty::ExistentialProjection<'tcx> { ty::ExistentialProjection<'tcx> {
let name = cx.tcx().associated_item(self.item_def_id).ident; 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> { ty::ExistentialPredicate<'tcx> {
@ -2499,7 +2513,14 @@ define_print_and_forward_display! {
} }
ty::ProjectionPredicate<'tcx> { 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> { ty::ProjectionTy<'tcx> {
@ -2709,5 +2730,5 @@ pub struct OpaqueFnEntry<'tcx> {
has_fn_once: bool, has_fn_once: bool,
fn_mut_trait_ref: Option<ty::PolyTraitRef<'tcx>>, fn_mut_trait_ref: Option<ty::PolyTraitRef<'tcx>>,
fn_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::mir::interpret::{get_slice_bytes, ConstValue, GlobalAlloc, Scalar};
use crate::ty::error::{ExpectedFound, TypeError}; use crate::ty::error::{ExpectedFound, TypeError};
use crate::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef}; 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 as ast;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_span::DUMMY_SP; use rustc_span::DUMMY_SP;
@ -291,11 +291,11 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialProjection<'tcx> {
b.item_def_id, b.item_def_id,
))) )))
} else { } else {
let ty = relation.relate_with_variance( let term = relation.relate_with_variance(
ty::Invariant, ty::Invariant,
ty::VarianceDiagInfo::default(), ty::VarianceDiagInfo::default(),
a.ty, a.term,
b.ty, b.term,
)?; )?;
let substs = relation.relate_with_variance( let substs = relation.relate_with_variance(
ty::Invariant, ty::Invariant,
@ -303,7 +303,7 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialProjection<'tcx> {
a.substs, a.substs,
b.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> { impl<'tcx> Relate<'tcx> for ty::ProjectionPredicate<'tcx> {
fn relate<R: TypeRelation<'tcx>>( fn relate<R: TypeRelation<'tcx>>(
relation: &mut R, relation: &mut R,
@ -841,7 +855,7 @@ impl<'tcx> Relate<'tcx> for ty::ProjectionPredicate<'tcx> {
) -> RelateResult<'tcx, ty::ProjectionPredicate<'tcx>> { ) -> RelateResult<'tcx, ty::ProjectionPredicate<'tcx>> {
Ok(ty::ProjectionPredicate { Ok(ty::ProjectionPredicate {
projection_ty: relation.relate(a.projection_ty, b.projection_ty)?, 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::mir::ProjectionKind;
use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeVisitor}; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeVisitor};
use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer}; 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_data_structures::functor::IdFunctor;
use rustc_hir::def::Namespace; use rustc_hir::def::Namespace;
use rustc_hir::def_id::CRATE_DEF_INDEX; 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> { impl<'tcx> fmt::Debug for ty::ProjectionPredicate<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 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> { impl<'a, 'tcx> Lift<'tcx> for ty::TraitPredicate<'a> {
type Lifted = ty::TraitPredicate<'tcx>; type Lifted = ty::TraitPredicate<'tcx>;
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<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> { impl<'a, 'tcx> Lift<'tcx> for ty::ProjectionPredicate<'a> {
type Lifted = ty::ProjectionPredicate<'tcx>; type Lifted = ty::ProjectionPredicate<'tcx>;
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ty::ProjectionPredicate<'tcx>> { fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ty::ProjectionPredicate<'tcx>> {
tcx.lift((self.projection_ty, self.ty)) tcx.lift((self.projection_ty, self.term))
.map(|(projection_ty, ty)| ty::ProjectionPredicate { projection_ty, ty }) .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> { fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
tcx.lift(self.substs).map(|substs| ty::ExistentialProjection { tcx.lift(self.substs).map(|substs| ty::ExistentialProjection {
substs, 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, 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::fold::ValidateBoundVars;
use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef}; use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
use crate::ty::InferTy::{self, *}; 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 crate::ty::{DelaySpanBugEmitted, List, ParamEnv, TyS};
use polonius_engine::Atom; use polonius_engine::Atom;
use rustc_data_structures::captures::Captures; use rustc_data_structures::captures::Captures;
@ -1540,7 +1540,7 @@ impl From<BoundVar> for BoundTy {
pub struct ExistentialProjection<'tcx> { pub struct ExistentialProjection<'tcx> {
pub item_def_id: DefId, pub item_def_id: DefId,
pub substs: SubstsRef<'tcx>, pub substs: SubstsRef<'tcx>,
pub ty: Ty<'tcx>, pub term: Term<'tcx>,
} }
pub type PolyExistentialProjection<'tcx> = Binder<'tcx, ExistentialProjection<'tcx>>; pub type PolyExistentialProjection<'tcx> = Binder<'tcx, ExistentialProjection<'tcx>>;
@ -1570,7 +1570,7 @@ impl<'tcx> ExistentialProjection<'tcx> {
item_def_id: self.item_def_id, item_def_id: self.item_def_id,
substs: tcx.mk_substs_trait(self_ty, self.substs), substs: tcx.mk_substs_trait(self_ty, self.substs),
}, },
ty: self.ty, term: self.term,
} }
} }
@ -1584,7 +1584,7 @@ impl<'tcx> ExistentialProjection<'tcx> {
Self { Self {
item_def_id: projection_predicate.projection_ty.item_def_id, item_def_id: projection_predicate.projection_ty.item_def_id,
substs: tcx.intern_substs(&projection_predicate.projection_ty.substs[1..]), 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| { stack.extend(obj.iter().rev().flat_map(|predicate| {
let (substs, opt_ty) = match predicate.skip_binder() { let (substs, opt_ty) = match predicate.skip_binder() {
ty::ExistentialPredicate::Trait(tr) => (tr.substs, None), 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(_) => ty::ExistentialPredicate::AutoTrait(_) =>
// Empty iterator // 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) ty::Adt(_, substs)

View file

@ -4,8 +4,8 @@ use crate::maybe_whole;
use rustc_ast::ptr::P; use rustc_ast::ptr::P;
use rustc_ast::token::{self, Token}; use rustc_ast::token::{self, Token};
use rustc_ast::{ use rustc_ast::{
self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocTyConstraint, self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocConstraint,
AssocTyConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs, AssocConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs,
Path, PathSegment, QSelf, Path, PathSegment, QSelf,
}; };
use rustc_errors::{pluralize, Applicability, PResult}; use rustc_errors::{pluralize, Applicability, PResult};
@ -469,12 +469,9 @@ impl<'a> Parser<'a> {
// Parse associated type constraint bound. // Parse associated type constraint bound.
let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?; let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?;
AssocTyConstraintKind::Bound { bounds } AssocConstraintKind::Bound { bounds }
} else if self.eat(&token::Eq) { } else if self.eat(&token::Eq) {
// Parse associated type equality constraint self.parse_assoc_equality_term(ident, self.prev_token.span)?
let ty = self.parse_assoc_equality_term(ident, self.prev_token.span)?;
AssocTyConstraintKind::Equality { ty }
} else { } else {
unreachable!(); unreachable!();
}; };
@ -482,11 +479,11 @@ impl<'a> Parser<'a> {
let span = lo.to(self.prev_token.span); let span = lo.to(self.prev_token.span);
// Gate associated type bounds, e.g., `Iterator<Item: Ord>`. // 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); self.sess.gated_spans.gate(sym::associated_type_bounds, span);
} }
let constraint = 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))) Ok(Some(AngleBracketedArg::Constraint(constraint)))
} else { } else {
Ok(Some(AngleBracketedArg::Arg(arg))) 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. /// Parse the term to the right of an associated item equality constraint.
/// That is, parse `<term>` in `Item = <term>`. /// That is, parse `<term>` in `Item = <term>`.
/// Right now, this only admits types in `<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 arg = self.parse_generic_arg(None)?;
let span = ident.span.to(self.prev_token.span); let span = ident.span.to(self.prev_token.span);
match arg { let term = match arg {
Some(GenericArg::Type(ty)) => return Ok(ty), Some(GenericArg::Type(ty)) => ty.into(),
Some(GenericArg::Const(expr)) => { Some(GenericArg::Const(c)) => {
self.struct_span_err(span, "cannot constrain an associated constant to a value") self.sess.gated_spans.gate(sym::associated_const_equality, span);
.span_label(ident.span, "this associated constant...") c.into()
.span_label(expr.value.span, "...cannot be constrained to this value")
.emit();
} }
Some(GenericArg::Lifetime(lt)) => { Some(GenericArg::Lifetime(lt)) => {
self.struct_span_err(span, "associated lifetimes are not supported") self.struct_span_err(span, "associated lifetimes are not supported")
.span_label(lt.ident.span, "the lifetime is given here") .span_label(lt.ident.span, "the lifetime is given here")
.help("if you meant to specify a trait object, write `dyn Trait + 'lifetime`") .help("if you meant to specify a trait object, write `dyn Trait + 'lifetime`")
.emit(); .emit();
self.mk_ty(span, ast::TyKind::Err).into()
} }
None => { None => {
let after_eq = eq.shrink_to_hi(); let after_eq = eq.shrink_to_hi();
@ -542,8 +542,8 @@ impl<'a> Parser<'a> {
}; };
return Err(err); 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: /// 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) ast_visit::walk_path_segment(self, path_span, path_segment)
} }
fn visit_assoc_ty_constraint(&mut self, constraint: &'v ast::AssocTyConstraint) { fn visit_assoc_constraint(&mut self, constraint: &'v ast::AssocConstraint) {
self.record("AssocTyConstraint", Id::None, constraint); self.record("AssocConstraint", Id::None, constraint);
ast_visit::walk_assoc_ty_constraint(self, constraint) ast_visit::walk_assoc_constraint(self, constraint)
} }
fn visit_attribute(&mut self, attr: &'v ast::Attribute) { fn visit_attribute(&mut self, attr: &'v ast::Attribute) {

View file

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

View file

@ -343,6 +343,7 @@ symbols! {
assert_receiver_is_total_eq, assert_receiver_is_total_eq,
assert_uninit_valid, assert_uninit_valid,
assert_zero_valid, assert_zero_valid,
associated_const_equality,
associated_consts, associated_consts,
associated_type_bounds, associated_type_bounds,
associated_type_defaults, 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; let name = cx.tcx.associated_item(projection.item_def_id).ident;
cx.push("p"); cx.push("p");
cx.push_ident(name.as_str()); 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) => { ty::ExistentialPredicate::AutoTrait(def_id) => {
cx = cx.print_def_path(*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::region_constraints::{Constraint, RegionConstraintData};
use crate::infer::InferCtxt; use crate::infer::InferCtxt;
use rustc_middle::ty::fold::TypeFolder; 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}; 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 { 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( fn evaluate_nested_obligations(
@ -663,7 +667,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
// Additionally, we check if we've seen this predicate before, // Additionally, we check if we've seen this predicate before,
// to avoid rendering duplicate bounds to the user. // to avoid rendering duplicate bounds to the user.
if self.is_param_no_infer(p.skip_binder().projection_ty.substs) 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 && is_new_pred
{ {
debug!( debug!(
@ -752,7 +756,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
// when we started out trying to unify // when we started out trying to unify
// some inference variables. See the comment above // some inference variables. See the comment above
// for more infomration // for more infomration
if p.ty().skip_binder().has_infer_types() { if p.term().skip_binder().has_infer_types() {
if !self.evaluate_nested_obligations( if !self.evaluate_nested_obligations(
ty, ty,
v.into_iter(), v.into_iter(),
@ -774,7 +778,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
// However, we should always make progress (either by generating // However, we should always make progress (either by generating
// subobligations or getting an error) when we started off with // subobligations or getting an error) when we started off with
// inference variables // 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) panic!("Unexpected result when selecting {:?} {:?}", ty, obligation)
} }
} }

View file

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

View file

@ -571,7 +571,7 @@ fn object_ty_for_trait<'tcx>(
// `trait MyTrait: for<'s> OtherTrait<&'s T, Output=bool>`. // `trait MyTrait: for<'s> OtherTrait<&'s T, Output=bool>`.
super_trait_ref.map_bound(|super_trait_ref| { super_trait_ref.map_bound(|super_trait_ref| {
ty::ExistentialPredicate::Projection(ty::ExistentialProjection { 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, item_def_id: item.def_id,
substs: super_trait_ref.substs, 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"); debug!(?normalized_ty, ?obligations, "project_and_unify_type result");
let infcx = selcx.infcx(); let infcx = selcx.infcx();
match infcx // FIXME(associated_const_equality): Handle consts here as well as types.
.at(&obligation.cause, obligation.param_env) let obligation_pred_ty = obligation.predicate.term.ty().unwrap();
.eq(normalized_ty, obligation.predicate.ty) match infcx.at(&obligation.cause, obligation.param_env).eq(normalized_ty, obligation_pred_ty) {
{
Ok(InferOk { obligations: inferred_obligations, value: () }) => { Ok(InferOk { obligations: inferred_obligations, value: () }) => {
obligations.extend(inferred_obligations); obligations.extend(inferred_obligations);
Ok(Ok(Some(obligations))) Ok(Ok(Some(obligations)))
@ -1615,7 +1614,7 @@ fn confirm_generator_candidate<'cx, 'tcx>(
substs: trait_ref.substs, substs: trait_ref.substs,
item_def_id: obligation.predicate.item_def_id, 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 { let predicate = ty::ProjectionPredicate {
projection_ty: ty::ProjectionTy { substs, item_def_id: discriminant_def_id }, 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 // 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 { let predicate = ty::ProjectionPredicate {
projection_ty: ty::ProjectionTy { substs, item_def_id: metadata_def_id }, 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) 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, substs: trait_ref.substs,
item_def_id: fn_once_output_def_id, item_def_id: fn_once_output_def_id,
}, },
ty: ret_type, term: ret_type.into(),
}); });
confirm_param_env_candidate(selcx, obligation, predicate, true) confirm_param_env_candidate(selcx, obligation, predicate, true)
@ -1803,7 +1802,9 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
Ok(InferOk { value: _, obligations }) => { Ok(InferOk { value: _, obligations }) => {
nested_obligations.extend(obligations); nested_obligations.extend(obligations);
assoc_ty_own_obligations(selcx, obligation, &mut nested_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) => { Err(e) => {
let msg = format!( 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 let ty::PredicateKind::Projection(predicate) = obligation.predicate.kind().skip_binder() {
// If the projection predicate (Foo::Bar == X) has X as a non-TyVid, // If the projection predicate (Foo::Bar == X) has X as a non-TyVid,
// we need to make it into one. // 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); debug!("relationship: {:?}.output = true", vid);
engine.relationships().entry(vid).or_default().output = true; engine.relationships().entry(vid).or_default().output = true;
} }

View file

@ -116,7 +116,10 @@ pub fn predicate_obligations<'a, 'tcx>(
} }
ty::PredicateKind::Projection(t) => { ty::PredicateKind::Projection(t) => {
wf.compute_projection(t.projection_ty); 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) => { ty::PredicateKind::WellFormed(arg) => {
wf.compute(arg); wf.compute(arg);
@ -219,7 +222,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>(
// projection coming from another associated type. See // projection coming from another associated type. See
// `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs` and // `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs` and
// `traits-assoc-type-in-supertrait-bad.rs`. // `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) = if let Some(&impl_item_id) =
tcx.impl_item_implementor_ids(impl_def_id).get(&projection_ty.item_def_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> for rustc_middle::ty::ProjectionPredicate<'tcx>
{ {
fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::AliasEq<RustInterner<'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 { chalk_ir::AliasEq {
ty: self.ty.lower_into(interner), ty: self.term.ty().unwrap().lower_into(interner),
alias: self.projection_ty.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> { impl<'tcx> LowerInto<'tcx, chalk_ir::Ty<RustInterner<'tcx>>> for Ty<'tcx> {
fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::Ty<RustInterner<'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)); 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) .mk_substs_trait(self_ty, predicate.substs)
.lower_into(interner), .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( 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), trait_bound: trait_ref.lower_into(interner),
associated_ty_id: chalk_ir::AssocTypeId(self.projection_ty.item_def_id), associated_ty_id: chalk_ir::AssocTypeId(self.projection_ty.item_def_id),
parameters: own_substs.iter().map(|arg| arg.lower_into(interner)).collect(), 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 .bindings
.iter() .iter()
.find_map(|b| match (b.ident.name == sym::Output, &b.kind) { .find_map(|b| match (b.ident.name == sym::Output, &b.kind) {
(true, hir::TypeBindingKind::Equality { ty }) => { (true, hir::TypeBindingKind::Equality { term }) => {
sess.source_map().span_to_snippet(ty.span).ok() 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, _ => None,
}) })

View file

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

View file

@ -48,14 +48,19 @@ impl<'tcx> Bounds<'tcx> {
/// where-clauses). Because some of our bounds listings (e.g., /// where-clauses). Because some of our bounds listings (e.g.,
/// regions) don't include the self-type, you must supply the /// regions) don't include the self-type, you must supply the
/// self-type here (the `param_ty` parameter). /// self-type here (the `param_ty` parameter).
pub fn predicates( pub fn predicates<'out, 's>(
&self, &'s self,
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
param_ty: Ty<'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. // If it could be sized, and is, add the `Sized` predicate.
let sized_predicate = self.implicitly_sized.and_then(|span| { 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 { let trait_ref = ty::Binder::dummy(ty::TraitRef {
def_id: sized, def_id: sized,
substs: tcx.mk_substs_trait(param_ty, &[]), substs: tcx.mk_substs_trait(param_ty, &[]),
@ -64,25 +69,22 @@ impl<'tcx> Bounds<'tcx> {
}) })
}); });
sized_predicate let region_preds = self.region_bounds.iter().map(move |&(region_bound, span)| {
.into_iter() let pred = region_bound
.chain(self.region_bounds.iter().map(|&(region_bound, span)| { .map_bound(|region_bound| ty::OutlivesPredicate(param_ty, region_bound))
( .to_predicate(tcx);
region_bound (pred, span)
.map_bound(|region_bound| ty::OutlivesPredicate(param_ty, region_bound)) });
.to_predicate(tcx), let trait_bounds =
span, self.trait_bounds.iter().map(move |&(bound_trait_ref, span, constness)| {
)
}))
.chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| {
let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx); let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx);
(predicate, span) (predicate, span)
})) });
.chain( let projection_bounds = self
self.projection_bounds .projection_bounds
.iter() .iter()
.map(|&(projection, span)| (projection.to_predicate(tcx), span)), .map(move |&(projection, span)| (projection.to_predicate(tcx), span));
)
.collect() 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; 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); let ret_param_ty = self.resolve_vars_if_possible(ret_param_ty);
debug!("deduce_sig_from_projection: ret_param_ty={:?}", 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 // Extract the type from the projection. Note that there can
// be no bound variables in this type because the "self type" // be no bound variables in this type because the "self type"
// does not have any regions in it. // 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); 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 /// 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, item_def_id: trait_ty.def_id,
substs: rebased_substs, substs: rebased_substs,
}, },
ty: impl_ty_value, term: impl_ty_value.into(),
}, },
bound_vars, bound_vars,
) )

View file

@ -789,10 +789,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
item_def_id: projection_ty.item_def_id, 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 obligation = format!("{} = {}", projection_ty, term);
let quiet = format!("{} = {}", quiet_projection_ty, ty); let quiet = format!("{} = {}", quiet_projection_ty, term);
bound_span_label(projection_ty.self_ty(), &obligation, &quiet); bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
Some((obligation, projection_ty.self_ty())) 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 // insert the associated types where they correspond, but for now let's be "lazy" and
// propose this instead of the following valid resugaring: // propose this instead of the following valid resugaring:
// `T: Trait, Trait::Assoc = K` → `T: Trait<Assoc = K>` // `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() { let where_clauses = if where_clauses.is_empty() {
String::new() String::new()

View file

@ -659,7 +659,11 @@ impl<'tcx> ItemCtxt<'tcx> {
.params .params
.iter() .iter()
.filter_map(|param| match param.kind { .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, _ => None,
}) })
.flat_map(|bounds| bounds.iter()) .flat_map(|bounds| bounds.iter())
@ -2527,7 +2531,7 @@ fn predicates_from_bound<'tcx>(
) -> Vec<(ty::Predicate<'tcx>, Span)> { ) -> Vec<(ty::Predicate<'tcx>, Span)> {
let mut bounds = Bounds::default(); let mut bounds = Bounds::default();
astconv.add_bounds(param_ty, [bound].into_iter(), &mut bounds, bound_vars); 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>( 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); let mut bounds = <dyn AstConv<'_>>::compute_bounds(&icx, item_ty, ast_bounds);
// Opaque types are implicitly sized unless a `?Sized` bound is found // Opaque types are implicitly sized unless a `?Sized` bound is found
<dyn AstConv<'_>>::add_implicitly_sized(&icx, &mut bounds, ast_bounds, None, span); <dyn AstConv<'_>>::add_implicitly_sized(&icx, &mut bounds, ast_bounds, None, span);
let bounds = bounds.predicates(tcx, item_ty); tcx.arena.alloc_from_iter(bounds.predicates(tcx, item_ty))
debug!("opaque_type_bounds({}) = {:?}", tcx.def_path_str(opaque_def_id), bounds);
tcx.arena.alloc_slice(&bounds)
}) })
} }

View file

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

View file

@ -199,7 +199,7 @@ fn unconstrained_parent_impl_substs<'tcx>(
for (predicate, _) in impl_generic_predicates.predicates.iter() { for (predicate, _) in impl_generic_predicates.predicates.iter() {
if let ty::PredicateKind::Projection(proj) = predicate.kind().skip_binder() { if let ty::PredicateKind::Projection(proj) = predicate.kind().skip_binder() {
let projection_ty = proj.projection_ty; 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); let unbound_trait_ref = projection_ty.trait_ref(tcx);
if Some(unbound_trait_ref) == impl_trait_ref { 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() { for projection in data.projection_bounds() {
self.add_constraints_from_ty( match projection.skip_binder().term {
current, ty::Term::Ty(ty) => {
projection.skip_binder().ty, self.add_constraints_from_ty(current, ty, self.invariant);
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"]) check_type(arg["const"]["type"])
for binding in args["angle_bracketed"]["bindings"]: for binding in args["angle_bracketed"]["bindings"]:
if "equality" in binding["binding"]: 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"]: elif "constraint" in binding["binding"]:
for bound in binding["binding"]["constraint"]: for bound in binding["binding"]["constraint"]:
check_generic_bound(bound) 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 { if self.is_fn_trait(trait_) && left_name == sym::Output {
ty_to_fn ty_to_fn
.entry(*ty.clone()) .entry(*ty.clone())
.and_modify(|e| *e = (e.0.clone(), Some(rhs.clone()))) .and_modify(|e| {
.or_insert((None, Some(rhs))); *e = (e.0.clone(), Some(rhs.ty().unwrap().clone()))
})
.or_insert((None, Some(rhs.ty().unwrap().clone())));
continue; continue;
} }
@ -570,7 +572,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
GenericArgs::AngleBracketed { ref mut bindings, .. } => { GenericArgs::AngleBracketed { ref mut bindings, .. } => {
bindings.push(TypeBinding { bindings.push(TypeBinding {
name: left_name, name: left_name,
kind: TypeBindingKind::Equality { ty: rhs }, kind: TypeBindingKind::Equality { term: rhs },
}); });
} }
GenericArgs::Parenthesized { .. } => { 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(), bounds: wrp.bounds.iter().filter_map(|x| x.clean(cx)).collect(),
}, },
hir::WherePredicate::EqPredicate(ref wrp) => { hir::WherePredicate::EqPredicate(ref wrp) => WherePredicate::EqPredicate {
WherePredicate::EqPredicate { lhs: wrp.lhs_ty.clean(cx), rhs: wrp.rhs_ty.clean(cx) } 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> { impl<'tcx> Clean<WherePredicate> for ty::ProjectionPredicate<'tcx> {
fn clean(&self, cx: &mut DocContext<'_>) -> WherePredicate { fn clean(&self, cx: &mut DocContext<'_>) -> WherePredicate {
let ty::ProjectionPredicate { projection_ty, ty } = self; let ty::ProjectionPredicate { projection_ty, term } = self;
WherePredicate::EqPredicate { lhs: projection_ty.clean(cx), rhs: ty.clean(cx) } 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(param_idx) = param_idx {
if let Some(b) = impl_trait.get_mut(&param_idx.into()) { if let Some(b) = impl_trait.get_mut(&param_idx.into()) {
let p = p.clean(cx)?; let p: WherePredicate = p.clean(cx)?;
b.extend( b.extend(
p.get_bounds() p.get_bounds()
@ -624,11 +646,16 @@ fn clean_ty_generics(
); );
let proj = projection 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)) = if let Some(((_, trait_did, name), rhs)) =
proj.as_ref().and_then(|(lhs, rhs)| Some((lhs.projection()?, 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; return None;
@ -647,7 +674,7 @@ fn clean_ty_generics(
if let Some(proj) = impl_trait_proj.remove(&idx) { if let Some(proj) = impl_trait_proj.remove(&idx) {
for (trait_did, name, rhs) in proj { for (trait_did, name, rhs) in proj {
let rhs = rhs.clean(cx); 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 { } else {
@ -1495,7 +1522,9 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
for pb in obj.projection_bounds() { for pb in obj.projection_bounds() {
bindings.push(TypeBinding { bindings.push(TypeBinding {
name: cx.tcx.associated_item(pb.item_def_id()).ident.name, 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 .ident
.name, .name,
kind: TypeBindingKind::Equality { kind: TypeBindingKind::Equality {
ty: proj.ty.clean(cx), term: proj.term.clean(cx),
}, },
}) })
} else { } else {
@ -2114,10 +2143,10 @@ impl Clean<TypeBinding> for hir::TypeBinding<'_> {
impl Clean<TypeBindingKind> for hir::TypeBindingKind<'_> { impl Clean<TypeBindingKind> for hir::TypeBindingKind<'_> {
fn clean(&self, cx: &mut DocContext<'_>) -> TypeBindingKind { fn clean(&self, cx: &mut DocContext<'_>) -> TypeBindingKind {
match *self { match *self {
hir::TypeBindingKind::Equality { ref ty } => { hir::TypeBindingKind::Equality { ref term } => {
TypeBindingKind::Equality { ty: ty.clean(cx) } 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(), 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>, bounds: &mut Vec<clean::GenericBound>,
trait_did: DefId, trait_did: DefId,
name: Symbol, name: Symbol,
rhs: &clean::Type, rhs: &clean::Term,
) -> bool { ) -> bool {
!bounds.iter_mut().any(|b| { !bounds.iter_mut().any(|b| {
let trait_ref = match *b { let trait_ref = match *b {
@ -110,14 +110,14 @@ crate fn merge_bounds(
PP::AngleBracketed { ref mut bindings, .. } => { PP::AngleBracketed { ref mut bindings, .. } => {
bindings.push(clean::TypeBinding { bindings.push(clean::TypeBinding {
name, name,
kind: clean::TypeBindingKind::Equality { ty: rhs.clone() }, kind: clean::TypeBindingKind::Equality { term: rhs.clone() },
}); });
} }
PP::Parenthesized { ref mut output, .. } => match output { 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 => { None => {
if *rhs != clean::Type::Tuple(Vec::new()) { if *rhs != clean::Term::Type(clean::Type::Tuple(Vec::new())) {
*output = Some(Box::new(rhs.clone())); *output = Some(Box::new(rhs.ty().unwrap().clone()));
} }
} }
}, },

View file

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

View file

@ -1442,11 +1442,11 @@ impl clean::TypeBinding {
display_fn(move |f| { display_fn(move |f| {
f.write_str(self.name.as_str())?; f.write_str(self.name.as_str())?;
match self.kind { match self.kind {
clean::TypeBindingKind::Equality { ref ty } => { clean::TypeBindingKind::Equality { ref term } => {
if f.alternate() { if f.alternate() {
write!(f, " = {:#}", ty.print(cx))?; write!(f, " = {:#}", term.print(cx))?;
} else { } else {
write!(f, " = {}", ty.print(cx))?; write!(f, " = {}", term.print(cx))?;
} }
} }
clean::TypeBindingKind::Constraint { ref bounds } => { 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 { crate fn display_fn(f: impl FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl fmt::Display {
struct WithFormatter<F>(Cell<Option<F>>); 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 { fn from_tcx(kind: clean::TypeBindingKind, tcx: TyCtxt<'_>) -> Self {
use clean::TypeBindingKind::*; use clean::TypeBindingKind::*;
match kind { match kind {
Equality { ty } => TypeBindingKind::Equality(ty.into_tcx(tcx)), Equality { term } => TypeBindingKind::Equality(term.into_tcx(tcx)),
Constraint { bounds } => { Constraint { bounds } => {
TypeBindingKind::Constraint(bounds.into_iter().map(|a| a.into_tcx(tcx)).collect()) 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 { impl FromWithTcx<clean::BareFunctionDecl> for FunctionPointer {
fn from_tcx(bare_decl: clean::BareFunctionDecl, tcx: TyCtxt<'_>) -> Self { fn from_tcx(bare_decl: clean::BareFunctionDecl, tcx: TyCtxt<'_>) -> Self {
let clean::BareFunctionDecl { unsafety, generic_params, decl, abi } = bare_decl; 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)] #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
pub enum TypeBindingKind { pub enum TypeBindingKind {
Equality(Type), Equality(Term),
Constraint(Vec<GenericBound>), Constraint(Vec<GenericBound>),
} }
@ -335,7 +335,7 @@ pub enum GenericParamDefKind {
pub enum WherePredicate { pub enum WherePredicate {
BoundPredicate { ty: Type, bounds: Vec<GenericBound> }, BoundPredicate { ty: Type, bounds: Vec<GenericBound> },
RegionPredicate { lifetime: String, 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)] #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
@ -359,6 +359,13 @@ pub enum TraitBoundModifier {
MaybeConst, 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)] #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
#[serde(tag = "kind", content = "inner")] #[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; const T: usize = 42;
impl Foo<N = 3> for Bar { 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 type bindings are not allowed here
//~| ERROR associated const equality is incomplete
fn do_x(&self) -> [u8; 3] { fn do_x(&self) -> [u8; 3] {
[0u8; 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 --> $DIR/issue-89013-no-kw.rs:9:10
| |
LL | impl Foo<N = 3> for Bar { LL | impl Foo<N = 3> for Bar {
| -^^^- | ^^^^^
| | | |
| | ...cannot be constrained to this value = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
| this associated constant... = 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 error[E0229]: associated type bindings are not allowed here
--> $DIR/issue-89013-no-kw.rs:9:10 --> $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 { LL | impl Foo<N = 3> for Bar {
| ^^^^^ associated type not allowed here | ^^^^^ 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 { impl Foo<N = const 3> for Bar {
//~^ ERROR expected lifetime, type, or constant, found keyword `const` //~^ 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 type bindings are not allowed here
//~| ERROR associated const equality is incomplete
fn do_x(&self) -> [u8; 3] { fn do_x(&self) -> [u8; 3] {
[0u8; 3] [0u8; 3]
} }

View file

@ -10,14 +10,30 @@ LL - impl Foo<N = const 3> for Bar {
LL + impl Foo<N = 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 --> $DIR/issue-89013.rs:9:10
| |
LL | impl Foo<N = const 3> for Bar { LL | impl Foo<N = const 3> for Bar {
| -^^^^^^^^^- | ^^^^^^^^^^^
| | | |
| | ...cannot be constrained to this value = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
| this associated constant... = 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 error[E0229]: associated type bindings are not allowed here
--> $DIR/issue-89013.rs:9:10 --> $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 { LL | impl Foo<N = const 3> for Bar {
| ^^^^^^^^^^^ associated type not allowed here | ^^^^^^^^^^^ 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)] #[cfg(FALSE)]
fn syntax() { fn syntax() {
bar::<Item = 42>(); //~ ERROR cannot constrain an associated constant to a value bar::<Item = 42>();
bar::<Item = { 42 }>(); //~ ERROR cannot constrain an associated constant to a value //~^ ERROR associated const equality is incomplete
bar::<Item = { 42 }>();
//~^ ERROR associated const equality is incomplete
} }
fn main() {} 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 --> $DIR/recover-assoc-const-constraint.rs:3:11
| |
LL | bar::<Item = 42>(); LL | bar::<Item = 42>();
| ----^^^-- | ^^^^^^^^^
| | | |
| | ...cannot be constrained to this value = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
| this associated constant... = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
error: cannot constrain an associated constant to a value error[E0658]: associated const equality is incomplete
--> $DIR/recover-assoc-const-constraint.rs:4:11 --> $DIR/recover-assoc-const-constraint.rs:5:11
| |
LL | bar::<Item = { 42 }>(); LL | bar::<Item = { 42 }>();
| ----^^^------ | ^^^^^^^^^^^^^
| | | |
| | ...cannot be constrained to this value = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
| this associated constant... = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
error: aborting due to 2 previous errors 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 --> $DIR/repeated_projection_type.rs:19:1
| |
LL | / impl<I, V: Id<This = (I,)>> X for V { 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_errors::Applicability;
use rustc_hir::intravisit::FnKind; use rustc_hir::intravisit::FnKind;
use rustc_hir::{ 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, IsAsync, ItemKind, LifetimeName, TraitRef, Ty, TyKind, TypeBindingKind,
}; };
use rustc_lint::{LateContext, LateLintPass}; 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; if args.bindings.len() == 1;
let binding = &args.bindings[0]; let binding = &args.bindings[0];
if binding.ident.name == sym::Output; 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 { then {
return Some(output) return Some(output)
} }

View file

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

View file

@ -243,9 +243,10 @@ fn check_other_call_arg<'tcx>(
if if trait_predicate.def_id() == deref_trait_id { if if trait_predicate.def_id() == deref_trait_id {
if let [projection_predicate] = projection_predicates[..] { if let [projection_predicate] = projection_predicates[..] {
let normalized_ty = 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, &[]) 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 { } else {
false 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 trait_pred.self_ty() == inp;
if let Some(return_ty_pred) = get_projection_pred(cx, generics, *trait_pred); if let Some(return_ty_pred) = get_projection_pred(cx, generics, *trait_pred);
then { 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())); 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())); 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 { fn eq_term(l: &Term, r: &Term) -> bool {
use AssocTyConstraintKind::*; 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) eq_id(l.ident, r.ident)
&& match (&l.kind, &r.kind) { && 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), (Bound { bounds: l }, Bound { bounds: r }) => over(l, r, eq_generic_bound),
_ => false, _ => false,
} }

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

View file

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