mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-16 17:03:35 +00:00
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:
commit
7bc7be860f
54
Cargo.lock
54
Cargo.lock
@ -335,7 +335,7 @@ dependencies = [
|
||||
"cargo-test-macro",
|
||||
"cargo-test-support",
|
||||
"cargo-util",
|
||||
"clap 3.0.6",
|
||||
"clap",
|
||||
"crates-io",
|
||||
"crossbeam-utils",
|
||||
"curl",
|
||||
@ -615,28 +615,13 @@ dependencies = [
|
||||
"ansi_term 0.12.1",
|
||||
"atty",
|
||||
"bitflags",
|
||||
"strsim 0.8.0",
|
||||
"textwrap 0.11.0",
|
||||
"strsim",
|
||||
"textwrap",
|
||||
"unicode-width",
|
||||
"vec_map",
|
||||
"yaml-rust 0.3.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "3.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1957aa4a5fb388f0a0a73ce7556c5b42025b874e5cdc2c670775e346e97adec0"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"bitflags",
|
||||
"indexmap",
|
||||
"os_str_bytes",
|
||||
"strsim 0.10.0",
|
||||
"termcolor",
|
||||
"textwrap 0.14.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clippy"
|
||||
version = "0.1.60"
|
||||
@ -669,7 +654,7 @@ version = "0.0.1"
|
||||
dependencies = [
|
||||
"bytecount",
|
||||
"cargo_metadata 0.14.0",
|
||||
"clap 2.34.0",
|
||||
"clap",
|
||||
"indoc",
|
||||
"itertools 0.10.1",
|
||||
"opener",
|
||||
@ -1751,7 +1736,7 @@ name = "installer"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 2.34.0",
|
||||
"clap",
|
||||
"flate2",
|
||||
"lazy_static",
|
||||
"num_cpus",
|
||||
@ -2190,7 +2175,7 @@ dependencies = [
|
||||
"ammonia",
|
||||
"anyhow",
|
||||
"chrono",
|
||||
"clap 2.34.0",
|
||||
"clap",
|
||||
"elasticlunr-rs",
|
||||
"env_logger 0.7.1",
|
||||
"handlebars",
|
||||
@ -2521,15 +2506,6 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
version = "6.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "output_vt100"
|
||||
version = "0.1.2"
|
||||
@ -2934,7 +2910,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0b4b5faaf07040474e8af74a9e19ff167d5d204df5db5c5c765edecfb900358"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"clap 2.34.0",
|
||||
"clap",
|
||||
"derive_more",
|
||||
"env_logger 0.7.1",
|
||||
"humantime 2.0.1",
|
||||
@ -3282,7 +3258,7 @@ dependencies = [
|
||||
name = "rustbook"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap 2.34.0",
|
||||
"clap",
|
||||
"env_logger 0.7.1",
|
||||
"mdbook",
|
||||
]
|
||||
@ -4898,19 +4874,13 @@ version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "structopt"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40b9788f4202aa75c240ecc9c15c65185e6a39ccdeb0fd5d008b98825464c87c"
|
||||
dependencies = [
|
||||
"clap 2.34.0",
|
||||
"clap",
|
||||
"lazy_static",
|
||||
"structopt-derive",
|
||||
]
|
||||
@ -5081,12 +5051,6 @@ dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.14.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.30"
|
||||
|
@ -224,7 +224,7 @@ pub enum AngleBracketedArg {
|
||||
/// Argument for a generic parameter.
|
||||
Arg(GenericArg),
|
||||
/// Constraint for an associated item.
|
||||
Constraint(AssocTyConstraint),
|
||||
Constraint(AssocConstraint),
|
||||
}
|
||||
|
||||
impl AngleBracketedArg {
|
||||
@ -1843,19 +1843,38 @@ impl UintTy {
|
||||
/// A constraint on an associated type (e.g., `A = Bar` in `Foo<A = Bar>` or
|
||||
/// `A: TraitA + TraitB` in `Foo<A: TraitA + TraitB>`).
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct AssocTyConstraint {
|
||||
pub struct AssocConstraint {
|
||||
pub id: NodeId,
|
||||
pub ident: Ident,
|
||||
pub gen_args: Option<GenericArgs>,
|
||||
pub kind: AssocTyConstraintKind,
|
||||
pub kind: AssocConstraintKind,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
/// The kinds of an `AssocTyConstraint`.
|
||||
/// The kinds of an `AssocConstraint`.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum AssocTyConstraintKind {
|
||||
/// E.g., `A = Bar` in `Foo<A = Bar>`.
|
||||
Equality { ty: P<Ty> },
|
||||
pub enum Term {
|
||||
Ty(P<Ty>),
|
||||
Const(AnonConst),
|
||||
}
|
||||
|
||||
impl From<P<Ty>> for Term {
|
||||
fn from(v: P<Ty>) -> Self {
|
||||
Term::Ty(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AnonConst> for Term {
|
||||
fn from(v: AnonConst) -> Self {
|
||||
Term::Const(v)
|
||||
}
|
||||
}
|
||||
|
||||
/// The kinds of an `AssocConstraint`.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum AssocConstraintKind {
|
||||
/// E.g., `A = Bar`, `A = 3` in `Foo<A = Bar>` where A is an associated type.
|
||||
Equality { term: Term },
|
||||
/// E.g. `A: TraitA + TraitB` in `Foo<A: TraitA + TraitB>`.
|
||||
Bound { bounds: GenericBounds },
|
||||
}
|
||||
|
@ -165,8 +165,8 @@ pub trait MutVisitor: Sized {
|
||||
noop_visit_lifetime(l, self);
|
||||
}
|
||||
|
||||
fn visit_ty_constraint(&mut self, t: &mut AssocTyConstraint) {
|
||||
noop_visit_ty_constraint(t, self);
|
||||
fn visit_constraint(&mut self, t: &mut AssocConstraint) {
|
||||
noop_visit_constraint(t, self);
|
||||
}
|
||||
|
||||
fn visit_foreign_mod(&mut self, nm: &mut ForeignMod) {
|
||||
@ -430,8 +430,8 @@ pub fn noop_flat_map_arm<T: MutVisitor>(mut arm: Arm, vis: &mut T) -> SmallVec<[
|
||||
smallvec![arm]
|
||||
}
|
||||
|
||||
pub fn noop_visit_ty_constraint<T: MutVisitor>(
|
||||
AssocTyConstraint { id, ident, gen_args, kind, span }: &mut AssocTyConstraint,
|
||||
pub fn noop_visit_constraint<T: MutVisitor>(
|
||||
AssocConstraint { id, ident, gen_args, kind, span }: &mut AssocConstraint,
|
||||
vis: &mut T,
|
||||
) {
|
||||
vis.visit_id(id);
|
||||
@ -440,12 +440,11 @@ pub fn noop_visit_ty_constraint<T: MutVisitor>(
|
||||
vis.visit_generic_args(gen_args);
|
||||
}
|
||||
match kind {
|
||||
AssocTyConstraintKind::Equality { ref mut ty } => {
|
||||
vis.visit_ty(ty);
|
||||
}
|
||||
AssocTyConstraintKind::Bound { ref mut bounds } => {
|
||||
visit_bounds(bounds, vis);
|
||||
}
|
||||
AssocConstraintKind::Equality { ref mut term } => match term {
|
||||
Term::Ty(ty) => vis.visit_ty(ty),
|
||||
Term::Const(c) => vis.visit_anon_const(c),
|
||||
},
|
||||
AssocConstraintKind::Bound { ref mut bounds } => visit_bounds(bounds, vis),
|
||||
}
|
||||
vis.visit_span(span);
|
||||
}
|
||||
@ -555,7 +554,7 @@ pub fn noop_visit_angle_bracketed_parameter_data<T: MutVisitor>(
|
||||
let AngleBracketedArgs { args, span } = data;
|
||||
visit_vec(args, |arg| match arg {
|
||||
AngleBracketedArg::Arg(arg) => vis.visit_generic_arg(arg),
|
||||
AngleBracketedArg::Constraint(constraint) => vis.visit_ty_constraint(constraint),
|
||||
AngleBracketedArg::Constraint(constraint) => vis.visit_constraint(constraint),
|
||||
});
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
@ -190,8 +190,8 @@ pub trait Visitor<'ast>: Sized {
|
||||
fn visit_generic_arg(&mut self, generic_arg: &'ast GenericArg) {
|
||||
walk_generic_arg(self, generic_arg)
|
||||
}
|
||||
fn visit_assoc_ty_constraint(&mut self, constraint: &'ast AssocTyConstraint) {
|
||||
walk_assoc_ty_constraint(self, constraint)
|
||||
fn visit_assoc_constraint(&mut self, constraint: &'ast AssocConstraint) {
|
||||
walk_assoc_constraint(self, constraint)
|
||||
}
|
||||
fn visit_attribute(&mut self, attr: &'ast Attribute) {
|
||||
walk_attribute(self, attr)
|
||||
@ -464,7 +464,7 @@ where
|
||||
for arg in &data.args {
|
||||
match arg {
|
||||
AngleBracketedArg::Arg(a) => visitor.visit_generic_arg(a),
|
||||
AngleBracketedArg::Constraint(c) => visitor.visit_assoc_ty_constraint(c),
|
||||
AngleBracketedArg::Constraint(c) => visitor.visit_assoc_constraint(c),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -486,19 +486,17 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_assoc_ty_constraint<'a, V: Visitor<'a>>(
|
||||
visitor: &mut V,
|
||||
constraint: &'a AssocTyConstraint,
|
||||
) {
|
||||
pub fn walk_assoc_constraint<'a, V: Visitor<'a>>(visitor: &mut V, constraint: &'a AssocConstraint) {
|
||||
visitor.visit_ident(constraint.ident);
|
||||
if let Some(ref gen_args) = constraint.gen_args {
|
||||
visitor.visit_generic_args(gen_args.span(), gen_args);
|
||||
}
|
||||
match constraint.kind {
|
||||
AssocTyConstraintKind::Equality { ref ty } => {
|
||||
visitor.visit_ty(ty);
|
||||
}
|
||||
AssocTyConstraintKind::Bound { ref bounds } => {
|
||||
AssocConstraintKind::Equality { ref term } => match term {
|
||||
Term::Ty(ty) => visitor.visit_ty(ty),
|
||||
Term::Const(c) => visitor.visit_anon_const(c),
|
||||
},
|
||||
AssocConstraintKind::Bound { ref bounds } => {
|
||||
walk_list!(visitor, visit_param_bound, bounds);
|
||||
}
|
||||
}
|
||||
|
@ -960,7 +960,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
/// returns a `hir::TypeBinding` representing `Item`.
|
||||
fn lower_assoc_ty_constraint(
|
||||
&mut self,
|
||||
constraint: &AssocTyConstraint,
|
||||
constraint: &AssocConstraint,
|
||||
mut itctx: ImplTraitContext<'_, 'hir>,
|
||||
) -> hir::TypeBinding<'hir> {
|
||||
debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx);
|
||||
@ -997,10 +997,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
};
|
||||
|
||||
let kind = match constraint.kind {
|
||||
AssocTyConstraintKind::Equality { ref ty } => {
|
||||
hir::TypeBindingKind::Equality { ty: self.lower_ty(ty, itctx) }
|
||||
AssocConstraintKind::Equality { ref term } => {
|
||||
let term = match term {
|
||||
Term::Ty(ref ty) => self.lower_ty(ty, itctx).into(),
|
||||
Term::Const(ref c) => self.lower_anon_const(c).into(),
|
||||
};
|
||||
hir::TypeBindingKind::Equality { term }
|
||||
}
|
||||
AssocTyConstraintKind::Bound { ref bounds } => {
|
||||
AssocConstraintKind::Bound { ref bounds } => {
|
||||
let mut capturable_lifetimes;
|
||||
let mut parent_def_id = self.current_hir_id_owner;
|
||||
// Piggy-back on the `impl Trait` context to figure out the correct behavior.
|
||||
@ -1078,7 +1082,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
itctx,
|
||||
);
|
||||
|
||||
hir::TypeBindingKind::Equality { ty }
|
||||
hir::TypeBindingKind::Equality { term: ty.into() }
|
||||
})
|
||||
} else {
|
||||
// Desugar `AssocTy: Bounds` into a type binding where the
|
||||
|
@ -420,7 +420,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
ty: &'hir hir::Ty<'hir>,
|
||||
) -> hir::TypeBinding<'hir> {
|
||||
let ident = Ident::with_dummy_span(hir::FN_OUTPUT_NAME);
|
||||
let kind = hir::TypeBindingKind::Equality { ty };
|
||||
let kind = hir::TypeBindingKind::Equality { term: ty.into() };
|
||||
let args = arena_vec![self;];
|
||||
let bindings = arena_vec![self;];
|
||||
let gen_args = self.arena.alloc(hir::GenericArgs {
|
||||
|
@ -138,10 +138,10 @@ impl<'a> AstValidator<'a> {
|
||||
self.outer_impl_trait = old;
|
||||
}
|
||||
|
||||
fn visit_assoc_ty_constraint_from_generic_args(&mut self, constraint: &'a AssocTyConstraint) {
|
||||
fn visit_assoc_constraint_from_generic_args(&mut self, constraint: &'a AssocConstraint) {
|
||||
match constraint.kind {
|
||||
AssocTyConstraintKind::Equality { .. } => {}
|
||||
AssocTyConstraintKind::Bound { .. } => {
|
||||
AssocConstraintKind::Equality { .. } => {}
|
||||
AssocConstraintKind::Bound { .. } => {
|
||||
if self.is_assoc_ty_bound_banned {
|
||||
self.err_handler().span_err(
|
||||
constraint.span,
|
||||
@ -150,7 +150,7 @@ impl<'a> AstValidator<'a> {
|
||||
}
|
||||
}
|
||||
}
|
||||
self.visit_assoc_ty_constraint(constraint);
|
||||
self.visit_assoc_constraint(constraint);
|
||||
}
|
||||
|
||||
// Mirrors `visit::walk_ty`, but tracks relevant state.
|
||||
@ -1277,7 +1277,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
// are allowed to contain nested `impl Trait`.
|
||||
AngleBracketedArg::Constraint(constraint) => {
|
||||
self.with_impl_trait(None, |this| {
|
||||
this.visit_assoc_ty_constraint_from_generic_args(constraint);
|
||||
this.visit_assoc_constraint_from_generic_args(constraint);
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1586,12 +1586,12 @@ fn deny_equality_constraints(
|
||||
let len = assoc_path.segments.len() - 1;
|
||||
let gen_args = args.as_ref().map(|p| (**p).clone());
|
||||
// Build `<Bar = RhsTy>`.
|
||||
let arg = AngleBracketedArg::Constraint(AssocTyConstraint {
|
||||
let arg = AngleBracketedArg::Constraint(AssocConstraint {
|
||||
id: rustc_ast::node_id::DUMMY_NODE_ID,
|
||||
ident: *ident,
|
||||
gen_args,
|
||||
kind: AssocTyConstraintKind::Equality {
|
||||
ty: predicate.rhs_ty.clone(),
|
||||
kind: AssocConstraintKind::Equality {
|
||||
term: predicate.rhs_ty.clone().into(),
|
||||
},
|
||||
span: ident.span,
|
||||
});
|
||||
|
@ -1,6 +1,6 @@
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
|
||||
use rustc_ast::{AssocTyConstraint, AssocTyConstraintKind, NodeId};
|
||||
use rustc_ast::{AssocConstraint, AssocConstraintKind, NodeId};
|
||||
use rustc_ast::{PatKind, RangeEnd, VariantData};
|
||||
use rustc_errors::struct_span_err;
|
||||
use rustc_feature::{AttributeGate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
|
||||
@ -622,8 +622,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
visit::walk_fn(self, fn_kind, span)
|
||||
}
|
||||
|
||||
fn visit_assoc_ty_constraint(&mut self, constraint: &'a AssocTyConstraint) {
|
||||
if let AssocTyConstraintKind::Bound { .. } = constraint.kind {
|
||||
fn visit_assoc_constraint(&mut self, constraint: &'a AssocConstraint) {
|
||||
if let AssocConstraintKind::Bound { .. } = constraint.kind {
|
||||
gate_feature_post!(
|
||||
&self,
|
||||
associated_type_bounds,
|
||||
@ -631,7 +631,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
"associated type bounds are unstable"
|
||||
)
|
||||
}
|
||||
visit::walk_assoc_ty_constraint(self, constraint)
|
||||
visit::walk_assoc_constraint(self, constraint)
|
||||
}
|
||||
|
||||
fn visit_assoc_item(&mut self, i: &'a ast::AssocItem, ctxt: AssocCtxt) {
|
||||
@ -724,6 +724,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
|
||||
gate_all!(half_open_range_patterns, "half-open range patterns are unstable");
|
||||
gate_all!(inline_const, "inline-const is experimental");
|
||||
gate_all!(inline_const_pat, "inline-const in pattern position is experimental");
|
||||
gate_all!(associated_const_equality, "associated const equality is incomplete");
|
||||
|
||||
// All uses of `gate_all!` below this point were added in #65742,
|
||||
// and subsequently disabled (with the non-early gating readded).
|
||||
|
@ -126,9 +126,9 @@ impl<'ast> Visitor<'ast> for NodeCounter {
|
||||
self.count += 1;
|
||||
walk_generic_args(self, path_span, generic_args)
|
||||
}
|
||||
fn visit_assoc_ty_constraint(&mut self, constraint: &AssocTyConstraint) {
|
||||
fn visit_assoc_constraint(&mut self, constraint: &AssocConstraint) {
|
||||
self.count += 1;
|
||||
walk_assoc_ty_constraint(self, constraint)
|
||||
walk_assoc_constraint(self, constraint)
|
||||
}
|
||||
fn visit_attribute(&mut self, _attr: &Attribute) {
|
||||
self.count += 1;
|
||||
|
@ -1,7 +1,6 @@
|
||||
use crate::pp::Breaks::{Consistent, Inconsistent};
|
||||
use crate::pp::{self, Breaks};
|
||||
|
||||
use rustc_ast::attr;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{self, BinOpToken, CommentKind, DelimToken, Nonterminal, Token, TokenKind};
|
||||
use rustc_ast::tokenstream::{TokenStream, TokenTree};
|
||||
@ -9,6 +8,7 @@ use rustc_ast::util::classify;
|
||||
use rustc_ast::util::comments::{gather_comments, Comment, CommentStyle};
|
||||
use rustc_ast::util::parser::{self, AssocOp, Fixity};
|
||||
use rustc_ast::{self as ast, BlockCheckMode, PatKind, RangeEnd, RangeSyntax};
|
||||
use rustc_ast::{attr, Term};
|
||||
use rustc_ast::{GenericArg, MacArgs, ModKind};
|
||||
use rustc_ast::{GenericBound, SelfKind, TraitBoundModifier};
|
||||
use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass};
|
||||
@ -952,18 +952,19 @@ impl<'a> State<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocTyConstraint) {
|
||||
pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocConstraint) {
|
||||
self.print_ident(constraint.ident);
|
||||
constraint.gen_args.as_ref().map(|args| self.print_generic_args(args, false));
|
||||
self.space();
|
||||
match &constraint.kind {
|
||||
ast::AssocTyConstraintKind::Equality { ty } => {
|
||||
ast::AssocConstraintKind::Equality { term } => {
|
||||
self.word_space("=");
|
||||
self.print_type(ty);
|
||||
}
|
||||
ast::AssocTyConstraintKind::Bound { bounds } => {
|
||||
self.print_type_bounds(":", &*bounds);
|
||||
match term {
|
||||
Term::Ty(ty) => self.print_type(ty),
|
||||
Term::Const(c) => self.print_expr_anon_const(c),
|
||||
}
|
||||
}
|
||||
ast::AssocConstraintKind::Bound { bounds } => self.print_type_bounds(":", &*bounds),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -779,7 +779,10 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
[
|
||||
hir::TypeBinding {
|
||||
ident: Ident { name: sym::Output, .. },
|
||||
kind: hir::TypeBindingKind::Equality { ty },
|
||||
kind:
|
||||
hir::TypeBindingKind::Equality {
|
||||
term: hir::Term::Ty(ty),
|
||||
},
|
||||
..
|
||||
},
|
||||
],
|
||||
|
@ -203,8 +203,9 @@ fn push_debuginfo_type_name<'tcx>(
|
||||
let projection_bounds: SmallVec<[_; 4]> = trait_data
|
||||
.projection_bounds()
|
||||
.map(|bound| {
|
||||
let ExistentialProjection { item_def_id, ty, .. } = bound.skip_binder();
|
||||
(item_def_id, ty)
|
||||
let ExistentialProjection { item_def_id, term, .. } = bound.skip_binder();
|
||||
// FIXME(associated_const_equality): allow for consts here
|
||||
(item_def_id, term.ty().unwrap())
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
@ -288,6 +288,8 @@ declare_features! (
|
||||
(active, asm_sym, "1.58.0", Some(72016), None),
|
||||
/// Allows the `may_unwind` option in inline assembly.
|
||||
(active, asm_unwind, "1.58.0", Some(72016), None),
|
||||
/// Allows users to enforce equality of associated constants `TraitImpl<AssocConst=3>`.
|
||||
(active, associated_const_equality, "1.58.0", Some(92827), None),
|
||||
/// Allows the user of associated type bounds.
|
||||
(active, associated_type_bounds, "1.34.0", Some(52662), None),
|
||||
/// Allows associated type defaults.
|
||||
|
@ -377,7 +377,7 @@ impl GenericArgs<'_> {
|
||||
GenericArg::Type(ty) => matches!(ty.kind, TyKind::Err),
|
||||
_ => false,
|
||||
}) || self.bindings.iter().any(|arg| match arg.kind {
|
||||
TypeBindingKind::Equality { ty } => matches!(ty.kind, TyKind::Err),
|
||||
TypeBindingKind::Equality { term: Term::Ty(ty) } => matches!(ty.kind, TyKind::Err),
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
@ -2129,19 +2129,37 @@ pub struct TypeBinding<'hir> {
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Debug, HashStable_Generic)]
|
||||
pub enum Term<'hir> {
|
||||
Ty(&'hir Ty<'hir>),
|
||||
Const(AnonConst),
|
||||
}
|
||||
|
||||
impl<'hir> From<&'hir Ty<'hir>> for Term<'hir> {
|
||||
fn from(ty: &'hir Ty<'hir>) -> Self {
|
||||
Term::Ty(ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'hir> From<AnonConst> for Term<'hir> {
|
||||
fn from(c: AnonConst) -> Self {
|
||||
Term::Const(c)
|
||||
}
|
||||
}
|
||||
|
||||
// Represents the two kinds of type bindings.
|
||||
#[derive(Debug, HashStable_Generic)]
|
||||
pub enum TypeBindingKind<'hir> {
|
||||
/// E.g., `Foo<Bar: Send>`.
|
||||
Constraint { bounds: &'hir [GenericBound<'hir>] },
|
||||
/// E.g., `Foo<Bar = ()>`.
|
||||
Equality { ty: &'hir Ty<'hir> },
|
||||
/// E.g., `Foo<Bar = ()>`, `Foo<Bar = ()>`
|
||||
Equality { term: Term<'hir> },
|
||||
}
|
||||
|
||||
impl TypeBinding<'_> {
|
||||
pub fn ty(&self) -> &Ty<'_> {
|
||||
match self.kind {
|
||||
TypeBindingKind::Equality { ref ty } => ty,
|
||||
TypeBindingKind::Equality { term: Term::Ty(ref ty) } => ty,
|
||||
_ => panic!("expected equality type binding for parenthesized generic args"),
|
||||
}
|
||||
}
|
||||
|
@ -801,12 +801,11 @@ pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(
|
||||
visitor.visit_ident(type_binding.ident);
|
||||
visitor.visit_generic_args(type_binding.span, type_binding.gen_args);
|
||||
match type_binding.kind {
|
||||
TypeBindingKind::Equality { ref ty } => {
|
||||
visitor.visit_ty(ty);
|
||||
}
|
||||
TypeBindingKind::Constraint { bounds } => {
|
||||
walk_list!(visitor, visit_param_bound, bounds);
|
||||
}
|
||||
TypeBindingKind::Equality { ref term } => match term {
|
||||
Term::Ty(ref ty) => visitor.visit_ty(ty),
|
||||
Term::Const(ref c) => visitor.visit_anon_const(c),
|
||||
},
|
||||
TypeBindingKind::Constraint { bounds } => walk_list!(visitor, visit_param_bound, bounds),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ use rustc_ast_pretty::pp::Breaks::{Consistent, Inconsistent};
|
||||
use rustc_ast_pretty::pp::{self, Breaks};
|
||||
use rustc_ast_pretty::pprust::{Comments, PrintState};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::{GenericArg, GenericParam, GenericParamKind, Node};
|
||||
use rustc_hir::{GenericArg, GenericParam, GenericParamKind, Node, Term};
|
||||
use rustc_hir::{GenericBound, PatKind, RangeEnd, TraitBoundModifier};
|
||||
use rustc_span::source_map::{SourceMap, Spanned};
|
||||
use rustc_span::symbol::{kw, Ident, IdentPrinter, Symbol};
|
||||
@ -1752,9 +1752,12 @@ impl<'a> State<'a> {
|
||||
self.print_generic_args(binding.gen_args, false, false);
|
||||
self.space();
|
||||
match generic_args.bindings[0].kind {
|
||||
hir::TypeBindingKind::Equality { ref ty } => {
|
||||
hir::TypeBindingKind::Equality { ref term } => {
|
||||
self.word_space("=");
|
||||
self.print_type(ty);
|
||||
match term {
|
||||
Term::Ty(ref ty) => self.print_type(ty),
|
||||
Term::Const(ref c) => self.print_anon_const(c),
|
||||
}
|
||||
}
|
||||
hir::TypeBindingKind::Constraint { bounds } => {
|
||||
self.print_bounds(":", bounds);
|
||||
|
@ -1780,7 +1780,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
{
|
||||
if projection_predicate.projection_ty.item_def_id == item_def_id {
|
||||
// We don't account for multiple `Future::Output = Ty` contraints.
|
||||
return Some(projection_predicate.ty);
|
||||
return projection_predicate.term.ty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -122,8 +122,9 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
||||
{
|
||||
for type_binding in generic_args.bindings.iter() {
|
||||
if type_binding.ident.name == rustc_span::sym::Output {
|
||||
if let hir::TypeBindingKind::Equality { ty } =
|
||||
type_binding.kind
|
||||
if let hir::TypeBindingKind::Equality {
|
||||
term: hir::Term::Ty(ty),
|
||||
} = type_binding.kind
|
||||
{
|
||||
return Some(ty);
|
||||
}
|
||||
|
@ -584,8 +584,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
|
||||
debug!(?predicate);
|
||||
|
||||
if let ty::PredicateKind::Projection(projection) = predicate.kind().skip_binder() {
|
||||
if projection.ty.references_error() {
|
||||
// No point on adding these obligations since there's a type error involved.
|
||||
if projection.term.references_error() {
|
||||
return tcx.ty_error();
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
kind: TypeVariableOriginKind::NormalizeProjectionType,
|
||||
span: self.tcx.def_span(def_id),
|
||||
});
|
||||
let projection = ty::Binder::dummy(ty::ProjectionPredicate { projection_ty, ty: ty_var });
|
||||
let projection =
|
||||
ty::Binder::dummy(ty::ProjectionPredicate { projection_ty, term: ty_var.into() });
|
||||
let obligation = Obligation::with_depth(
|
||||
cause,
|
||||
recursion_depth,
|
||||
|
@ -1,7 +1,7 @@
|
||||
use libloading::Library;
|
||||
use rustc_ast::mut_visit::{visit_clobber, MutVisitor, *};
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::{self as ast, AttrVec, BlockCheckMode};
|
||||
use rustc_ast::{self as ast, AttrVec, BlockCheckMode, Term};
|
||||
use rustc_codegen_ssa::traits::CodegenBackend;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
#[cfg(parallel_compiler)]
|
||||
@ -738,9 +738,14 @@ impl<'a, 'b> ReplaceBodyWithLoop<'a, 'b> {
|
||||
| ast::GenericArg::Const(_) => false,
|
||||
},
|
||||
ast::AngleBracketedArg::Constraint(c) => match c.kind {
|
||||
ast::AssocTyConstraintKind::Bound { .. } => true,
|
||||
ast::AssocTyConstraintKind::Equality { ref ty } => {
|
||||
involves_impl_trait(ty)
|
||||
ast::AssocConstraintKind::Bound { .. } => true,
|
||||
ast::AssocConstraintKind::Equality { ref term } => {
|
||||
match term {
|
||||
Term::Ty(ty) => involves_impl_trait(ty),
|
||||
// FIXME(...): This should check if the constant
|
||||
// involves a trait impl, but for now ignore.
|
||||
Term::Const(_) => false,
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
|
@ -152,6 +152,19 @@ impl<'tcx> AssocItems<'tcx> {
|
||||
.find(|item| tcx.hygienic_eq(ident, item.ident, parent_def_id))
|
||||
}
|
||||
|
||||
/// Returns the associated item with the given name and any of `AssocKind`, if one exists.
|
||||
pub fn find_by_name_and_kinds(
|
||||
&self,
|
||||
tcx: TyCtxt<'_>,
|
||||
ident: Ident,
|
||||
kinds: &[AssocKind],
|
||||
parent_def_id: DefId,
|
||||
) -> Option<&ty::AssocItem> {
|
||||
self.filter_by_name_unhygienic(ident.name)
|
||||
.filter(|item| kinds.contains(&item.kind))
|
||||
.find(|item| tcx.hygienic_eq(ident, item.ident, parent_def_id))
|
||||
}
|
||||
|
||||
/// Returns the associated item with the given name in the given `Namespace`, if one exists.
|
||||
pub fn find_by_name_and_namespace(
|
||||
&self,
|
||||
|
@ -86,10 +86,14 @@ impl<'tcx> Const<'tcx> {
|
||||
if let Some(lit_input) = lit_input {
|
||||
// If an error occurred, ignore that it's a literal and leave reporting the error up to
|
||||
// mir.
|
||||
if let Ok(c) = tcx.at(expr.span).lit_to_const(lit_input) {
|
||||
return Some(c);
|
||||
} else {
|
||||
tcx.sess.delay_span_bug(expr.span, "Const::from_anon_const: couldn't lit_to_const");
|
||||
match tcx.at(expr.span).lit_to_const(lit_input) {
|
||||
Ok(c) => return Some(c),
|
||||
Err(e) => {
|
||||
tcx.sess.delay_span_bug(
|
||||
expr.span,
|
||||
&format!("Const::from_anon_const: couldn't lit_to_const {:?}", e),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@ use crate::ty::subst::{GenericArg, GenericArgKind};
|
||||
use crate::ty::TyKind::*;
|
||||
use crate::ty::{
|
||||
ConstKind, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, InferTy,
|
||||
ProjectionTy, TyCtxt, TyS, TypeAndMut,
|
||||
ProjectionTy, Term, TyCtxt, TyS, TypeAndMut,
|
||||
};
|
||||
|
||||
use rustc_errors::{Applicability, DiagnosticBuilder};
|
||||
@ -105,8 +105,14 @@ impl<'tcx> TyS<'tcx> {
|
||||
ExistentialPredicate::Trait(ExistentialTraitRef { substs, .. }) => {
|
||||
substs.iter().all(generic_arg_is_suggestible)
|
||||
}
|
||||
ExistentialPredicate::Projection(ExistentialProjection { substs, ty, .. }) => {
|
||||
ty.is_suggestable() && substs.iter().all(generic_arg_is_suggestible)
|
||||
ExistentialPredicate::Projection(ExistentialProjection {
|
||||
substs, term, ..
|
||||
}) => {
|
||||
let term_is_suggestable = match term {
|
||||
Term::Ty(ty) => ty.is_suggestable(),
|
||||
Term::Const(c) => const_is_suggestable(c.val),
|
||||
};
|
||||
term_is_suggestable && substs.iter().all(generic_arg_is_suggestible)
|
||||
}
|
||||
_ => true,
|
||||
}),
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::ty::subst::{GenericArg, GenericArgKind};
|
||||
use crate::ty::{self, InferConst, Ty, TypeFlags};
|
||||
use crate::ty::{self, InferConst, Term, Ty, TypeFlags};
|
||||
use std::slice;
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -241,9 +241,12 @@ impl FlagComputation {
|
||||
self.add_ty(a);
|
||||
self.add_ty(b);
|
||||
}
|
||||
ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
|
||||
ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => {
|
||||
self.add_projection_ty(projection_ty);
|
||||
self.add_ty(ty);
|
||||
match term {
|
||||
Term::Ty(ty) => self.add_ty(ty),
|
||||
Term::Const(c) => self.add_const(c),
|
||||
}
|
||||
}
|
||||
ty::PredicateKind::WellFormed(arg) => {
|
||||
self.add_substs(slice::from_ref(&arg));
|
||||
@ -317,7 +320,10 @@ impl FlagComputation {
|
||||
|
||||
fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<'_>) {
|
||||
self.add_substs(projection.substs);
|
||||
self.add_ty(projection.ty);
|
||||
match projection.term {
|
||||
ty::Term::Ty(ty) => self.add_ty(ty),
|
||||
ty::Term::Const(ct) => self.add_const(ct),
|
||||
}
|
||||
}
|
||||
|
||||
fn add_projection_ty(&mut self, projection_ty: ty::ProjectionTy<'_>) {
|
||||
|
@ -484,7 +484,7 @@ crate struct PredicateInner<'tcx> {
|
||||
}
|
||||
|
||||
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
|
||||
static_assert_size!(PredicateInner<'_>, 48);
|
||||
static_assert_size!(PredicateInner<'_>, 56);
|
||||
|
||||
#[derive(Clone, Copy, Lift)]
|
||||
pub struct Predicate<'tcx> {
|
||||
@ -795,6 +795,31 @@ pub struct CoercePredicate<'tcx> {
|
||||
}
|
||||
pub type PolyCoercePredicate<'tcx> = ty::Binder<'tcx, CoercePredicate<'tcx>>;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)]
|
||||
#[derive(HashStable, TypeFoldable)]
|
||||
pub enum Term<'tcx> {
|
||||
Ty(Ty<'tcx>),
|
||||
Const(&'tcx Const<'tcx>),
|
||||
}
|
||||
|
||||
impl<'tcx> From<Ty<'tcx>> for Term<'tcx> {
|
||||
fn from(ty: Ty<'tcx>) -> Self {
|
||||
Term::Ty(ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> From<&'tcx Const<'tcx>> for Term<'tcx> {
|
||||
fn from(c: &'tcx Const<'tcx>) -> Self {
|
||||
Term::Const(c)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Term<'tcx> {
|
||||
pub fn ty(&self) -> Option<Ty<'tcx>> {
|
||||
if let Term::Ty(ty) = self { Some(ty) } else { None }
|
||||
}
|
||||
}
|
||||
|
||||
/// This kind of predicate has no *direct* correspondent in the
|
||||
/// syntax, but it roughly corresponds to the syntactic forms:
|
||||
///
|
||||
@ -811,7 +836,7 @@ pub type PolyCoercePredicate<'tcx> = ty::Binder<'tcx, CoercePredicate<'tcx>>;
|
||||
#[derive(HashStable, TypeFoldable)]
|
||||
pub struct ProjectionPredicate<'tcx> {
|
||||
pub projection_ty: ProjectionTy<'tcx>,
|
||||
pub ty: Ty<'tcx>,
|
||||
pub term: Term<'tcx>,
|
||||
}
|
||||
|
||||
pub type PolyProjectionPredicate<'tcx> = Binder<'tcx, ProjectionPredicate<'tcx>>;
|
||||
@ -836,8 +861,8 @@ impl<'tcx> PolyProjectionPredicate<'tcx> {
|
||||
self.map_bound(|predicate| predicate.projection_ty.trait_ref(tcx))
|
||||
}
|
||||
|
||||
pub fn ty(&self) -> Binder<'tcx, Ty<'tcx>> {
|
||||
self.map_bound(|predicate| predicate.ty)
|
||||
pub fn term(&self) -> Binder<'tcx, Term<'tcx>> {
|
||||
self.map_bound(|predicate| predicate.term)
|
||||
}
|
||||
|
||||
/// The `DefId` of the `TraitItem` for the associated type.
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::mir::interpret::{AllocRange, ConstValue, GlobalAlloc, Pointer, Provenance, Scalar};
|
||||
use crate::ty::subst::{GenericArg, GenericArgKind, Subst};
|
||||
use crate::ty::{self, ConstInt, DefIdTree, ParamConst, ScalarInt, Ty, TyCtxt, TypeFoldable};
|
||||
use crate::ty::{self, ConstInt, DefIdTree, ParamConst, ScalarInt, Term, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc_apfloat::ieee::{Double, Single};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::sso::SsoHashSet;
|
||||
@ -799,7 +799,7 @@ pub trait PrettyPrinter<'tcx>:
|
||||
let trait_ref = proj_ref.required_poly_trait_ref(self.tcx());
|
||||
|
||||
// Projection type entry -- the def-id for naming, and the ty.
|
||||
let proj_ty = (proj_ref.projection_def_id(), proj_ref.ty());
|
||||
let proj_ty = (proj_ref.projection_def_id(), proj_ref.term());
|
||||
|
||||
self.insert_trait_and_projection(
|
||||
trait_ref,
|
||||
@ -850,8 +850,10 @@ pub trait PrettyPrinter<'tcx>:
|
||||
}
|
||||
|
||||
p!(")");
|
||||
if !return_ty.skip_binder().is_unit() {
|
||||
p!("-> ", print(return_ty));
|
||||
if let Term::Ty(ty) = return_ty.skip_binder() {
|
||||
if !ty.is_unit() {
|
||||
p!("-> ", print(return_ty));
|
||||
}
|
||||
}
|
||||
p!(write("{}", if paren_needed { ")" } else { "" }));
|
||||
|
||||
@ -902,23 +904,28 @@ pub trait PrettyPrinter<'tcx>:
|
||||
first = false;
|
||||
}
|
||||
|
||||
for (assoc_item_def_id, ty) in assoc_items {
|
||||
for (assoc_item_def_id, term) in assoc_items {
|
||||
if !first {
|
||||
p!(", ");
|
||||
}
|
||||
p!(write("{} = ", self.tcx().associated_item(assoc_item_def_id).ident));
|
||||
|
||||
// Skip printing `<[generator@] as Generator<_>>::Return` from async blocks
|
||||
match ty.skip_binder().kind() {
|
||||
ty::Projection(ty::ProjectionTy { item_def_id, .. })
|
||||
if Some(*item_def_id) == self.tcx().lang_items().generator_return() =>
|
||||
{
|
||||
p!("[async output]")
|
||||
match term.skip_binder() {
|
||||
Term::Ty(ty) => {
|
||||
// Skip printing `<[generator@] as Generator<_>>::Return` from async blocks
|
||||
if matches!(
|
||||
ty.kind(), ty::Projection(ty::ProjectionTy { item_def_id, .. })
|
||||
if Some(*item_def_id) == self.tcx().lang_items().generator_return()
|
||||
) {
|
||||
p!("[async output]")
|
||||
} else {
|
||||
p!(print(ty))
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
p!(print(ty))
|
||||
Term::Const(c) => {
|
||||
p!(print(c));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
first = false;
|
||||
}
|
||||
@ -943,8 +950,11 @@ pub trait PrettyPrinter<'tcx>:
|
||||
fn insert_trait_and_projection(
|
||||
&mut self,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
proj_ty: Option<(DefId, ty::Binder<'tcx, Ty<'tcx>>)>,
|
||||
traits: &mut BTreeMap<ty::PolyTraitRef<'tcx>, BTreeMap<DefId, ty::Binder<'tcx, Ty<'tcx>>>>,
|
||||
proj_ty: Option<(DefId, ty::Binder<'tcx, Term<'tcx>>)>,
|
||||
traits: &mut BTreeMap<
|
||||
ty::PolyTraitRef<'tcx>,
|
||||
BTreeMap<DefId, ty::Binder<'tcx, Term<'tcx>>>,
|
||||
>,
|
||||
fn_traits: &mut BTreeMap<ty::PolyTraitRef<'tcx>, OpaqueFnEntry<'tcx>>,
|
||||
) {
|
||||
let trait_def_id = trait_ref.def_id();
|
||||
@ -1019,7 +1029,11 @@ pub trait PrettyPrinter<'tcx>:
|
||||
let mut projections = predicates.projection_bounds();
|
||||
if let (Some(proj), None) = (projections.next(), projections.next()) {
|
||||
let tys: Vec<_> = args.iter().map(|k| k.expect_ty()).collect();
|
||||
p!(pretty_fn_sig(&tys, false, proj.skip_binder().ty));
|
||||
p!(pretty_fn_sig(
|
||||
&tys,
|
||||
false,
|
||||
proj.skip_binder().term.ty().expect("Return type was a const")
|
||||
));
|
||||
resugared = true;
|
||||
}
|
||||
}
|
||||
@ -2442,7 +2456,7 @@ define_print_and_forward_display! {
|
||||
|
||||
ty::ExistentialProjection<'tcx> {
|
||||
let name = cx.tcx().associated_item(self.item_def_id).ident;
|
||||
p!(write("{} = ", name), print(self.ty))
|
||||
p!(write("{} = ", name), print(self.term))
|
||||
}
|
||||
|
||||
ty::ExistentialPredicate<'tcx> {
|
||||
@ -2499,7 +2513,14 @@ define_print_and_forward_display! {
|
||||
}
|
||||
|
||||
ty::ProjectionPredicate<'tcx> {
|
||||
p!(print(self.projection_ty), " == ", print(self.ty))
|
||||
p!(print(self.projection_ty), " == ", print(self.term))
|
||||
}
|
||||
|
||||
ty::Term<'tcx> {
|
||||
match self {
|
||||
ty::Term::Ty(ty) => p!(print(ty)),
|
||||
ty::Term::Const(c) => p!(print(c)),
|
||||
}
|
||||
}
|
||||
|
||||
ty::ProjectionTy<'tcx> {
|
||||
@ -2709,5 +2730,5 @@ pub struct OpaqueFnEntry<'tcx> {
|
||||
has_fn_once: bool,
|
||||
fn_mut_trait_ref: Option<ty::PolyTraitRef<'tcx>>,
|
||||
fn_trait_ref: Option<ty::PolyTraitRef<'tcx>>,
|
||||
return_ty: Option<ty::Binder<'tcx, Ty<'tcx>>>,
|
||||
return_ty: Option<ty::Binder<'tcx, Term<'tcx>>>,
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
use crate::mir::interpret::{get_slice_bytes, ConstValue, GlobalAlloc, Scalar};
|
||||
use crate::ty::error::{ExpectedFound, TypeError};
|
||||
use crate::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
|
||||
use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
use crate::ty::{self, Term, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc_hir as ast;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_span::DUMMY_SP;
|
||||
@ -291,11 +291,11 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialProjection<'tcx> {
|
||||
b.item_def_id,
|
||||
)))
|
||||
} else {
|
||||
let ty = relation.relate_with_variance(
|
||||
let term = relation.relate_with_variance(
|
||||
ty::Invariant,
|
||||
ty::VarianceDiagInfo::default(),
|
||||
a.ty,
|
||||
b.ty,
|
||||
a.term,
|
||||
b.term,
|
||||
)?;
|
||||
let substs = relation.relate_with_variance(
|
||||
ty::Invariant,
|
||||
@ -303,7 +303,7 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialProjection<'tcx> {
|
||||
a.substs,
|
||||
b.substs,
|
||||
)?;
|
||||
Ok(ty::ExistentialProjection { item_def_id: a.item_def_id, substs, ty })
|
||||
Ok(ty::ExistentialProjection { item_def_id: a.item_def_id, substs, term })
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -833,6 +833,20 @@ impl<'tcx> Relate<'tcx> for ty::TraitPredicate<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<'tcx> for ty::Term<'tcx> {
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
relation: &mut R,
|
||||
a: Self,
|
||||
b: Self,
|
||||
) -> RelateResult<'tcx, Self> {
|
||||
Ok(match (a, b) {
|
||||
(Term::Ty(a), Term::Ty(b)) => relation.relate(a, b)?.into(),
|
||||
(Term::Const(a), Term::Const(b)) => relation.relate(a, b)?.into(),
|
||||
_ => return Err(TypeError::Mismatch),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<'tcx> for ty::ProjectionPredicate<'tcx> {
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
relation: &mut R,
|
||||
@ -841,7 +855,7 @@ impl<'tcx> Relate<'tcx> for ty::ProjectionPredicate<'tcx> {
|
||||
) -> RelateResult<'tcx, ty::ProjectionPredicate<'tcx>> {
|
||||
Ok(ty::ProjectionPredicate {
|
||||
projection_ty: relation.relate(a.projection_ty, b.projection_ty)?,
|
||||
ty: relation.relate(a.ty, b.ty)?,
|
||||
term: relation.relate(a.term, b.term)?.into(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ use crate::mir::interpret;
|
||||
use crate::mir::ProjectionKind;
|
||||
use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeVisitor};
|
||||
use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer};
|
||||
use crate::ty::{self, InferConst, Lift, Ty, TyCtxt};
|
||||
use crate::ty::{self, InferConst, Lift, Term, Ty, TyCtxt};
|
||||
use rustc_data_structures::functor::IdFunctor;
|
||||
use rustc_hir::def::Namespace;
|
||||
use rustc_hir::def_id::CRATE_DEF_INDEX;
|
||||
@ -158,7 +158,7 @@ impl<'tcx> fmt::Debug for ty::TraitPredicate<'tcx> {
|
||||
|
||||
impl<'tcx> fmt::Debug for ty::ProjectionPredicate<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "ProjectionPredicate({:?}, {:?})", self.projection_ty, self.ty)
|
||||
write!(f, "ProjectionPredicate({:?}, {:?})", self.projection_ty, self.term)
|
||||
}
|
||||
}
|
||||
|
||||
@ -356,6 +356,16 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialPredicate<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Lift<'tcx> for Term<'a> {
|
||||
type Lifted = ty::Term<'tcx>;
|
||||
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
|
||||
Some(match self {
|
||||
Term::Ty(ty) => Term::Ty(tcx.lift(ty)?),
|
||||
Term::Const(c) => Term::Const(tcx.lift(c)?),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Lift<'tcx> for ty::TraitPredicate<'a> {
|
||||
type Lifted = ty::TraitPredicate<'tcx>;
|
||||
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ty::TraitPredicate<'tcx>> {
|
||||
@ -403,8 +413,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ProjectionTy<'a> {
|
||||
impl<'a, 'tcx> Lift<'tcx> for ty::ProjectionPredicate<'a> {
|
||||
type Lifted = ty::ProjectionPredicate<'tcx>;
|
||||
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ty::ProjectionPredicate<'tcx>> {
|
||||
tcx.lift((self.projection_ty, self.ty))
|
||||
.map(|(projection_ty, ty)| ty::ProjectionPredicate { projection_ty, ty })
|
||||
tcx.lift((self.projection_ty, self.term))
|
||||
.map(|(projection_ty, term)| ty::ProjectionPredicate { projection_ty, term })
|
||||
}
|
||||
}
|
||||
|
||||
@ -413,7 +423,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialProjection<'a> {
|
||||
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
|
||||
tcx.lift(self.substs).map(|substs| ty::ExistentialProjection {
|
||||
substs,
|
||||
ty: tcx.lift(self.ty).expect("type must lift when substs do"),
|
||||
term: tcx.lift(self.term).expect("type must lift when substs do"),
|
||||
item_def_id: self.item_def_id,
|
||||
})
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ use crate::infer::canonical::Canonical;
|
||||
use crate::ty::fold::ValidateBoundVars;
|
||||
use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
|
||||
use crate::ty::InferTy::{self, *};
|
||||
use crate::ty::{self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable};
|
||||
use crate::ty::{self, AdtDef, DefIdTree, Discr, Term, Ty, TyCtxt, TypeFlags, TypeFoldable};
|
||||
use crate::ty::{DelaySpanBugEmitted, List, ParamEnv, TyS};
|
||||
use polonius_engine::Atom;
|
||||
use rustc_data_structures::captures::Captures;
|
||||
@ -1540,7 +1540,7 @@ impl From<BoundVar> for BoundTy {
|
||||
pub struct ExistentialProjection<'tcx> {
|
||||
pub item_def_id: DefId,
|
||||
pub substs: SubstsRef<'tcx>,
|
||||
pub ty: Ty<'tcx>,
|
||||
pub term: Term<'tcx>,
|
||||
}
|
||||
|
||||
pub type PolyExistentialProjection<'tcx> = Binder<'tcx, ExistentialProjection<'tcx>>;
|
||||
@ -1570,7 +1570,7 @@ impl<'tcx> ExistentialProjection<'tcx> {
|
||||
item_def_id: self.item_def_id,
|
||||
substs: tcx.mk_substs_trait(self_ty, self.substs),
|
||||
},
|
||||
ty: self.ty,
|
||||
term: self.term,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1584,7 +1584,7 @@ impl<'tcx> ExistentialProjection<'tcx> {
|
||||
Self {
|
||||
item_def_id: projection_predicate.projection_ty.item_def_id,
|
||||
substs: tcx.intern_substs(&projection_predicate.projection_ty.substs[1..]),
|
||||
ty: projection_predicate.ty,
|
||||
term: projection_predicate.term,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -157,7 +157,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
|
||||
stack.extend(obj.iter().rev().flat_map(|predicate| {
|
||||
let (substs, opt_ty) = match predicate.skip_binder() {
|
||||
ty::ExistentialPredicate::Trait(tr) => (tr.substs, None),
|
||||
ty::ExistentialPredicate::Projection(p) => (p.substs, Some(p.ty)),
|
||||
ty::ExistentialPredicate::Projection(p) => (p.substs, Some(p.term)),
|
||||
ty::ExistentialPredicate::AutoTrait(_) =>
|
||||
// Empty iterator
|
||||
{
|
||||
@ -165,7 +165,10 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
|
||||
}
|
||||
};
|
||||
|
||||
substs.iter().rev().chain(opt_ty.map(|ty| ty.into()))
|
||||
substs.iter().rev().chain(opt_ty.map(|term| match term {
|
||||
ty::Term::Ty(ty) => ty.into(),
|
||||
ty::Term::Const(ct) => ct.into(),
|
||||
}))
|
||||
}));
|
||||
}
|
||||
ty::Adt(_, substs)
|
||||
|
@ -4,8 +4,8 @@ use crate::maybe_whole;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{self, Token};
|
||||
use rustc_ast::{
|
||||
self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocTyConstraint,
|
||||
AssocTyConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs,
|
||||
self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocConstraint,
|
||||
AssocConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs,
|
||||
Path, PathSegment, QSelf,
|
||||
};
|
||||
use rustc_errors::{pluralize, Applicability, PResult};
|
||||
@ -469,12 +469,9 @@ impl<'a> Parser<'a> {
|
||||
// Parse associated type constraint bound.
|
||||
|
||||
let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?;
|
||||
AssocTyConstraintKind::Bound { bounds }
|
||||
AssocConstraintKind::Bound { bounds }
|
||||
} else if self.eat(&token::Eq) {
|
||||
// Parse associated type equality constraint
|
||||
|
||||
let ty = self.parse_assoc_equality_term(ident, self.prev_token.span)?;
|
||||
AssocTyConstraintKind::Equality { ty }
|
||||
self.parse_assoc_equality_term(ident, self.prev_token.span)?
|
||||
} else {
|
||||
unreachable!();
|
||||
};
|
||||
@ -482,11 +479,11 @@ impl<'a> Parser<'a> {
|
||||
let span = lo.to(self.prev_token.span);
|
||||
|
||||
// Gate associated type bounds, e.g., `Iterator<Item: Ord>`.
|
||||
if let AssocTyConstraintKind::Bound { .. } = kind {
|
||||
if let AssocConstraintKind::Bound { .. } = kind {
|
||||
self.sess.gated_spans.gate(sym::associated_type_bounds, span);
|
||||
}
|
||||
let constraint =
|
||||
AssocTyConstraint { id: ast::DUMMY_NODE_ID, ident, gen_args, kind, span };
|
||||
AssocConstraint { id: ast::DUMMY_NODE_ID, ident, gen_args, kind, span };
|
||||
Ok(Some(AngleBracketedArg::Constraint(constraint)))
|
||||
} else {
|
||||
Ok(Some(AngleBracketedArg::Arg(arg)))
|
||||
@ -499,22 +496,25 @@ impl<'a> Parser<'a> {
|
||||
/// Parse the term to the right of an associated item equality constraint.
|
||||
/// That is, parse `<term>` in `Item = <term>`.
|
||||
/// Right now, this only admits types in `<term>`.
|
||||
fn parse_assoc_equality_term(&mut self, ident: Ident, eq: Span) -> PResult<'a, P<ast::Ty>> {
|
||||
fn parse_assoc_equality_term(
|
||||
&mut self,
|
||||
ident: Ident,
|
||||
eq: Span,
|
||||
) -> PResult<'a, AssocConstraintKind> {
|
||||
let arg = self.parse_generic_arg(None)?;
|
||||
let span = ident.span.to(self.prev_token.span);
|
||||
match arg {
|
||||
Some(GenericArg::Type(ty)) => return Ok(ty),
|
||||
Some(GenericArg::Const(expr)) => {
|
||||
self.struct_span_err(span, "cannot constrain an associated constant to a value")
|
||||
.span_label(ident.span, "this associated constant...")
|
||||
.span_label(expr.value.span, "...cannot be constrained to this value")
|
||||
.emit();
|
||||
let term = match arg {
|
||||
Some(GenericArg::Type(ty)) => ty.into(),
|
||||
Some(GenericArg::Const(c)) => {
|
||||
self.sess.gated_spans.gate(sym::associated_const_equality, span);
|
||||
c.into()
|
||||
}
|
||||
Some(GenericArg::Lifetime(lt)) => {
|
||||
self.struct_span_err(span, "associated lifetimes are not supported")
|
||||
.span_label(lt.ident.span, "the lifetime is given here")
|
||||
.help("if you meant to specify a trait object, write `dyn Trait + 'lifetime`")
|
||||
.emit();
|
||||
self.mk_ty(span, ast::TyKind::Err).into()
|
||||
}
|
||||
None => {
|
||||
let after_eq = eq.shrink_to_hi();
|
||||
@ -542,8 +542,8 @@ impl<'a> Parser<'a> {
|
||||
};
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
Ok(self.mk_ty(span, ast::TyKind::Err))
|
||||
};
|
||||
Ok(AssocConstraintKind::Equality { term })
|
||||
}
|
||||
|
||||
/// We do not permit arbitrary expressions as const arguments. They must be one of:
|
||||
|
@ -332,9 +332,9 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
|
||||
ast_visit::walk_path_segment(self, path_span, path_segment)
|
||||
}
|
||||
|
||||
fn visit_assoc_ty_constraint(&mut self, constraint: &'v ast::AssocTyConstraint) {
|
||||
self.record("AssocTyConstraint", Id::None, constraint);
|
||||
ast_visit::walk_assoc_ty_constraint(self, constraint)
|
||||
fn visit_assoc_constraint(&mut self, constraint: &'v ast::AssocConstraint) {
|
||||
self.record("AssocConstraint", Id::None, constraint);
|
||||
ast_visit::walk_assoc_constraint(self, constraint)
|
||||
}
|
||||
|
||||
fn visit_attribute(&mut self, attr: &'v ast::Attribute) {
|
||||
|
@ -127,8 +127,8 @@ where
|
||||
constness: _,
|
||||
polarity: _,
|
||||
}) => self.visit_trait(trait_ref),
|
||||
ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
|
||||
ty.visit_with(self)?;
|
||||
ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => {
|
||||
term.visit_with(self)?;
|
||||
self.visit_projection_ty(projection_ty)
|
||||
}
|
||||
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, _region)) => {
|
||||
@ -1185,10 +1185,10 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
|
||||
}
|
||||
|
||||
for (poly_predicate, _) in bounds.projection_bounds {
|
||||
if self.visit(poly_predicate.skip_binder().ty).is_break()
|
||||
|| self
|
||||
.visit_projection_ty(poly_predicate.skip_binder().projection_ty)
|
||||
.is_break()
|
||||
let pred = poly_predicate.skip_binder();
|
||||
let poly_pred_term = self.visit(pred.term);
|
||||
if poly_pred_term.is_break()
|
||||
|| self.visit_projection_ty(pred.projection_ty).is_break()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -343,6 +343,7 @@ symbols! {
|
||||
assert_receiver_is_total_eq,
|
||||
assert_uninit_valid,
|
||||
assert_zero_valid,
|
||||
associated_const_equality,
|
||||
associated_consts,
|
||||
associated_type_bounds,
|
||||
associated_type_defaults,
|
||||
|
@ -559,7 +559,10 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> {
|
||||
let name = cx.tcx.associated_item(projection.item_def_id).ident;
|
||||
cx.push("p");
|
||||
cx.push_ident(name.as_str());
|
||||
cx = projection.ty.print(cx)?;
|
||||
cx = match projection.term {
|
||||
ty::Term::Ty(ty) => ty.print(cx),
|
||||
ty::Term::Const(c) => c.print(cx),
|
||||
}?;
|
||||
}
|
||||
ty::ExistentialPredicate::AutoTrait(def_id) => {
|
||||
cx = cx.print_def_path(*def_id, &[])?;
|
||||
|
@ -6,7 +6,7 @@ use super::*;
|
||||
use crate::infer::region_constraints::{Constraint, RegionConstraintData};
|
||||
use crate::infer::InferCtxt;
|
||||
use rustc_middle::ty::fold::TypeFolder;
|
||||
use rustc_middle::ty::{Region, RegionVid};
|
||||
use rustc_middle::ty::{Region, RegionVid, Term};
|
||||
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
|
||||
@ -606,7 +606,11 @@ impl<'tcx> AutoTraitFinder<'tcx> {
|
||||
}
|
||||
|
||||
fn is_self_referential_projection(&self, p: ty::PolyProjectionPredicate<'_>) -> bool {
|
||||
matches!(*p.ty().skip_binder().kind(), ty::Projection(proj) if proj == p.skip_binder().projection_ty)
|
||||
if let Term::Ty(ty) = p.term().skip_binder() {
|
||||
matches!(ty.kind(), ty::Projection(proj) if proj == &p.skip_binder().projection_ty)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn evaluate_nested_obligations(
|
||||
@ -663,7 +667,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
|
||||
// Additionally, we check if we've seen this predicate before,
|
||||
// to avoid rendering duplicate bounds to the user.
|
||||
if self.is_param_no_infer(p.skip_binder().projection_ty.substs)
|
||||
&& !p.ty().skip_binder().has_infer_types()
|
||||
&& !p.term().skip_binder().has_infer_types()
|
||||
&& is_new_pred
|
||||
{
|
||||
debug!(
|
||||
@ -752,7 +756,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
|
||||
// when we started out trying to unify
|
||||
// some inference variables. See the comment above
|
||||
// for more infomration
|
||||
if p.ty().skip_binder().has_infer_types() {
|
||||
if p.term().skip_binder().has_infer_types() {
|
||||
if !self.evaluate_nested_obligations(
|
||||
ty,
|
||||
v.into_iter(),
|
||||
@ -774,7 +778,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
|
||||
// However, we should always make progress (either by generating
|
||||
// subobligations or getting an error) when we started off with
|
||||
// inference variables
|
||||
if p.ty().skip_binder().has_infer_types() {
|
||||
if p.term().skip_binder().has_infer_types() {
|
||||
panic!("Unexpected result when selecting {:?} {:?}", ty, obligation)
|
||||
}
|
||||
}
|
||||
|
@ -1304,7 +1304,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
|
||||
|
||||
debug!(
|
||||
"report_projection_error normalized_ty={:?} data.ty={:?}",
|
||||
normalized_ty, data.ty
|
||||
normalized_ty, data.term,
|
||||
);
|
||||
|
||||
let is_normalized_ty_expected = !matches!(
|
||||
@ -1314,16 +1314,17 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
|
||||
| ObligationCauseCode::ObjectCastObligation(_)
|
||||
| ObligationCauseCode::OpaqueType
|
||||
);
|
||||
|
||||
// FIXME(associated_const_equality): Handle Consts here
|
||||
let data_ty = data.term.ty().unwrap();
|
||||
if let Err(error) = self.at(&obligation.cause, obligation.param_env).eq_exp(
|
||||
is_normalized_ty_expected,
|
||||
normalized_ty,
|
||||
data.ty,
|
||||
data_ty,
|
||||
) {
|
||||
values = Some(infer::ValuePairs::Types(ExpectedFound::new(
|
||||
is_normalized_ty_expected,
|
||||
normalized_ty,
|
||||
data.ty,
|
||||
data_ty,
|
||||
)));
|
||||
|
||||
err_buf = error;
|
||||
@ -1803,11 +1804,11 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
|
||||
}
|
||||
ty::PredicateKind::Projection(data) => {
|
||||
let self_ty = data.projection_ty.self_ty();
|
||||
let ty = data.ty;
|
||||
let term = data.term;
|
||||
if predicate.references_error() || self.is_tainted_by_errors() {
|
||||
return;
|
||||
}
|
||||
if self_ty.needs_infer() && ty.needs_infer() {
|
||||
if self_ty.needs_infer() && term.needs_infer() {
|
||||
// We do this for the `foo.collect()?` case to produce a suggestion.
|
||||
let mut err = self.emit_inference_failure_err(
|
||||
body_id,
|
||||
|
@ -571,7 +571,7 @@ fn object_ty_for_trait<'tcx>(
|
||||
// `trait MyTrait: for<'s> OtherTrait<&'s T, Output=bool>`.
|
||||
super_trait_ref.map_bound(|super_trait_ref| {
|
||||
ty::ExistentialPredicate::Projection(ty::ExistentialProjection {
|
||||
ty: tcx.mk_projection(item.def_id, super_trait_ref.substs),
|
||||
term: tcx.mk_projection(item.def_id, super_trait_ref.substs).into(),
|
||||
item_def_id: item.def_id,
|
||||
substs: super_trait_ref.substs,
|
||||
})
|
||||
|
@ -212,10 +212,9 @@ fn project_and_unify_type<'cx, 'tcx>(
|
||||
debug!(?normalized_ty, ?obligations, "project_and_unify_type result");
|
||||
|
||||
let infcx = selcx.infcx();
|
||||
match infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.eq(normalized_ty, obligation.predicate.ty)
|
||||
{
|
||||
// FIXME(associated_const_equality): Handle consts here as well as types.
|
||||
let obligation_pred_ty = obligation.predicate.term.ty().unwrap();
|
||||
match infcx.at(&obligation.cause, obligation.param_env).eq(normalized_ty, obligation_pred_ty) {
|
||||
Ok(InferOk { obligations: inferred_obligations, value: () }) => {
|
||||
obligations.extend(inferred_obligations);
|
||||
Ok(Ok(Some(obligations)))
|
||||
@ -1615,7 +1614,7 @@ fn confirm_generator_candidate<'cx, 'tcx>(
|
||||
substs: trait_ref.substs,
|
||||
item_def_id: obligation.predicate.item_def_id,
|
||||
},
|
||||
ty,
|
||||
term: ty.into(),
|
||||
}
|
||||
});
|
||||
|
||||
@ -1641,7 +1640,7 @@ fn confirm_discriminant_kind_candidate<'cx, 'tcx>(
|
||||
|
||||
let predicate = ty::ProjectionPredicate {
|
||||
projection_ty: ty::ProjectionTy { substs, item_def_id: discriminant_def_id },
|
||||
ty: self_ty.discriminant_ty(tcx),
|
||||
term: self_ty.discriminant_ty(tcx).into(),
|
||||
};
|
||||
|
||||
// We get here from `poly_project_and_unify_type` which replaces bound vars
|
||||
@ -1674,7 +1673,7 @@ fn confirm_pointee_candidate<'cx, 'tcx>(
|
||||
|
||||
let predicate = ty::ProjectionPredicate {
|
||||
projection_ty: ty::ProjectionTy { substs, item_def_id: metadata_def_id },
|
||||
ty: metadata_ty,
|
||||
term: metadata_ty.into(),
|
||||
};
|
||||
|
||||
confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false)
|
||||
@ -1747,7 +1746,7 @@ fn confirm_callable_candidate<'cx, 'tcx>(
|
||||
substs: trait_ref.substs,
|
||||
item_def_id: fn_once_output_def_id,
|
||||
},
|
||||
ty: ret_type,
|
||||
term: ret_type.into(),
|
||||
});
|
||||
|
||||
confirm_param_env_candidate(selcx, obligation, predicate, true)
|
||||
@ -1803,7 +1802,9 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
|
||||
Ok(InferOk { value: _, obligations }) => {
|
||||
nested_obligations.extend(obligations);
|
||||
assoc_ty_own_obligations(selcx, obligation, &mut nested_obligations);
|
||||
Progress { ty: cache_entry.ty, obligations: nested_obligations }
|
||||
// FIXME(associated_const_equality): Handle consts here as well? Maybe this progress type should just take
|
||||
// a term instead.
|
||||
Progress { ty: cache_entry.term.ty().unwrap(), obligations: nested_obligations }
|
||||
}
|
||||
Err(e) => {
|
||||
let msg = format!(
|
||||
|
@ -62,7 +62,7 @@ pub(crate) fn update<'tcx, T>(
|
||||
if let ty::PredicateKind::Projection(predicate) = obligation.predicate.kind().skip_binder() {
|
||||
// If the projection predicate (Foo::Bar == X) has X as a non-TyVid,
|
||||
// we need to make it into one.
|
||||
if let Some(vid) = predicate.ty.ty_vid() {
|
||||
if let Some(vid) = predicate.term.ty().and_then(|ty| ty.ty_vid()) {
|
||||
debug!("relationship: {:?}.output = true", vid);
|
||||
engine.relationships().entry(vid).or_default().output = true;
|
||||
}
|
||||
|
@ -116,7 +116,10 @@ pub fn predicate_obligations<'a, 'tcx>(
|
||||
}
|
||||
ty::PredicateKind::Projection(t) => {
|
||||
wf.compute_projection(t.projection_ty);
|
||||
wf.compute(t.ty.into());
|
||||
wf.compute(match t.term {
|
||||
ty::Term::Ty(ty) => ty.into(),
|
||||
ty::Term::Const(c) => c.into(),
|
||||
})
|
||||
}
|
||||
ty::PredicateKind::WellFormed(arg) => {
|
||||
wf.compute(arg);
|
||||
@ -219,7 +222,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>(
|
||||
// projection coming from another associated type. See
|
||||
// `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs` and
|
||||
// `traits-assoc-type-in-supertrait-bad.rs`.
|
||||
if let ty::Projection(projection_ty) = proj.ty.kind() {
|
||||
if let Some(ty::Projection(projection_ty)) = proj.term.ty().map(|ty| ty.kind()) {
|
||||
if let Some(&impl_item_id) =
|
||||
tcx.impl_item_implementor_ids(impl_def_id).get(&projection_ty.item_def_id)
|
||||
{
|
||||
|
@ -226,13 +226,26 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::AliasEq<RustInterner<'tcx>>>
|
||||
for rustc_middle::ty::ProjectionPredicate<'tcx>
|
||||
{
|
||||
fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::AliasEq<RustInterner<'tcx>> {
|
||||
// FIXME(associated_const_equality): teach chalk about terms for alias eq.
|
||||
chalk_ir::AliasEq {
|
||||
ty: self.ty.lower_into(interner),
|
||||
ty: self.term.ty().unwrap().lower_into(interner),
|
||||
alias: self.projection_ty.lower_into(interner),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// FIXME(...): Where do I add this to Chalk? I can't find it in the rustc repo anywhere.
|
||||
impl<'tcx> LowerInto<'tcx, chalk_ir::Term<RustInterner<'tcx>>> for rustc_middle::ty::Term<'tcx> {
|
||||
fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::Term<RustInterner<'tcx>> {
|
||||
match self {
|
||||
ty::Term::Ty(ty) => ty.lower_into(interner).into(),
|
||||
ty::Term::Const(c) => c.lower_into(interner).into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
impl<'tcx> LowerInto<'tcx, chalk_ir::Ty<RustInterner<'tcx>>> for Ty<'tcx> {
|
||||
fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::Ty<RustInterner<'tcx>> {
|
||||
let int = |i| chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Int(i));
|
||||
@ -651,7 +664,8 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Binders<chalk_ir::QuantifiedWhereClauses<Ru
|
||||
.mk_substs_trait(self_ty, predicate.substs)
|
||||
.lower_into(interner),
|
||||
}),
|
||||
ty: predicate.ty.lower_into(interner),
|
||||
// FIXME(associated_const_equality): teach chalk about terms for alias eq.
|
||||
ty: predicate.term.ty().unwrap().lower_into(interner),
|
||||
}),
|
||||
),
|
||||
ty::ExistentialPredicate::AutoTrait(def_id) => chalk_ir::Binders::new(
|
||||
@ -787,7 +801,7 @@ impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::AliasEqBound<RustInterner<'tcx>
|
||||
trait_bound: trait_ref.lower_into(interner),
|
||||
associated_ty_id: chalk_ir::AssocTypeId(self.projection_ty.item_def_id),
|
||||
parameters: own_substs.iter().map(|arg| arg.lower_into(interner)).collect(),
|
||||
value: self.ty.lower_into(interner),
|
||||
value: self.term.ty().unwrap().lower_into(interner),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -151,8 +151,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
.bindings
|
||||
.iter()
|
||||
.find_map(|b| match (b.ident.name == sym::Output, &b.kind) {
|
||||
(true, hir::TypeBindingKind::Equality { ty }) => {
|
||||
sess.source_map().span_to_snippet(ty.span).ok()
|
||||
(true, hir::TypeBindingKind::Equality { term }) => {
|
||||
let span = match term {
|
||||
hir::Term::Ty(ty) => ty.span,
|
||||
hir::Term::Const(c) => self.tcx().hir().span(c.hir_id),
|
||||
};
|
||||
sess.source_map().span_to_snippet(span).ok()
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
|
@ -123,7 +123,7 @@ struct ConvertedBinding<'a, 'tcx> {
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ConvertedBindingKind<'a, 'tcx> {
|
||||
Equality(Ty<'tcx>),
|
||||
Equality(ty::Term<'tcx>),
|
||||
Constraint(&'a [hir::GenericBound<'a>]),
|
||||
}
|
||||
|
||||
@ -601,10 +601,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
.iter()
|
||||
.map(|binding| {
|
||||
let kind = match binding.kind {
|
||||
hir::TypeBindingKind::Equality { ty } => {
|
||||
ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty))
|
||||
}
|
||||
hir::TypeBindingKind::Constraint { bounds } => {
|
||||
hir::TypeBindingKind::Equality { ref term } => match term {
|
||||
hir::Term::Ty(ref ty) => {
|
||||
ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty).into())
|
||||
}
|
||||
hir::Term::Const(ref c) => {
|
||||
let local_did = self.tcx().hir().local_def_id(c.hir_id);
|
||||
let c = Const::from_anon_const(self.tcx(), local_did);
|
||||
ConvertedBindingKind::Equality(c.into())
|
||||
}
|
||||
},
|
||||
hir::TypeBindingKind::Constraint { ref bounds } => {
|
||||
ConvertedBindingKind::Constraint(bounds)
|
||||
}
|
||||
};
|
||||
@ -867,6 +874,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
.find_by_name_and_kind(self.tcx(), assoc_name, ty::AssocKind::Type, trait_def_id)
|
||||
.is_some()
|
||||
}
|
||||
fn trait_defines_associated_named(&self, trait_def_id: DefId, assoc_name: Ident) -> bool {
|
||||
self.tcx()
|
||||
.associated_items(trait_def_id)
|
||||
.find_by_name_and_kinds(
|
||||
self.tcx(),
|
||||
assoc_name,
|
||||
&[ty::AssocKind::Type, ty::AssocKind::Const],
|
||||
trait_def_id,
|
||||
)
|
||||
.is_some()
|
||||
}
|
||||
|
||||
// Sets `implicitly_sized` to true on `Bounds` if necessary
|
||||
pub(crate) fn add_implicitly_sized<'hir>(
|
||||
@ -1118,9 +1136,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
.associated_items(candidate.def_id())
|
||||
.filter_by_name_unhygienic(assoc_ident.name)
|
||||
.find(|i| {
|
||||
i.kind == ty::AssocKind::Type && i.ident.normalize_to_macros_2_0() == assoc_ident
|
||||
(i.kind == ty::AssocKind::Type || i.kind == ty::AssocKind::Const)
|
||||
&& i.ident.normalize_to_macros_2_0() == assoc_ident
|
||||
})
|
||||
.expect("missing associated type");
|
||||
// FIXME(associated_const_equality): need to handle assoc_consts here as well.
|
||||
if assoc_ty.kind == ty::AssocKind::Const {
|
||||
tcx.sess
|
||||
.struct_span_err(path_span, &format!("associated const equality is incomplete"))
|
||||
.span_label(path_span, "cannot yet relate associated const")
|
||||
.emit();
|
||||
return Err(ErrorReported);
|
||||
}
|
||||
|
||||
if !assoc_ty.vis.is_accessible_from(def_scope, tcx) {
|
||||
tcx.sess
|
||||
@ -1215,18 +1242,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
}
|
||||
|
||||
match binding.kind {
|
||||
ConvertedBindingKind::Equality(ty) => {
|
||||
ConvertedBindingKind::Equality(term) => {
|
||||
// "Desugar" a constraint like `T: Iterator<Item = u32>` this to
|
||||
// the "projection predicate" for:
|
||||
//
|
||||
// `<T as Iterator>::Item = u32`
|
||||
bounds.projection_bounds.push((
|
||||
projection_ty.map_bound(|projection_ty| {
|
||||
debug!(
|
||||
"add_predicates_for_ast_type_binding: projection_ty {:?}, substs: {:?}",
|
||||
projection_ty, projection_ty.substs
|
||||
);
|
||||
ty::ProjectionPredicate { projection_ty, ty }
|
||||
projection_ty.map_bound(|projection_ty| ty::ProjectionPredicate {
|
||||
projection_ty,
|
||||
term: term,
|
||||
}),
|
||||
binding.span,
|
||||
));
|
||||
@ -1377,8 +1401,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
let pred = bound_predicate.rebind(pred);
|
||||
// A `Self` within the original bound will be substituted with a
|
||||
// `trait_object_dummy_self`, so check for that.
|
||||
let references_self =
|
||||
pred.skip_binder().ty.walk().any(|arg| arg == dummy_self.into());
|
||||
let references_self = match pred.skip_binder().term {
|
||||
ty::Term::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()),
|
||||
ty::Term::Const(c) => c.ty.walk().any(|arg| arg == dummy_self.into()),
|
||||
};
|
||||
|
||||
// If the projection output contains `Self`, force the user to
|
||||
// elaborate it explicitly to avoid a lot of complexity.
|
||||
@ -1601,7 +1627,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
|
||||
{
|
||||
let mut matching_candidates = all_candidates()
|
||||
.filter(|r| self.trait_defines_associated_type_named(r.def_id(), assoc_name));
|
||||
.filter(|r| self.trait_defines_associated_named(r.def_id(), assoc_name));
|
||||
|
||||
let bound = match matching_candidates.next() {
|
||||
Some(bound) => bound,
|
||||
|
@ -48,14 +48,19 @@ impl<'tcx> Bounds<'tcx> {
|
||||
/// where-clauses). Because some of our bounds listings (e.g.,
|
||||
/// regions) don't include the self-type, you must supply the
|
||||
/// self-type here (the `param_ty` parameter).
|
||||
pub fn predicates(
|
||||
&self,
|
||||
pub fn predicates<'out, 's>(
|
||||
&'s self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_ty: Ty<'tcx>,
|
||||
) -> Vec<(ty::Predicate<'tcx>, Span)> {
|
||||
// the output must live shorter than the duration of the borrow of self and 'tcx.
|
||||
) -> impl Iterator<Item = (ty::Predicate<'tcx>, Span)> + 'out
|
||||
where
|
||||
'tcx: 'out,
|
||||
's: 'out,
|
||||
{
|
||||
// If it could be sized, and is, add the `Sized` predicate.
|
||||
let sized_predicate = self.implicitly_sized.and_then(|span| {
|
||||
tcx.lang_items().sized_trait().map(|sized| {
|
||||
tcx.lang_items().sized_trait().map(move |sized| {
|
||||
let trait_ref = ty::Binder::dummy(ty::TraitRef {
|
||||
def_id: sized,
|
||||
substs: tcx.mk_substs_trait(param_ty, &[]),
|
||||
@ -64,25 +69,22 @@ impl<'tcx> Bounds<'tcx> {
|
||||
})
|
||||
});
|
||||
|
||||
sized_predicate
|
||||
.into_iter()
|
||||
.chain(self.region_bounds.iter().map(|&(region_bound, span)| {
|
||||
(
|
||||
region_bound
|
||||
.map_bound(|region_bound| ty::OutlivesPredicate(param_ty, region_bound))
|
||||
.to_predicate(tcx),
|
||||
span,
|
||||
)
|
||||
}))
|
||||
.chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| {
|
||||
let region_preds = self.region_bounds.iter().map(move |&(region_bound, span)| {
|
||||
let pred = region_bound
|
||||
.map_bound(|region_bound| ty::OutlivesPredicate(param_ty, region_bound))
|
||||
.to_predicate(tcx);
|
||||
(pred, span)
|
||||
});
|
||||
let trait_bounds =
|
||||
self.trait_bounds.iter().map(move |&(bound_trait_ref, span, constness)| {
|
||||
let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx);
|
||||
(predicate, span)
|
||||
}))
|
||||
.chain(
|
||||
self.projection_bounds
|
||||
.iter()
|
||||
.map(|&(projection, span)| (projection.to_predicate(tcx), span)),
|
||||
)
|
||||
.collect()
|
||||
});
|
||||
let projection_bounds = self
|
||||
.projection_bounds
|
||||
.iter()
|
||||
.map(move |&(projection, span)| (projection.to_predicate(tcx), span));
|
||||
|
||||
sized_predicate.into_iter().chain(region_preds).chain(trait_bounds).chain(projection_bounds)
|
||||
}
|
||||
}
|
||||
|
@ -279,7 +279,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
return None;
|
||||
};
|
||||
|
||||
let ret_param_ty = projection.skip_binder().ty;
|
||||
// Since this is a return parameter type it is safe to unwrap.
|
||||
let ret_param_ty = projection.skip_binder().term.ty().unwrap();
|
||||
let ret_param_ty = self.resolve_vars_if_possible(ret_param_ty);
|
||||
debug!("deduce_sig_from_projection: ret_param_ty={:?}", ret_param_ty);
|
||||
|
||||
@ -706,9 +707,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// Extract the type from the projection. Note that there can
|
||||
// be no bound variables in this type because the "self type"
|
||||
// does not have any regions in it.
|
||||
let output_ty = self.resolve_vars_if_possible(predicate.ty);
|
||||
let output_ty = self.resolve_vars_if_possible(predicate.term);
|
||||
debug!("deduce_future_output_from_projection: output_ty={:?}", output_ty);
|
||||
Some(output_ty)
|
||||
// This is a projection on a Fn trait so will always be a type.
|
||||
Some(output_ty.ty().unwrap())
|
||||
}
|
||||
|
||||
/// Converts the types that the user supplied, in case that doing
|
||||
|
@ -1353,7 +1353,7 @@ pub fn check_type_bounds<'tcx>(
|
||||
item_def_id: trait_ty.def_id,
|
||||
substs: rebased_substs,
|
||||
},
|
||||
ty: impl_ty_value,
|
||||
term: impl_ty_value.into(),
|
||||
},
|
||||
bound_vars,
|
||||
)
|
||||
|
@ -789,10 +789,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
item_def_id: projection_ty.item_def_id,
|
||||
};
|
||||
|
||||
let ty = pred.skip_binder().ty;
|
||||
let term = pred.skip_binder().term;
|
||||
|
||||
let obligation = format!("{} = {}", projection_ty, ty);
|
||||
let quiet = format!("{} = {}", quiet_projection_ty, ty);
|
||||
let obligation = format!("{} = {}", projection_ty, term);
|
||||
let quiet = format!("{} = {}", quiet_projection_ty, term);
|
||||
|
||||
bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
|
||||
Some((obligation, projection_ty.self_ty()))
|
||||
|
@ -716,7 +716,11 @@ fn bounds_from_generic_predicates<'tcx>(
|
||||
// insert the associated types where they correspond, but for now let's be "lazy" and
|
||||
// propose this instead of the following valid resugaring:
|
||||
// `T: Trait, Trait::Assoc = K` → `T: Trait<Assoc = K>`
|
||||
where_clauses.push(format!("{} = {}", tcx.def_path_str(p.projection_ty.item_def_id), p.ty));
|
||||
where_clauses.push(format!(
|
||||
"{} = {}",
|
||||
tcx.def_path_str(p.projection_ty.item_def_id),
|
||||
p.term,
|
||||
));
|
||||
}
|
||||
let where_clauses = if where_clauses.is_empty() {
|
||||
String::new()
|
||||
|
@ -659,7 +659,11 @@ impl<'tcx> ItemCtxt<'tcx> {
|
||||
.params
|
||||
.iter()
|
||||
.filter_map(|param| match param.kind {
|
||||
GenericParamKind::Type { .. } if param.hir_id == param_id => Some(¶m.bounds),
|
||||
GenericParamKind::Type { .. } | GenericParamKind::Const { .. }
|
||||
if param.hir_id == param_id =>
|
||||
{
|
||||
Some(¶m.bounds)
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.flat_map(|bounds| bounds.iter())
|
||||
@ -2527,7 +2531,7 @@ fn predicates_from_bound<'tcx>(
|
||||
) -> Vec<(ty::Predicate<'tcx>, Span)> {
|
||||
let mut bounds = Bounds::default();
|
||||
astconv.add_bounds(param_ty, [bound].into_iter(), &mut bounds, bound_vars);
|
||||
bounds.predicates(astconv.tcx(), param_ty)
|
||||
bounds.predicates(astconv.tcx(), param_ty).collect()
|
||||
}
|
||||
|
||||
fn compute_sig_of_foreign_fn_decl<'tcx>(
|
||||
|
@ -67,11 +67,7 @@ fn opaque_type_bounds<'tcx>(
|
||||
let mut bounds = <dyn AstConv<'_>>::compute_bounds(&icx, item_ty, ast_bounds);
|
||||
// Opaque types are implicitly sized unless a `?Sized` bound is found
|
||||
<dyn AstConv<'_>>::add_implicitly_sized(&icx, &mut bounds, ast_bounds, None, span);
|
||||
let bounds = bounds.predicates(tcx, item_ty);
|
||||
|
||||
debug!("opaque_type_bounds({}) = {:?}", tcx.def_path_str(opaque_def_id), bounds);
|
||||
|
||||
tcx.arena.alloc_slice(&bounds)
|
||||
tcx.arena.alloc_from_iter(bounds.predicates(tcx, item_ty))
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -203,7 +203,7 @@ pub fn setup_constraining_predicates<'tcx>(
|
||||
if !relies_only_on_inputs {
|
||||
continue;
|
||||
}
|
||||
input_parameters.extend(parameters_for(&projection.ty, false));
|
||||
input_parameters.extend(parameters_for(&projection.term, false));
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
@ -199,7 +199,7 @@ fn unconstrained_parent_impl_substs<'tcx>(
|
||||
for (predicate, _) in impl_generic_predicates.predicates.iter() {
|
||||
if let ty::PredicateKind::Projection(proj) = predicate.kind().skip_binder() {
|
||||
let projection_ty = proj.projection_ty;
|
||||
let projected_ty = proj.ty;
|
||||
let projected_ty = proj.term;
|
||||
|
||||
let unbound_trait_ref = projection_ty.trait_ref(tcx);
|
||||
if Some(unbound_trait_ref) == impl_trait_ref {
|
||||
|
@ -308,11 +308,14 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
||||
}
|
||||
|
||||
for projection in data.projection_bounds() {
|
||||
self.add_constraints_from_ty(
|
||||
current,
|
||||
projection.skip_binder().ty,
|
||||
self.invariant,
|
||||
);
|
||||
match projection.skip_binder().term {
|
||||
ty::Term::Ty(ty) => {
|
||||
self.add_constraints_from_ty(current, ty, self.invariant);
|
||||
}
|
||||
ty::Term::Const(c) => {
|
||||
self.add_constraints_from_const(current, c, self.invariant)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,7 +83,9 @@ def check_type(ty):
|
||||
check_type(arg["const"]["type"])
|
||||
for binding in args["angle_bracketed"]["bindings"]:
|
||||
if "equality" in binding["binding"]:
|
||||
check_type(binding["binding"]["equality"])
|
||||
term = binding["binding"]["equality"]
|
||||
if "type" in term: check_type(term["type"])
|
||||
elif "const" in term: check_type(term["const"])
|
||||
elif "constraint" in binding["binding"]:
|
||||
for bound in binding["binding"]["constraint"]:
|
||||
check_generic_bound(bound)
|
||||
|
@ -553,8 +553,10 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
||||
if self.is_fn_trait(trait_) && left_name == sym::Output {
|
||||
ty_to_fn
|
||||
.entry(*ty.clone())
|
||||
.and_modify(|e| *e = (e.0.clone(), Some(rhs.clone())))
|
||||
.or_insert((None, Some(rhs)));
|
||||
.and_modify(|e| {
|
||||
*e = (e.0.clone(), Some(rhs.ty().unwrap().clone()))
|
||||
})
|
||||
.or_insert((None, Some(rhs.ty().unwrap().clone())));
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -570,7 +572,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
||||
GenericArgs::AngleBracketed { ref mut bindings, .. } => {
|
||||
bindings.push(TypeBinding {
|
||||
name: left_name,
|
||||
kind: TypeBindingKind::Equality { ty: rhs },
|
||||
kind: TypeBindingKind::Equality { term: rhs },
|
||||
});
|
||||
}
|
||||
GenericArgs::Parenthesized { .. } => {
|
||||
|
@ -272,9 +272,10 @@ impl Clean<WherePredicate> for hir::WherePredicate<'_> {
|
||||
bounds: wrp.bounds.iter().filter_map(|x| x.clean(cx)).collect(),
|
||||
},
|
||||
|
||||
hir::WherePredicate::EqPredicate(ref wrp) => {
|
||||
WherePredicate::EqPredicate { lhs: wrp.lhs_ty.clean(cx), rhs: wrp.rhs_ty.clean(cx) }
|
||||
}
|
||||
hir::WherePredicate::EqPredicate(ref wrp) => WherePredicate::EqPredicate {
|
||||
lhs: wrp.lhs_ty.clean(cx),
|
||||
rhs: wrp.rhs_ty.clean(cx).into(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -352,10 +353,31 @@ impl<'tcx> Clean<Option<WherePredicate>> for ty::OutlivesPredicate<Ty<'tcx>, ty:
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Clean<Term> for ty::Term<'tcx> {
|
||||
fn clean(&self, cx: &mut DocContext<'_>) -> Term {
|
||||
match self {
|
||||
ty::Term::Ty(ty) => Term::Type(ty.clean(cx)),
|
||||
ty::Term::Const(c) => Term::Constant(c.clean(cx)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Clean<Term> for hir::Term<'tcx> {
|
||||
fn clean(&self, cx: &mut DocContext<'_>) -> Term {
|
||||
match self {
|
||||
hir::Term::Ty(ty) => Term::Type(ty.clean(cx)),
|
||||
hir::Term::Const(c) => {
|
||||
let def_id = cx.tcx.hir().local_def_id(c.hir_id);
|
||||
Term::Constant(ty::Const::from_anon_const(cx.tcx, def_id).clean(cx))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Clean<WherePredicate> for ty::ProjectionPredicate<'tcx> {
|
||||
fn clean(&self, cx: &mut DocContext<'_>) -> WherePredicate {
|
||||
let ty::ProjectionPredicate { projection_ty, ty } = self;
|
||||
WherePredicate::EqPredicate { lhs: projection_ty.clean(cx), rhs: ty.clean(cx) }
|
||||
let ty::ProjectionPredicate { projection_ty, term } = self;
|
||||
WherePredicate::EqPredicate { lhs: projection_ty.clean(cx), rhs: term.clean(cx) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -613,7 +635,7 @@ fn clean_ty_generics(
|
||||
|
||||
if let Some(param_idx) = param_idx {
|
||||
if let Some(b) = impl_trait.get_mut(¶m_idx.into()) {
|
||||
let p = p.clean(cx)?;
|
||||
let p: WherePredicate = p.clean(cx)?;
|
||||
|
||||
b.extend(
|
||||
p.get_bounds()
|
||||
@ -624,11 +646,16 @@ fn clean_ty_generics(
|
||||
);
|
||||
|
||||
let proj = projection
|
||||
.map(|p| (p.skip_binder().projection_ty.clean(cx), p.skip_binder().ty));
|
||||
.map(|p| (p.skip_binder().projection_ty.clean(cx), p.skip_binder().term));
|
||||
if let Some(((_, trait_did, name), rhs)) =
|
||||
proj.as_ref().and_then(|(lhs, rhs)| Some((lhs.projection()?, rhs)))
|
||||
{
|
||||
impl_trait_proj.entry(param_idx).or_default().push((trait_did, name, rhs));
|
||||
// FIXME(...): Remove this unwrap()
|
||||
impl_trait_proj.entry(param_idx).or_default().push((
|
||||
trait_did,
|
||||
name,
|
||||
rhs.ty().unwrap(),
|
||||
));
|
||||
}
|
||||
|
||||
return None;
|
||||
@ -647,7 +674,7 @@ fn clean_ty_generics(
|
||||
if let Some(proj) = impl_trait_proj.remove(&idx) {
|
||||
for (trait_did, name, rhs) in proj {
|
||||
let rhs = rhs.clean(cx);
|
||||
simplify::merge_bounds(cx, &mut bounds, trait_did, name, &rhs);
|
||||
simplify::merge_bounds(cx, &mut bounds, trait_did, name, &Term::Type(rhs));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -1495,7 +1522,9 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
|
||||
for pb in obj.projection_bounds() {
|
||||
bindings.push(TypeBinding {
|
||||
name: cx.tcx.associated_item(pb.item_def_id()).ident.name,
|
||||
kind: TypeBindingKind::Equality { ty: pb.skip_binder().ty.clean(cx) },
|
||||
kind: TypeBindingKind::Equality {
|
||||
term: pb.skip_binder().term.clean(cx).into(),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@ -1566,7 +1595,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
|
||||
.ident
|
||||
.name,
|
||||
kind: TypeBindingKind::Equality {
|
||||
ty: proj.ty.clean(cx),
|
||||
term: proj.term.clean(cx),
|
||||
},
|
||||
})
|
||||
} else {
|
||||
@ -2114,10 +2143,10 @@ impl Clean<TypeBinding> for hir::TypeBinding<'_> {
|
||||
impl Clean<TypeBindingKind> for hir::TypeBindingKind<'_> {
|
||||
fn clean(&self, cx: &mut DocContext<'_>) -> TypeBindingKind {
|
||||
match *self {
|
||||
hir::TypeBindingKind::Equality { ref ty } => {
|
||||
TypeBindingKind::Equality { ty: ty.clean(cx) }
|
||||
hir::TypeBindingKind::Equality { ref term } => {
|
||||
TypeBindingKind::Equality { term: term.clean(cx) }
|
||||
}
|
||||
hir::TypeBindingKind::Constraint { bounds } => TypeBindingKind::Constraint {
|
||||
hir::TypeBindingKind::Constraint { ref bounds } => TypeBindingKind::Constraint {
|
||||
bounds: bounds.iter().filter_map(|b| b.clean(cx)).collect(),
|
||||
},
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ crate fn merge_bounds(
|
||||
bounds: &mut Vec<clean::GenericBound>,
|
||||
trait_did: DefId,
|
||||
name: Symbol,
|
||||
rhs: &clean::Type,
|
||||
rhs: &clean::Term,
|
||||
) -> bool {
|
||||
!bounds.iter_mut().any(|b| {
|
||||
let trait_ref = match *b {
|
||||
@ -110,14 +110,14 @@ crate fn merge_bounds(
|
||||
PP::AngleBracketed { ref mut bindings, .. } => {
|
||||
bindings.push(clean::TypeBinding {
|
||||
name,
|
||||
kind: clean::TypeBindingKind::Equality { ty: rhs.clone() },
|
||||
kind: clean::TypeBindingKind::Equality { term: rhs.clone() },
|
||||
});
|
||||
}
|
||||
PP::Parenthesized { ref mut output, .. } => match output {
|
||||
Some(o) => assert_eq!(o.as_ref(), rhs),
|
||||
Some(o) => assert_eq!(&clean::Term::Type(o.as_ref().clone()), rhs),
|
||||
None => {
|
||||
if *rhs != clean::Type::Tuple(Vec::new()) {
|
||||
*output = Some(Box::new(rhs.clone()));
|
||||
if *rhs != clean::Term::Type(clean::Type::Tuple(Vec::new())) {
|
||||
*output = Some(Box::new(rhs.ty().unwrap().clone()));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -1212,7 +1212,7 @@ impl Lifetime {
|
||||
crate enum WherePredicate {
|
||||
BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<Lifetime> },
|
||||
RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
|
||||
EqPredicate { lhs: Type, rhs: Type },
|
||||
EqPredicate { lhs: Type, rhs: Term },
|
||||
}
|
||||
|
||||
impl WherePredicate {
|
||||
@ -1308,7 +1308,9 @@ impl FnDecl {
|
||||
FnRetTy::Return(Type::ImplTrait(bounds)) => match &bounds[0] {
|
||||
GenericBound::TraitBound(PolyTrait { trait_, .. }, ..) => {
|
||||
let bindings = trait_.bindings().unwrap();
|
||||
FnRetTy::Return(bindings[0].ty().clone())
|
||||
let ret_ty = bindings[0].term();
|
||||
let ty = ret_ty.ty().expect("Unexpected constant return term");
|
||||
FnRetTy::Return(ty.clone())
|
||||
}
|
||||
_ => panic!("unexpected desugaring of async function"),
|
||||
},
|
||||
@ -2121,6 +2123,24 @@ crate struct Constant {
|
||||
crate kind: ConstantKind,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
crate enum Term {
|
||||
Type(Type),
|
||||
Constant(Constant),
|
||||
}
|
||||
|
||||
impl Term {
|
||||
crate fn ty(&self) -> Option<&Type> {
|
||||
if let Term::Type(ty) = self { Some(ty) } else { None }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Type> for Term {
|
||||
fn from(ty: Type) -> Self {
|
||||
Term::Type(ty)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
crate enum ConstantKind {
|
||||
/// This is the wrapper around `ty::Const` for a non-local constant. Because it doesn't have a
|
||||
@ -2283,14 +2303,14 @@ crate struct TypeBinding {
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||
crate enum TypeBindingKind {
|
||||
Equality { ty: Type },
|
||||
Equality { term: Term },
|
||||
Constraint { bounds: Vec<GenericBound> },
|
||||
}
|
||||
|
||||
impl TypeBinding {
|
||||
crate fn ty(&self) -> &Type {
|
||||
crate fn term(&self) -> &Term {
|
||||
match self.kind {
|
||||
TypeBindingKind::Equality { ref ty } => ty,
|
||||
TypeBindingKind::Equality { ref term } => term,
|
||||
_ => panic!("expected equality type binding for parenthesized generic args"),
|
||||
}
|
||||
}
|
||||
|
@ -1442,11 +1442,11 @@ impl clean::TypeBinding {
|
||||
display_fn(move |f| {
|
||||
f.write_str(self.name.as_str())?;
|
||||
match self.kind {
|
||||
clean::TypeBindingKind::Equality { ref ty } => {
|
||||
clean::TypeBindingKind::Equality { ref term } => {
|
||||
if f.alternate() {
|
||||
write!(f, " = {:#}", ty.print(cx))?;
|
||||
write!(f, " = {:#}", term.print(cx))?;
|
||||
} else {
|
||||
write!(f, " = {}", ty.print(cx))?;
|
||||
write!(f, " = {}", term.print(cx))?;
|
||||
}
|
||||
}
|
||||
clean::TypeBindingKind::Constraint { ref bounds } => {
|
||||
@ -1492,6 +1492,18 @@ impl clean::GenericArg {
|
||||
}
|
||||
}
|
||||
|
||||
impl clean::types::Term {
|
||||
crate fn print<'a, 'tcx: 'a>(
|
||||
&'a self,
|
||||
cx: &'a Context<'tcx>,
|
||||
) -> impl fmt::Display + 'a + Captures<'tcx> {
|
||||
match self {
|
||||
clean::types::Term::Type(ty) => ty.print(cx),
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
crate fn display_fn(f: impl FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl fmt::Display {
|
||||
struct WithFormatter<F>(Cell<Option<F>>);
|
||||
|
||||
|
@ -162,7 +162,7 @@ impl FromWithTcx<clean::TypeBindingKind> for TypeBindingKind {
|
||||
fn from_tcx(kind: clean::TypeBindingKind, tcx: TyCtxt<'_>) -> Self {
|
||||
use clean::TypeBindingKind::*;
|
||||
match kind {
|
||||
Equality { ty } => TypeBindingKind::Equality(ty.into_tcx(tcx)),
|
||||
Equality { term } => TypeBindingKind::Equality(term.into_tcx(tcx)),
|
||||
Constraint { bounds } => {
|
||||
TypeBindingKind::Constraint(bounds.into_iter().map(|a| a.into_tcx(tcx)).collect())
|
||||
}
|
||||
@ -452,6 +452,15 @@ impl FromWithTcx<clean::Type> for Type {
|
||||
}
|
||||
}
|
||||
|
||||
impl FromWithTcx<clean::Term> for Term {
|
||||
fn from_tcx(term: clean::Term, tcx: TyCtxt<'_>) -> Term {
|
||||
match term {
|
||||
clean::Term::Type(ty) => Term::Type(FromWithTcx::from_tcx(ty, tcx)),
|
||||
clean::Term::Constant(c) => Term::Constant(FromWithTcx::from_tcx(c, tcx)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromWithTcx<clean::BareFunctionDecl> for FunctionPointer {
|
||||
fn from_tcx(bare_decl: clean::BareFunctionDecl, tcx: TyCtxt<'_>) -> Self {
|
||||
let clean::BareFunctionDecl { unsafety, generic_params, decl, abi } = bare_decl;
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 2abffbf977a9e8c6ca4174a08fe5c4d7781f0aac
|
||||
Subproject commit 6b3dbcc81a470e5da84576d63fcfc19e3b1154cd
|
@ -148,7 +148,7 @@ pub struct TypeBinding {
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum TypeBindingKind {
|
||||
Equality(Type),
|
||||
Equality(Term),
|
||||
Constraint(Vec<GenericBound>),
|
||||
}
|
||||
|
||||
@ -335,7 +335,7 @@ pub enum GenericParamDefKind {
|
||||
pub enum WherePredicate {
|
||||
BoundPredicate { ty: Type, bounds: Vec<GenericBound> },
|
||||
RegionPredicate { lifetime: String, bounds: Vec<GenericBound> },
|
||||
EqPredicate { lhs: Type, rhs: Type },
|
||||
EqPredicate { lhs: Type, rhs: Term },
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
@ -359,6 +359,13 @@ pub enum TraitBoundModifier {
|
||||
MaybeConst,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum Term {
|
||||
Type(Type),
|
||||
Constant(Constant),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[serde(tag = "kind", content = "inner")]
|
||||
|
21
src/test/ui/associated-consts/assoc-const.rs
Normal file
21
src/test/ui/associated-consts/assoc-const.rs
Normal 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() {}
|
14
src/test/ui/associated-consts/assoc-const.stderr
Normal file
14
src/test/ui/associated-consts/assoc-const.stderr
Normal 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
|
||||
|
@ -7,8 +7,9 @@ struct Bar;
|
||||
const T: usize = 42;
|
||||
|
||||
impl Foo<N = 3> for Bar {
|
||||
//~^ ERROR cannot constrain an associated constant to a value
|
||||
//~^ ERROR this trait takes 1 generic argument but 0 generic arguments were supplied
|
||||
//~| ERROR associated type bindings are not allowed here
|
||||
//~| ERROR associated const equality is incomplete
|
||||
fn do_x(&self) -> [u8; 3] {
|
||||
[0u8; 3]
|
||||
}
|
||||
|
@ -1,11 +1,27 @@
|
||||
error: cannot constrain an associated constant to a value
|
||||
error[E0658]: associated const equality is incomplete
|
||||
--> $DIR/issue-89013-no-kw.rs:9:10
|
||||
|
|
||||
LL | impl Foo<N = 3> for Bar {
|
||||
| -^^^-
|
||||
| | |
|
||||
| | ...cannot be constrained to this value
|
||||
| this associated constant...
|
||||
| ^^^^^
|
||||
|
|
||||
= note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
|
||||
= help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
|
||||
|
||||
error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
|
||||
--> $DIR/issue-89013-no-kw.rs:9:6
|
||||
|
|
||||
LL | impl Foo<N = 3> for Bar {
|
||||
| ^^^ expected 1 generic argument
|
||||
|
|
||||
note: trait defined here, with 1 generic parameter: `N`
|
||||
--> $DIR/issue-89013-no-kw.rs:1:7
|
||||
|
|
||||
LL | trait Foo<const N: usize> {
|
||||
| ^^^ -
|
||||
help: add missing generic argument
|
||||
|
|
||||
LL | impl Foo<N, N = 3> for Bar {
|
||||
| ++
|
||||
|
||||
error[E0229]: associated type bindings are not allowed here
|
||||
--> $DIR/issue-89013-no-kw.rs:9:10
|
||||
@ -13,6 +29,7 @@ error[E0229]: associated type bindings are not allowed here
|
||||
LL | impl Foo<N = 3> for Bar {
|
||||
| ^^^^^ associated type not allowed here
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0229`.
|
||||
Some errors have detailed explanations: E0107, E0229, E0658.
|
||||
For more information about an error, try `rustc --explain E0107`.
|
||||
|
@ -8,8 +8,9 @@ const T: usize = 42;
|
||||
|
||||
impl Foo<N = const 3> for Bar {
|
||||
//~^ ERROR expected lifetime, type, or constant, found keyword `const`
|
||||
//~| ERROR cannot constrain an associated constant to a value
|
||||
//~| ERROR this trait takes 1 generic
|
||||
//~| ERROR associated type bindings are not allowed here
|
||||
//~| ERROR associated const equality is incomplete
|
||||
fn do_x(&self) -> [u8; 3] {
|
||||
[0u8; 3]
|
||||
}
|
||||
|
@ -10,14 +10,30 @@ LL - impl Foo<N = const 3> for Bar {
|
||||
LL + impl Foo<N = 3> for Bar {
|
||||
|
|
||||
|
||||
error: cannot constrain an associated constant to a value
|
||||
error[E0658]: associated const equality is incomplete
|
||||
--> $DIR/issue-89013.rs:9:10
|
||||
|
|
||||
LL | impl Foo<N = const 3> for Bar {
|
||||
| -^^^^^^^^^-
|
||||
| | |
|
||||
| | ...cannot be constrained to this value
|
||||
| this associated constant...
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
|
||||
= help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
|
||||
|
||||
error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
|
||||
--> $DIR/issue-89013.rs:9:6
|
||||
|
|
||||
LL | impl Foo<N = const 3> for Bar {
|
||||
| ^^^ expected 1 generic argument
|
||||
|
|
||||
note: trait defined here, with 1 generic parameter: `N`
|
||||
--> $DIR/issue-89013.rs:1:7
|
||||
|
|
||||
LL | trait Foo<const N: usize> {
|
||||
| ^^^ -
|
||||
help: add missing generic argument
|
||||
|
|
||||
LL | impl Foo<N, N = const 3> for Bar {
|
||||
| ++
|
||||
|
||||
error[E0229]: associated type bindings are not allowed here
|
||||
--> $DIR/issue-89013.rs:9:10
|
||||
@ -25,6 +41,7 @@ error[E0229]: associated type bindings are not allowed here
|
||||
LL | impl Foo<N = const 3> for Bar {
|
||||
| ^^^^^^^^^^^ associated type not allowed here
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0229`.
|
||||
Some errors have detailed explanations: E0107, E0229, E0658.
|
||||
For more information about an error, try `rustc --explain E0107`.
|
||||
|
@ -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>();
|
||||
}
|
@ -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`.
|
@ -1,7 +1,9 @@
|
||||
#[cfg(FALSE)]
|
||||
fn syntax() {
|
||||
bar::<Item = 42>(); //~ ERROR cannot constrain an associated constant to a value
|
||||
bar::<Item = { 42 }>(); //~ ERROR cannot constrain an associated constant to a value
|
||||
bar::<Item = 42>();
|
||||
//~^ ERROR associated const equality is incomplete
|
||||
bar::<Item = { 42 }>();
|
||||
//~^ ERROR associated const equality is incomplete
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,20 +1,21 @@
|
||||
error: cannot constrain an associated constant to a value
|
||||
error[E0658]: associated const equality is incomplete
|
||||
--> $DIR/recover-assoc-const-constraint.rs:3:11
|
||||
|
|
||||
LL | bar::<Item = 42>();
|
||||
| ----^^^--
|
||||
| | |
|
||||
| | ...cannot be constrained to this value
|
||||
| this associated constant...
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
|
||||
= help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
|
||||
|
||||
error: cannot constrain an associated constant to a value
|
||||
--> $DIR/recover-assoc-const-constraint.rs:4:11
|
||||
error[E0658]: associated const equality is incomplete
|
||||
--> $DIR/recover-assoc-const-constraint.rs:5:11
|
||||
|
|
||||
LL | bar::<Item = { 42 }>();
|
||||
| ----^^^------
|
||||
| | |
|
||||
| | ...cannot be constrained to this value
|
||||
| this associated constant...
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
|
||||
= help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
@ -1,4 +1,4 @@
|
||||
error: cannot specialize on `Binder(ProjectionPredicate(ProjectionTy { substs: [V], item_def_id: DefId(0:6 ~ repeated_projection_type[HASH]::Id::This) }, (I,)), [])`
|
||||
error: cannot specialize on `Binder(ProjectionPredicate(ProjectionTy { substs: [V], item_def_id: DefId(0:6 ~ repeated_projection_type[HASH]::Id::This) }, Ty((I,))), [])`
|
||||
--> $DIR/repeated_projection_type.rs:19:1
|
||||
|
|
||||
LL | / impl<I, V: Id<This = (I,)>> X for V {
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 06b9d31743210b788b130c8a484c2838afa6fc27
|
||||
Subproject commit 358e79fe56fe374649275ca7aebaafd57ade0e8d
|
@ -6,7 +6,7 @@ use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_hir::{
|
||||
AsyncGeneratorKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericArg, GenericBound, HirId,
|
||||
Term, AsyncGeneratorKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericArg, GenericBound, HirId,
|
||||
IsAsync, ItemKind, LifetimeName, TraitRef, Ty, TyKind, TypeBindingKind,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
@ -140,7 +140,7 @@ fn future_output_ty<'tcx>(trait_ref: &'tcx TraitRef<'tcx>) -> Option<&'tcx Ty<'t
|
||||
if args.bindings.len() == 1;
|
||||
let binding = &args.bindings[0];
|
||||
if binding.ident.name == sym::Output;
|
||||
if let TypeBindingKind::Equality{ty: output} = binding.kind;
|
||||
if let TypeBindingKind::Equality{term: Term::Ty(output)} = binding.kind;
|
||||
then {
|
||||
return Some(output)
|
||||
}
|
||||
|
@ -2178,12 +2178,16 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
|
||||
// one of the associated types must be Self
|
||||
for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
|
||||
if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() {
|
||||
let assoc_ty = match projection_predicate.term {
|
||||
ty::Term::Ty(ty) => ty,
|
||||
ty::Term::Const(_c) => continue,
|
||||
};
|
||||
// walk the associated type and check for Self
|
||||
if let Some(self_adt) = self_ty.ty_adt_def() {
|
||||
if contains_adt_constructor(projection_predicate.ty, self_adt) {
|
||||
if contains_adt_constructor(assoc_ty, self_adt) {
|
||||
return;
|
||||
}
|
||||
} else if contains_ty(projection_predicate.ty, self_ty) {
|
||||
} else if contains_ty(assoc_ty, self_ty) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -243,9 +243,10 @@ fn check_other_call_arg<'tcx>(
|
||||
if if trait_predicate.def_id() == deref_trait_id {
|
||||
if let [projection_predicate] = projection_predicates[..] {
|
||||
let normalized_ty =
|
||||
cx.tcx.subst_and_normalize_erasing_regions(call_substs, cx.param_env, projection_predicate.ty);
|
||||
cx.tcx.subst_and_normalize_erasing_regions(call_substs, cx.param_env, projection_predicate.term);
|
||||
implements_trait(cx, receiver_ty, deref_trait_id, &[])
|
||||
&& get_associated_type(cx, receiver_ty, deref_trait_id, "Target") == Some(normalized_ty)
|
||||
&& get_associated_type(cx, receiver_ty, deref_trait_id,
|
||||
"Target").map_or(false, |ty| ty::Term::Ty(ty) == normalized_ty)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
@ -98,9 +98,10 @@ fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Ve
|
||||
if trait_pred.self_ty() == inp;
|
||||
if let Some(return_ty_pred) = get_projection_pred(cx, generics, *trait_pred);
|
||||
then {
|
||||
if ord_preds.iter().any(|ord| ord.self_ty() == return_ty_pred.ty) {
|
||||
if ord_preds.iter().any(|ord| Some(ord.self_ty()) ==
|
||||
return_ty_pred.term.ty()) {
|
||||
args_to_check.push((i, "Ord".to_string()));
|
||||
} else if partial_ord_preds.iter().any(|pord| pord.self_ty() == return_ty_pred.ty) {
|
||||
} else if partial_ord_preds.iter().any(|pord| pord.self_ty() == return_ty_pred.term.ty().unwrap()) {
|
||||
args_to_check.push((i, "PartialOrd".to_string()));
|
||||
}
|
||||
}
|
||||
|
@ -645,11 +645,19 @@ pub fn eq_generic_bound(l: &GenericBound, r: &GenericBound) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eq_assoc_constraint(l: &AssocTyConstraint, r: &AssocTyConstraint) -> bool {
|
||||
use AssocTyConstraintKind::*;
|
||||
fn eq_term(l: &Term, r: &Term) -> bool {
|
||||
match (l, r) {
|
||||
(Term::Ty(l), Term::Ty(r)) => eq_ty(l,r),
|
||||
(Term::Const(l), Term::Const(r)) => eq_anon_const(l,r),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eq_assoc_constraint(l: &AssocConstraint, r: &AssocConstraint) -> bool {
|
||||
use AssocConstraintKind::*;
|
||||
eq_id(l.ident, r.ident)
|
||||
&& match (&l.kind, &r.kind) {
|
||||
(Equality { ty: l }, Equality { ty: r }) => eq_ty(l, r),
|
||||
(Equality { term: l }, Equality { term: r }) => eq_term(l, r),
|
||||
(Bound { bounds: l }, Bound { bounds: r }) => over(l, r, eq_generic_bound),
|
||||
_ => false,
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 0f8c96c92689af8378dbe9f466c6bf15a3a27458
|
||||
Subproject commit 8e9ccbf97a70259b6c6576e8fd7d77d28238737e
|
@ -1,7 +1,7 @@
|
||||
use std::iter::ExactSizeIterator;
|
||||
use std::ops::Deref;
|
||||
|
||||
use rustc_ast::ast::{self, FnRetTy, Mutability};
|
||||
use rustc_ast::ast::{self, FnRetTy, Mutability, Term};
|
||||
use rustc_ast::ptr;
|
||||
use rustc_span::{symbol::kw, BytePos, Pos, Span};
|
||||
|
||||
@ -141,7 +141,7 @@ pub(crate) enum SegmentParam<'a> {
|
||||
Const(&'a ast::AnonConst),
|
||||
LifeTime(&'a ast::Lifetime),
|
||||
Type(&'a ast::Ty),
|
||||
Binding(&'a ast::AssocTyConstraint),
|
||||
Binding(&'a ast::AssocConstraint),
|
||||
}
|
||||
|
||||
impl<'a> SegmentParam<'a> {
|
||||
@ -176,9 +176,9 @@ impl<'a> Rewrite for SegmentParam<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl Rewrite for ast::AssocTyConstraint {
|
||||
impl Rewrite for ast::AssocConstraint {
|
||||
fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
|
||||
use ast::AssocTyConstraintKind::{Bound, Equality};
|
||||
use ast::AssocConstraintKind::{Bound, Equality};
|
||||
|
||||
let mut result = String::with_capacity(128);
|
||||
result.push_str(rewrite_ident(context, self.ident));
|
||||
@ -206,11 +206,14 @@ impl Rewrite for ast::AssocTyConstraint {
|
||||
}
|
||||
}
|
||||
|
||||
impl Rewrite for ast::AssocTyConstraintKind {
|
||||
impl Rewrite for ast::AssocConstraintKind {
|
||||
fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
|
||||
match self {
|
||||
ast::AssocTyConstraintKind::Equality { ty } => ty.rewrite(context, shape),
|
||||
ast::AssocTyConstraintKind::Bound { bounds } => bounds.rewrite(context, shape),
|
||||
ast::AssocConstraintKind::Equality { term } => match term {
|
||||
Term::Ty(ty) => ty.rewrite(context, shape),
|
||||
Term::Const(c) => c.rewrite(context, shape),
|
||||
},
|
||||
ast::AssocConstraintKind::Bound { bounds } => bounds.rewrite(context, shape),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user