diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs index dab1e2d525345..6940b4a504584 100644 --- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs +++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs @@ -9,9 +9,7 @@ use rustc_span::{ErrorGuaranteed, Span}; use rustc_trait_selection::traits; use smallvec::SmallVec; -use crate::astconv::{ - AstConv, ConvertedBinding, ConvertedBindingKind, OnlySelfBounds, PredicateFilter, -}; +use crate::astconv::{AstConv, OnlySelfBounds, PredicateFilter}; use crate::bounds::Bounds; use crate::errors; @@ -238,7 +236,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { &self, hir_ref_id: hir::HirId, trait_ref: ty::PolyTraitRef<'tcx>, - binding: &ConvertedBinding<'_, 'tcx>, + binding: &hir::TypeBinding<'tcx>, bounds: &mut Bounds<'tcx>, speculative: bool, dup_bindings: &mut FxIndexMap, @@ -263,21 +261,20 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { let tcx = self.tcx(); - let assoc_kind = - if binding.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation { - ty::AssocKind::Fn - } else if let ConvertedBindingKind::Equality(term) = binding.kind - && let ty::TermKind::Const(_) = term.node.unpack() - { - ty::AssocKind::Const - } else { - ty::AssocKind::Type - }; + let assoc_kind = if binding.gen_args.parenthesized + == hir::GenericArgsParentheses::ReturnTypeNotation + { + ty::AssocKind::Fn + } else if let hir::TypeBindingKind::Equality { term: hir::Term::Const(_) } = binding.kind { + ty::AssocKind::Const + } else { + ty::AssocKind::Type + }; let candidate = if self.trait_defines_associated_item_named( trait_ref.def_id(), assoc_kind, - binding.item_name, + binding.ident, ) { // Simple case: The assoc item is defined in the current trait. trait_ref @@ -289,14 +286,14 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { trait_ref.skip_binder().print_only_trait_name(), None, assoc_kind, - binding.item_name, + binding.ident, path_span, - Some(&binding), + Some(binding), )? }; let (assoc_ident, def_scope) = - tcx.adjust_ident_and_get_scope(binding.item_name, candidate.def_id(), hir_ref_id); + tcx.adjust_ident_and_get_scope(binding.ident, candidate.def_id(), hir_ref_id); // We have already adjusted the item name above, so compare with `.normalize_to_macros_2_0()` // instead of calling `filter_by_name_and_kind` which would needlessly normalize the @@ -312,7 +309,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { .dcx() .struct_span_err( binding.span, - format!("{} `{}` is private", assoc_item.kind, binding.item_name), + format!("{} `{}` is private", assoc_item.kind, binding.ident), ) .with_span_label(binding.span, format!("private {}", assoc_item.kind)) .emit(); @@ -327,7 +324,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { tcx.dcx().emit_err(errors::ValueOfAssociatedStructAlreadySpecified { span: binding.span, prev_span: *prev_span, - item_name: binding.item_name, + item_name: binding.ident, def_path: tcx.def_path_str(assoc_item.container_id(tcx)), }); }) @@ -390,14 +387,12 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { { alias_ty } else { - return Err(self.tcx().dcx().emit_err( - crate::errors::ReturnTypeNotationOnNonRpitit { - span: binding.span, - ty: tcx.liberate_late_bound_regions(assoc_item.def_id, output), - fn_span: tcx.hir().span_if_local(assoc_item.def_id), - note: (), - }, - )); + return Err(tcx.dcx().emit_err(crate::errors::ReturnTypeNotationOnNonRpitit { + span: binding.span, + ty: tcx.liberate_late_bound_regions(assoc_item.def_id, output), + fn_span: tcx.hir().span_if_local(assoc_item.def_id), + note: (), + })); }; // Finally, move the fn return type's bound vars over to account for the early bound @@ -410,9 +405,11 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { let bound_vars = tcx.late_bound_vars(binding.hir_id); ty::Binder::bind_with_vars(instantiation_output, bound_vars) } else { - // Append the generic arguments of the associated type to the `trait_ref`. + // Create the generic arguments for the associated type or constant by joining the + // parent arguments (the arguments of the trait) and the own arguments (the ones of + // the associated item itself) and construct an alias type using them. candidate.map_bound(|trait_ref| { - let ident = Ident::new(assoc_item.name, binding.item_name.span); + let ident = Ident::new(assoc_item.name, binding.ident.span); let item_segment = hir::PathSegment { ident, hir_id: binding.hir_id, @@ -421,77 +418,82 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { infer_args: false, }; - let args_trait_ref_and_assoc_item = self.create_args_for_associated_item( + let alias_args = self.create_args_for_associated_item( path_span, assoc_item.def_id, &item_segment, trait_ref.args, ); + debug!(?alias_args); - debug!(?args_trait_ref_and_assoc_item); - - ty::AliasTy::new(tcx, assoc_item.def_id, args_trait_ref_and_assoc_item) + // Note that we're indeed also using `AliasTy` (alias *type*) for associated + // *constants* to represent *const projections*. Alias *term* would be a more + // appropriate name but alas. + ty::AliasTy::new(tcx, assoc_item.def_id, alias_args) }) }; - if !speculative { - // Find any late-bound regions declared in `ty` that are not - // declared in the trait-ref or assoc_item. These are not well-formed. - // - // Example: - // - // for<'a> ::Item = &'a str // <-- 'a is bad - // for<'a> >::Output = &'a str // <-- 'a is ok - if let ConvertedBindingKind::Equality(ty) = binding.kind { - let late_bound_in_trait_ref = - tcx.collect_constrained_late_bound_regions(&projection_ty); - let late_bound_in_ty = - tcx.collect_referenced_late_bound_regions(&trait_ref.rebind(ty.node)); - debug!(?late_bound_in_trait_ref); - debug!(?late_bound_in_ty); - - // FIXME: point at the type params that don't have appropriate lifetimes: - // struct S1 Fn(&i32, &i32) -> &'a i32>(F); - // ---- ---- ^^^^^^^ - self.validate_late_bound_regions( - late_bound_in_trait_ref, - late_bound_in_ty, - |br_name| { - struct_span_code_err!( - tcx.dcx(), - binding.span, - E0582, - "binding for associated type `{}` references {}, \ - which does not appear in the trait input types", - binding.item_name, - br_name - ) - }, - ); - } - } - match binding.kind { - ConvertedBindingKind::Equality(..) if let ty::AssocKind::Fn = assoc_kind => { - return Err(self.tcx().dcx().emit_err( - crate::errors::ReturnTypeNotationEqualityBound { span: binding.span }, - )); + hir::TypeBindingKind::Equality { .. } if let ty::AssocKind::Fn = assoc_kind => { + return Err(tcx.dcx().emit_err(crate::errors::ReturnTypeNotationEqualityBound { + span: binding.span, + })); } - ConvertedBindingKind::Equality(term) => { + hir::TypeBindingKind::Equality { term } => { + let term = match term { + hir::Term::Ty(ty) => self.ast_ty_to_ty(ty).into(), + hir::Term::Const(ct) => ty::Const::from_anon_const(tcx, ct.def_id).into(), + }; + + if !speculative { + // Find any late-bound regions declared in `ty` that are not + // declared in the trait-ref or assoc_item. These are not well-formed. + // + // Example: + // + // for<'a> ::Item = &'a str // <-- 'a is bad + // for<'a> >::Output = &'a str // <-- 'a is ok + let late_bound_in_projection_ty = + tcx.collect_constrained_late_bound_regions(&projection_ty); + let late_bound_in_term = + tcx.collect_referenced_late_bound_regions(&trait_ref.rebind(term)); + debug!(?late_bound_in_projection_ty); + debug!(?late_bound_in_term); + + // FIXME: point at the type params that don't have appropriate lifetimes: + // struct S1 Fn(&i32, &i32) -> &'a i32>(F); + // ---- ---- ^^^^^^^ + // NOTE(associated_const_equality): This error should be impossible to trigger + // with associated const equality bounds. + self.validate_late_bound_regions( + late_bound_in_projection_ty, + late_bound_in_term, + |br_name| { + struct_span_code_err!( + tcx.dcx(), + binding.span, + E0582, + "binding for associated type `{}` references {}, \ + which does not appear in the trait input types", + binding.ident, + br_name + ) + }, + ); + } + // "Desugar" a constraint like `T: Iterator` this to // the "projection predicate" for: // // `::Item = u32` bounds.push_projection_bound( tcx, - projection_ty.map_bound(|projection_ty| ty::ProjectionPredicate { - projection_ty, - term: term.node, - }), + projection_ty + .map_bound(|projection_ty| ty::ProjectionPredicate { projection_ty, term }), binding.span, ); } - ConvertedBindingKind::Constraint(ast_bounds) => { + hir::TypeBindingKind::Constraint { bounds: ast_bounds } => { // "Desugar" a constraint like `T: Iterator` to // // `::Item: Debug` diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs index ea8d364bba6c1..ad34c31ef8fc7 100644 --- a/compiler/rustc_hir_analysis/src/astconv/errors.rs +++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs @@ -1,4 +1,4 @@ -use crate::astconv::{AstConv, ConvertedBindingKind}; +use crate::astconv::AstConv; use crate::errors::{ self, AssocTypeBindingNotAllowed, ManualImplementation, MissingTypeParams, ParenthesizedFnTraitExpansion, @@ -111,7 +111,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { assoc_kind: ty::AssocKind, assoc_name: Ident, span: Span, - binding: Option<&super::ConvertedBinding<'_, 'tcx>>, + binding: Option<&hir::TypeBinding<'tcx>>, ) -> ErrorGuaranteed where I: Iterator>, @@ -243,7 +243,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { None, ) && suggested_name != assoc_name.name { - // We suggested constraining a type parameter, but the associated type on it + // We suggested constraining a type parameter, but the associated item on it // was also not an exact match, so we also suggest changing it. err.span_suggestion_verbose( assoc_name.span, @@ -258,16 +258,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } } - // If we still couldn't find any associated type, and only one associated type exists, + // If we still couldn't find any associated item, and only one associated item exists, // suggests using it. if let [candidate_name] = all_candidate_names.as_slice() { - // this should still compile, except on `#![feature(associated_type_defaults)]` - // where it could suggests `type A = Self::A`, thus recursing infinitely - let applicability = if tcx.features().associated_type_defaults { - Applicability::Unspecified - } else { - Applicability::MaybeIncorrect - }; + // This should still compile, except on `#![feature(associated_type_defaults)]` + // where it could suggests `type A = Self::A`, thus recursing infinitely. + let applicability = + if assoc_kind == ty::AssocKind::Type && tcx.features().associated_type_defaults { + Applicability::Unspecified + } else { + Applicability::MaybeIncorrect + }; err.sugg = Some(errors::AssocItemNotFoundSugg::Other { span: assoc_name.span, @@ -289,13 +290,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { assoc_kind: ty::AssocKind, ident: Ident, span: Span, - binding: Option<&super::ConvertedBinding<'_, 'tcx>>, + binding: Option<&hir::TypeBinding<'tcx>>, ) -> ErrorGuaranteed { let tcx = self.tcx(); let bound_on_assoc_const_label = if let ty::AssocKind::Const = assoc_item.kind && let Some(binding) = binding - && let ConvertedBindingKind::Constraint(_) = binding.kind + && let hir::TypeBindingKind::Constraint { .. } = binding.kind { let lo = if binding.gen_args.span_ext.is_dummy() { ident.span @@ -309,25 +310,29 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // FIXME(associated_const_equality): This has quite a few false positives and negatives. let wrap_in_braces_sugg = if let Some(binding) = binding - && let ConvertedBindingKind::Equality(term) = binding.kind - && let ty::TermKind::Ty(ty) = term.node.unpack() + && let hir::TypeBindingKind::Equality { term: hir::Term::Ty(hir_ty) } = binding.kind + && let ty = self.ast_ty_to_ty(hir_ty) && (ty.is_enum() || ty.references_error()) && tcx.features().associated_const_equality { Some(errors::AssocKindMismatchWrapInBracesSugg { - lo: term.span.shrink_to_lo(), - hi: term.span.shrink_to_hi(), + lo: hir_ty.span.shrink_to_lo(), + hi: hir_ty.span.shrink_to_hi(), }) } else { None }; // For equality bounds, we want to blame the term (RHS) instead of the item (LHS) since - // one can argue that that's more “untuitive” to the user. + // one can argue that that's more “intuitive” to the user. let (span, expected_because_label, expected, got) = if let Some(binding) = binding - && let ConvertedBindingKind::Equality(term) = binding.kind + && let hir::TypeBindingKind::Equality { term } = binding.kind { - (term.span, Some(ident.span), assoc_item.kind, assoc_kind) + let span = match term { + hir::Term::Ty(ty) => ty.span, + hir::Term::Const(ct) => tcx.def_span(ct.def_id), + }; + (span, Some(ident.span), assoc_item.kind, assoc_kind) } else { (ident.span, None, assoc_kind, assoc_item.kind) }; diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 94c49453cdcf3..3ccf78567edd2 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -35,7 +35,6 @@ use rustc_middle::ty::{ }; use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; use rustc_span::edit_distance::find_best_match_for_name; -use rustc_span::source_map::{respan, Spanned}; use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::{sym, BytePos, Span, DUMMY_SP}; use rustc_target::spec::abi; @@ -151,21 +150,6 @@ pub trait AstConv<'tcx> { fn infcx(&self) -> Option<&InferCtxt<'tcx>>; } -#[derive(Debug)] -struct ConvertedBinding<'a, 'tcx> { - hir_id: hir::HirId, - item_name: Ident, - kind: ConvertedBindingKind<'a, 'tcx>, - gen_args: &'tcx GenericArgs<'tcx>, - span: Span, -} - -#[derive(Debug)] -enum ConvertedBindingKind<'a, 'tcx> { - Equality(Spanned>), - Constraint(&'a [hir::GenericBound<'tcx>]), -} - /// New-typed boolean indicating whether explicit late-bound lifetimes /// are present in a set of generic arguments. /// @@ -316,7 +300,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// Given the type/lifetime/const arguments provided to some path (along with /// an implicit `Self`, if this is a trait reference), returns the complete /// set of generic arguments. This may involve applying defaulted type parameters. - /// Constraints on associated types are created from `create_assoc_bindings_for_generic_args`. + /// + /// Constraints on associated types are not converted here but + /// separately in `add_predicates_for_ast_type_binding`. /// /// Example: /// @@ -329,8 +315,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// 2. The path in question is the path to the trait `std::ops::Index`, /// which will have been resolved to a `def_id` /// 3. The `generic_args` contains info on the `<...>` contents. The `usize` type - /// parameters are returned in the `GenericArgsRef`, the associated type bindings like - /// `Output = u32` are returned from `create_assoc_bindings_for_generic_args`. + /// parameters are returned in the `GenericArgsRef` + /// 4. Associated type bindings like `Output = u32` are contained in `generic_args.bindings`. /// /// Note that the type listing given here is *exactly* what the user provided. /// @@ -591,52 +577,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { (args, arg_count) } - fn create_assoc_bindings_for_generic_args<'a>( - &self, - generic_args: &'a hir::GenericArgs<'tcx>, - ) -> Vec> { - // Convert associated-type bindings or constraints into a separate vector. - // Example: Given this: - // - // T: Iterator - // - // The `T` is passed in as a self-type; the `Item = u32` is - // not a "type parameter" of the `Iterator` trait, but rather - // a restriction on `::Item`, so it is passed - // back separately. - let assoc_bindings = generic_args - .bindings - .iter() - .map(|binding| { - let kind = match &binding.kind { - hir::TypeBindingKind::Equality { term } => match term { - hir::Term::Ty(ty) => ConvertedBindingKind::Equality(respan( - ty.span, - self.ast_ty_to_ty(ty).into(), - )), - hir::Term::Const(c) => { - let span = self.tcx().def_span(c.def_id); - let c = Const::from_anon_const(self.tcx(), c.def_id); - ConvertedBindingKind::Equality(respan(span, c.into())) - } - }, - hir::TypeBindingKind::Constraint { bounds } => { - ConvertedBindingKind::Constraint(bounds) - } - }; - ConvertedBinding { - hir_id: binding.hir_id, - item_name: binding.ident, - kind, - gen_args: binding.gen_args, - span: binding.span, - } - }) - .collect(); - - assoc_bindings - } - pub fn create_args_for_associated_item( &self, span: Span, @@ -742,18 +682,16 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let bound_vars = tcx.late_bound_vars(trait_ref.hir_ref_id); debug!(?bound_vars); - let assoc_bindings = self.create_assoc_bindings_for_generic_args(args); - let poly_trait_ref = ty::Binder::bind_with_vars( ty::TraitRef::new(tcx, trait_def_id, generic_args), bound_vars, ); - debug!(?poly_trait_ref, ?assoc_bindings); + debug!(?poly_trait_ref); bounds.push_trait_bound(tcx, poly_trait_ref, span, polarity); let mut dup_bindings = FxIndexMap::default(); - for binding in &assoc_bindings { + for binding in args.bindings { // Don't register additional associated type bounds for negative bounds, // since we should have emitten an error for them earlier, and they will // not be well-formed! @@ -1029,7 +967,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { assoc_kind: ty::AssocKind, assoc_name: Ident, span: Span, - binding: Option<&ConvertedBinding<'_, 'tcx>>, + binding: Option<&hir::TypeBinding<'tcx>>, ) -> Result, ErrorGuaranteed> where I: Iterator>, @@ -1069,7 +1007,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Provide a more specific error code index entry for equality bindings. err.code( if let Some(binding) = binding - && let ConvertedBindingKind::Equality(_) = binding.kind + && let hir::TypeBindingKind::Equality { .. } = binding.kind { E0222 } else { @@ -1094,16 +1032,21 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ); if let Some(binding) = binding { match binding.kind { - ConvertedBindingKind::Equality(term) => { + hir::TypeBindingKind::Equality { term } => { + let term: ty::Term<'_> = match term { + hir::Term::Ty(ty) => self.ast_ty_to_ty(ty).into(), + hir::Term::Const(ct) => { + ty::Const::from_anon_const(tcx, ct.def_id).into() + } + }; // FIXME(#97583): This isn't syntactically well-formed! where_bounds.push(format!( " T: {trait}::{assoc_name} = {term}", trait = bound.print_only_trait_path(), - term = term.node, )); } // FIXME: Provide a suggestion. - ConvertedBindingKind::Constraint(_bounds) => {} + hir::TypeBindingKind::Constraint { bounds: _ } => {} } } else { err.span_suggestion_verbose(