diff options
| author | bors <bors@rust-lang.org> | 2022-01-18 09:58:39 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2022-01-18 09:58:39 +0000 |
| commit | 7bc7be860f99f4a40d45b0f74e2d01b02e072357 (patch) | |
| tree | bae7d965ae2524594d217ae3022513e7c929ea2c /compiler | |
| parent | 7531d2fdd49966d83830a7b4596c95587b1e9573 (diff) | |
| parent | b77bb5cb2589246cf684431ad2a184466940633d (diff) | |
| download | rust-7bc7be860f99f4a40d45b0f74e2d01b02e072357.tar.gz rust-7bc7be860f99f4a40d45b0f74e2d01b02e072357.zip | |
Auto merge of #87648 - JulianKnodt:const_eq_constrain, r=oli-obk
allow eq constraints on associated constants Updates #70256 (cc `@varkor,` `@Centril)`
Diffstat (limited to 'compiler')
54 files changed, 476 insertions, 252 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 079b9e43373..d0732b35b6e 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -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 }, } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 564a8a8c872..a81a2276295 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -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); } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 0b95270a4e1..73e9297549c 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -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); } } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 7eb08b8754a..47b61067055 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -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 diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 46928a18465..79262235cd9 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -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 { diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 45920bb27d5..eb7c75cac05 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -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, }); diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 85e35c942b9..89671788255 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -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). diff --git a/compiler/rustc_ast_passes/src/node_count.rs b/compiler/rustc_ast_passes/src/node_count.rs index 3980e6da682..a4a48cc8e8a 100644 --- a/compiler/rustc_ast_passes/src/node_count.rs +++ b/compiler/rustc_ast_passes/src/node_count.rs @@ -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; diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index dab2e1f5ee1..17941058ed6 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -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), } } diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 9aa58f05a8e..01cc72121c7 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -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), + }, .. }, ], diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 61322a6e556..9687fd09a53 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -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(); diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index ebd12d6ab4e..47010ea3ab6 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -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. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 369b5e6da2d..43aa0ae265a 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -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"), } } diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 6347a64fa85..cfdcd1618ba 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -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), } } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 7675778ff88..a301c5e3456 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -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); diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 6e6012fdc1a..e98b9c3b03c 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -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(); } } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs index 04eceecc5f0..3fa71d1a3d8 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs @@ -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); } diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 8894093c66c..4851e637d3a 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -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(); } } diff --git a/compiler/rustc_infer/src/infer/projection.rs b/compiler/rustc_infer/src/infer/projection.rs index 9b53ab72b00..b45a6514d79 100644 --- a/compiler/rustc_infer/src/infer/projection.rs +++ b/compiler/rustc_infer/src/infer/projection.rs @@ -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, diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index cb51555f5ca..3921187baa5 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -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, + } } }, }) diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index 8563bac0bbf..2776370ba6f 100644 --- a/compiler/rustc_middle/src/ty/assoc.rs +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -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, diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 75705d40a6c..d6c35dfef88 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -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), + ); + } } } diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index a29a7d241e3..d68c5514821 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -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, }), diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index b6e673983fd..f06a1b09cd8 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -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<'_>) { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index d6e89e52b95..4bc3e23f4a5 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -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. diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 94cd650e39e..bbdaf248a9e 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -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>>>, } diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 9e381cabdfe..bb040acd270 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -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(), }) } } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index a27169d59e1..1c5bc7860db 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -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, }) } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 92fb7612688..20db25f7899 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -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, } } } diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs index 6808316a230..38aa7633385 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -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) diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 7f8fadb33bd..4e60b7593c6 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -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: diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index 5cc958ef549..6cf1aa480d2 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -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) { diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 7bee2ebf2f9..2c968991973 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -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; } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 21f4312de35..075a9764d4c 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -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, diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 14e12bed59e..809b9732529 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -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, &[])?; diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 05d2a373dc6..f2ed5ae26a3 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -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) } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index d1958f85521..0760f626851 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -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, diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 185d64eab70..7bfedecbdc7 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -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, }) diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 577b96f3a40..f49f53351aa 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -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!( diff --git a/compiler/rustc_trait_selection/src/traits/relationships.rs b/compiler/rustc_trait_selection/src/traits/relationships.rs index e0098cc92d5..aea44841b8f 100644 --- a/compiler/rustc_trait_selection/src/traits/relationships.rs +++ b/compiler/rustc_trait_selection/src/traits/relationships.rs @@ -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; } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index f6e98f42710..6a355b567e0 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -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) { diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index 36c536c0ba3..67d0ba39667 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -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), } } } diff --git a/compiler/rustc_typeck/src/astconv/errors.rs b/compiler/rustc_typeck/src/astconv/errors.rs index 1f99a9b0536..b532c41642c 100644 --- a/compiler/rustc_typeck/src/astconv/errors.rs +++ b/compiler/rustc_typeck/src/astconv/errors.rs @@ -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, }) diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 2ada1c0ddf4..7c53e49e280 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -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, diff --git a/compiler/rustc_typeck/src/bounds.rs b/compiler/rustc_typeck/src/bounds.rs index 8bc3a48e5b5..6a28bb16a20 100644 --- a/compiler/rustc_typeck/src/bounds.rs +++ b/compiler/rustc_typeck/src/bounds.rs @@ -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) } } diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs index c87ab0d410c..e88099afa03 100644 --- a/compiler/rustc_typeck/src/check/closure.rs +++ b/compiler/rustc_typeck/src/check/closure.rs @@ -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 diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index 3984d8b7425..94648d5702c 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -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, ) diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index f2fe4403d55..56f4d5afe40 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -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())) diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 059d4a7f3a4..34caabe44d6 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -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() diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 314174e0f85..403aa16689f 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -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>( diff --git a/compiler/rustc_typeck/src/collect/item_bounds.rs b/compiler/rustc_typeck/src/collect/item_bounds.rs index 26cad8fb180..87a67c4a4e0 100644 --- a/compiler/rustc_typeck/src/collect/item_bounds.rs +++ b/compiler/rustc_typeck/src/collect/item_bounds.rs @@ -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)) }) } diff --git a/compiler/rustc_typeck/src/constrained_generic_params.rs b/compiler/rustc_typeck/src/constrained_generic_params.rs index 10952901323..a0c8fc822df 100644 --- a/compiler/rustc_typeck/src/constrained_generic_params.rs +++ b/compiler/rustc_typeck/src/constrained_generic_params.rs @@ -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; } diff --git a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs index 6296f2ab32a..d87e670a8fb 100644 --- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs @@ -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 { diff --git a/compiler/rustc_typeck/src/variance/constraints.rs b/compiler/rustc_typeck/src/variance/constraints.rs index b2b607a2ffc..7c504a0d89c 100644 --- a/compiler/rustc_typeck/src/variance/constraints.rs +++ b/compiler/rustc_typeck/src/variance/constraints.rs @@ -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) + } + } } } |
