diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 277bb7bd3e15c..1138e9774d510 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -37,7 +37,7 @@ hir_analysis_assoc_kind_mismatch = expected {$expected}, found {$got} hir_analysis_assoc_kind_mismatch_wrap_in_braces_sugg = consider adding braces here -hir_analysis_associated_type_trait_uninferred_generic_params = cannot use the associated {$what} of a trait with uninferred generic parameters +hir_analysis_associated_type_trait_uninferred_generic_params = cannot use the {$what} of a trait with uninferred generic parameters .suggestion = use a fully qualified path with inferred lifetimes hir_analysis_associated_type_trait_uninferred_generic_params_multipart_suggestion = use a fully qualified path with explicit lifetimes diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 4520fbe352cea..350bdc7821d5b 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -44,7 +44,6 @@ use rustc_trait_selection::traits::ObligationCtxt; use tracing::{debug, instrument}; use crate::errors; -use crate::hir_ty_lowering::errors::assoc_tag_str; use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer, RegionInferReason}; pub(crate) mod dump; @@ -444,13 +443,12 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { self.tcx.at(span).type_param_predicates((self.item_def_id, def_id, assoc_ident)) } - fn lower_assoc_shared( + fn lower_assoc_item_path( &self, span: Span, item_def_id: DefId, item_segment: &rustc_hir::PathSegment<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>, - assoc_tag: ty::AssocTag, ) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> { if let Some(trait_ref) = poly_trait_ref.no_bound_vars() { let item_args = self.lowerer().lower_generic_args_of_assoc_item( @@ -525,7 +523,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { inferred_sugg, bound, mpart_sugg, - what: assoc_tag_str(assoc_tag), + what: self.tcx.def_descr(item_def_id), })) } } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index bf91eb1b8fdac..106420faa4c01 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -4,9 +4,9 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::struct_span_code_err; use rustc_hir as hir; +use rustc_hir::AmbigArg; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::{AmbigArg, HirId}; use rustc_middle::bug; use rustc_middle::ty::{ self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, @@ -309,7 +309,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { false => "`?Sized`", }; // There was a `?Trait` bound, but it was neither `?Sized` nor `experimental_default_bounds`. - tcx.dcx().span_err( + self.dcx().span_err( unbound.span, format!( "relaxing a default bound only does something for {}; \ @@ -675,7 +675,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // Good error for `where Trait::method(..): Send`. let Some(self_ty) = opt_self_ty else { - let guar = self.error_missing_qpath_self_ty( + let guar = self.report_missing_self_ty_for_resolved_path( trait_def_id, hir_ty.span, item_segment, @@ -713,120 +713,51 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Err(guar) => Ty::new_error(tcx, guar), } } - hir::QPath::TypeRelative(qself, item_segment) - if item_segment.args.is_some_and(|args| { + hir::QPath::TypeRelative(hir_self_ty, segment) + if segment.args.is_some_and(|args| { matches!(args.parenthesized, hir::GenericArgsParentheses::ReturnTypeNotation) }) => { - match self - .resolve_type_relative_return_type_notation( - qself, - item_segment, - hir_ty.hir_id, - hir_ty.span, - ) - .and_then(|(candidate, item_def_id)| { - self.lower_return_type_notation_ty(candidate, item_def_id, hir_ty.span) - }) { - Ok(ty) => Ty::new_alias(tcx, ty::Projection, ty), - Err(guar) => Ty::new_error(tcx, guar), - } - } - _ => self.lower_ty(hir_ty), - } - } - - /// Perform type-dependent lookup for a *method* for return type notation. - /// This generally mirrors `::lower_assoc_path`. - fn resolve_type_relative_return_type_notation( - &self, - qself: &'tcx hir::Ty<'tcx>, - item_segment: &'tcx hir::PathSegment<'tcx>, - qpath_hir_id: HirId, - span: Span, - ) -> Result<(ty::PolyTraitRef<'tcx>, DefId), ErrorGuaranteed> { - let tcx = self.tcx(); - let qself_ty = self.lower_ty(qself); - let assoc_ident = item_segment.ident; - let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind { - path.res - } else { - Res::Err - }; - - let bound = match (qself_ty.kind(), qself_res) { - (_, Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true, .. }) => { - // `Self` in an impl of a trait -- we have a concrete self type and a - // trait reference. - let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) else { - // A cycle error occurred, most likely. - self.dcx().span_bug(span, "expected cycle error"); - }; - - self.probe_single_bound_for_assoc_item( - || { - traits::supertraits( - tcx, - ty::Binder::dummy(trait_ref.instantiate_identity()), - ) - }, - AssocItemQSelf::SelfTyAlias, + let self_ty = self.lower_ty(hir_self_ty); + let (item_def_id, bound) = match self.resolve_type_relative_path( + self_ty, + hir_self_ty, ty::AssocTag::Fn, - assoc_ident, - span, + segment, + hir_ty.hir_id, + hir_ty.span, None, - )? - } - ( - &ty::Param(_), - Res::SelfTyParam { trait_: param_did } | Res::Def(DefKind::TyParam, param_did), - ) => self.probe_single_ty_param_bound_for_assoc_item( - param_did.expect_local(), - qself.span, - ty::AssocTag::Fn, - assoc_ident, - span, - )?, - _ => { - if let Err(reported) = qself_ty.error_reported() { - return Err(reported); - } else { - // FIXME(return_type_notation): Provide some structured suggestion here. - let err = struct_span_code_err!( - self.dcx(), - span, - E0223, - "ambiguous associated function" + ) { + Ok(result) => result, + Err(guar) => return Ty::new_error(tcx, guar), + }; + + // Don't let `T::method` resolve to some `for<'a> >::method`, + // which may happen via a higher-ranked where clause or supertrait. + // This is the same restrictions as associated types; even though we could + // support it, it just makes things a lot more difficult to support in + // `resolve_bound_vars`, since we'd need to introduce those as elided + // bound vars on the where clause too. + if bound.has_bound_vars() { + return Ty::new_error( + tcx, + self.dcx().emit_err(errors::AssociatedItemTraitUninferredGenericParams { + span: hir_ty.span, + inferred_sugg: Some(hir_ty.span.with_hi(segment.ident.span.lo())), + bound: format!("{}::", tcx.anonymize_bound_vars(bound).skip_binder()), + mpart_sugg: None, + what: tcx.def_descr(item_def_id), + }), ); - return Err(err.emit()); } - } - }; - // Don't let `T::method` resolve to some `for<'a> >::method`, - // which may happen via a higher-ranked where clause or supertrait. - // This is the same restrictions as associated types; even though we could - // support it, it just makes things a lot more difficult to support in - // `resolve_bound_vars`, since we'd need to introduce those as elided - // bound vars on the where clause too. - if bound.has_bound_vars() { - return Err(self.tcx().dcx().emit_err( - errors::AssociatedItemTraitUninferredGenericParams { - span, - inferred_sugg: Some(span.with_hi(item_segment.ident.span.lo())), - bound: format!("{}::", tcx.anonymize_bound_vars(bound).skip_binder(),), - mpart_sugg: None, - what: "function", - }, - )); + match self.lower_return_type_notation_ty(bound, item_def_id, hir_ty.span) { + Ok(ty) => Ty::new_alias(tcx, ty::Projection, ty), + Err(guar) => Ty::new_error(tcx, guar), + } + } + _ => self.lower_ty(hir_ty), } - - let trait_def_id = bound.def_id(); - let assoc_ty = self - .probe_assoc_item(assoc_ident, ty::AssocTag::Fn, qpath_hir_id, span, trait_def_id) - .expect("failed to find associated type"); - - Ok((bound, assoc_ty.def_id)) } /// Do the common parts of lowering an RTN type. This involves extending the diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs index d1ee5a5494c00..ebeb3b58208eb 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs @@ -35,7 +35,7 @@ pub(crate) fn validate_cmse_abi<'tcx>( _ => tcx.hir_span(hir_id), }; struct_span_code_err!( - tcx.dcx(), + dcx, span, E0781, "the `\"C-cmse-nonsecure-call\"` ABI is only allowed on function pointers" diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index 88f745892048c..f411bf4d6102d 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -78,15 +78,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // We don't support empty trait objects. if regular_traits.is_empty() && auto_traits.is_empty() { - let guar = self.report_trait_object_with_no_traits_error( - span, - user_written_bounds.iter().copied(), - ); + let guar = + self.report_trait_object_with_no_traits(span, user_written_bounds.iter().copied()); return Ty::new_error(tcx, guar); } // We don't support >1 principal if regular_traits.len() > 1 { - let guar = self.report_trait_object_addition_traits_error(®ular_traits); + let guar = self.report_trait_object_addition_traits(®ular_traits); return Ty::new_error(tcx, guar); } // Don't create a dyn trait if we have errors in the principal. @@ -132,7 +130,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { if references_self { // With trait alias and type alias combined, type resolver // may not be able to catch all illegal `Self` usages (issue 139082) - let guar = tcx.dcx().emit_err(SelfInTypeAlias { span }); + let guar = self.dcx().emit_err(SelfInTypeAlias { span }); b.term = replace_dummy_self_with_error(tcx, b.term, guar); } } @@ -344,7 +342,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id) && hir_bound.span.contains(span) }); - self.complain_about_missing_type_params( + self.report_missing_type_params( missing_type_params, trait_ref.def_id, span, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 3759a224ff75b..45fee0fa4024e 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -3,11 +3,12 @@ use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::unord::UnordMap; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, ErrorGuaranteed, MultiSpan, listify, pluralize, struct_span_code_err, + Applicability, Diag, ErrorGuaranteed, MultiSpan, SuggestionStyle, listify, pluralize, + struct_span_code_err, }; -use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; +use rustc_hir::{self as hir, HirId}; use rustc_middle::bug; use rustc_middle::ty::fast_reject::{TreatParams, simplify_type}; use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _}; @@ -23,6 +24,7 @@ use rustc_trait_selection::traits::{ FulfillmentError, dyn_compatibility_violations_for_assoc_item, }; use smallvec::SmallVec; +use tracing::debug; use crate::errors::{ self, AssocItemConstraintsNotAllowedHere, ManualImplementation, MissingTypeParams, @@ -34,7 +36,7 @@ use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer}; impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// On missing type parameters, emit an E0393 error and provide a structured suggestion using /// the type parameter's name as a placeholder. - pub(crate) fn complain_about_missing_type_params( + pub(crate) fn report_missing_type_params( &self, missing_type_params: Vec, def_id: DefId, @@ -56,7 +58,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// When the code is using the `Fn` traits directly, instead of the `Fn(A) -> B` syntax, emit /// an error and attempt to build a reasonable structured suggestion. - pub(crate) fn complain_about_internal_fn_trait( + pub(crate) fn report_internal_fn_trait( &self, span: Span, trait_def_id: DefId, @@ -112,7 +114,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - pub(super) fn complain_about_assoc_item_not_found( + pub(super) fn report_unresolved_assoc_item( &self, all_candidates: impl Fn() -> I, qself: AssocItemQSelf, @@ -132,7 +134,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .filter_by_name_unhygienic(assoc_ident.name) .find(|item| tcx.hygienic_eq(assoc_ident, item.ident(tcx), r.def_id())) }) { - return self.complain_about_assoc_kind_mismatch( + return self.report_assoc_kind_mismatch( assoc_item, assoc_tag, assoc_ident, @@ -331,7 +333,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self.dcx().emit_err(err) } - fn complain_about_assoc_kind_mismatch( + fn report_assoc_kind_mismatch( &self, assoc_item: &ty::AssocItem, assoc_tag: ty::AssocTag, @@ -396,12 +398,177 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }) } - pub(super) fn report_ambiguous_assoc( + pub(crate) fn report_missing_self_ty_for_resolved_path( + &self, + trait_def_id: DefId, + span: Span, + item_segment: &hir::PathSegment<'tcx>, + assoc_tag: ty::AssocTag, + ) -> ErrorGuaranteed { + let tcx = self.tcx(); + let path_str = tcx.def_path_str(trait_def_id); + + let def_id = self.item_def_id(); + debug!(item_def_id = ?def_id); + + // FIXME: document why/how this is different from `tcx.local_parent(def_id)` + let parent_def_id = tcx.hir_get_parent_item(tcx.local_def_id_to_hir_id(def_id)).to_def_id(); + debug!(?parent_def_id); + + // If the trait in segment is the same as the trait defining the item, + // use the `` syntax in the error. + let is_part_of_self_trait_constraints = def_id.to_def_id() == trait_def_id; + let is_part_of_fn_in_self_trait = parent_def_id == trait_def_id; + + let type_names = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait { + vec!["Self".to_string()] + } else { + // Find all the types that have an `impl` for the trait. + tcx.all_impls(trait_def_id) + .filter_map(|impl_def_id| tcx.impl_trait_header(impl_def_id)) + .filter(|header| { + // Consider only accessible traits + tcx.visibility(trait_def_id).is_accessible_from(self.item_def_id(), tcx) + && header.polarity != ty::ImplPolarity::Negative + }) + .map(|header| header.trait_ref.instantiate_identity().self_ty()) + // We don't care about blanket impls. + .filter(|self_ty| !self_ty.has_non_region_param()) + .map(|self_ty| tcx.erase_regions(self_ty).to_string()) + .collect() + }; + // FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that + // references the trait. Relevant for the first case in + // `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs` + self.report_ambiguous_assoc_item_path( + span, + &type_names, + &[path_str], + item_segment.ident, + assoc_tag, + ) + } + + pub(super) fn report_unresolved_type_relative_path( + &self, + self_ty: Ty<'tcx>, + hir_self_ty: &hir::Ty<'_>, + assoc_tag: ty::AssocTag, + ident: Ident, + qpath_hir_id: HirId, + span: Span, + variant_def_id: Option, + ) -> ErrorGuaranteed { + let tcx = self.tcx(); + let kind_str = assoc_tag_str(assoc_tag); + if variant_def_id.is_some() { + // Variant in type position + let msg = format!("expected {kind_str}, found variant `{ident}`"); + self.dcx().span_err(span, msg) + } else if self_ty.is_enum() { + let mut err = self.dcx().create_err(errors::NoVariantNamed { + span: ident.span, + ident, + ty: self_ty, + }); + + let adt_def = self_ty.ty_adt_def().expect("enum is not an ADT"); + if let Some(variant_name) = find_best_match_for_name( + &adt_def.variants().iter().map(|variant| variant.name).collect::>(), + ident.name, + None, + ) && let Some(variant) = adt_def.variants().iter().find(|s| s.name == variant_name) + { + let mut suggestion = vec![(ident.span, variant_name.to_string())]; + if let hir::Node::Stmt(&hir::Stmt { kind: hir::StmtKind::Semi(expr), .. }) + | hir::Node::Expr(expr) = tcx.parent_hir_node(qpath_hir_id) + && let hir::ExprKind::Struct(..) = expr.kind + { + match variant.ctor { + None => { + // struct + suggestion = vec![( + ident.span.with_hi(expr.span.hi()), + if variant.fields.is_empty() { + format!("{variant_name} {{}}") + } else { + format!( + "{variant_name} {{ {} }}", + variant + .fields + .iter() + .map(|f| format!("{}: /* value */", f.name)) + .collect::>() + .join(", ") + ) + }, + )]; + } + Some((hir::def::CtorKind::Fn, def_id)) => { + // tuple + let fn_sig = tcx.fn_sig(def_id).instantiate_identity(); + let inputs = fn_sig.inputs().skip_binder(); + suggestion = vec![( + ident.span.with_hi(expr.span.hi()), + format!( + "{variant_name}({})", + inputs + .iter() + .map(|i| format!("/* {i} */")) + .collect::>() + .join(", ") + ), + )]; + } + Some((hir::def::CtorKind::Const, _)) => { + // unit + suggestion = vec![( + ident.span.with_hi(expr.span.hi()), + variant_name.to_string(), + )]; + } + } + } + err.multipart_suggestion_verbose( + "there is a variant with a similar name", + suggestion, + Applicability::HasPlaceholders, + ); + } else { + err.span_label(ident.span, format!("variant not found in `{self_ty}`")); + } + + if let Some(sp) = tcx.hir_span_if_local(adt_def.did()) { + err.span_label(sp, format!("variant `{ident}` not found here")); + } + + err.emit() + } else if let Err(reported) = self_ty.error_reported() { + reported + } else { + match self.maybe_report_similar_assoc_fn(span, self_ty, hir_self_ty) { + Ok(()) => {} + Err(reported) => return reported, + } + + let traits: Vec<_> = self.probe_traits_that_match_assoc_ty(self_ty, ident); + + self.report_ambiguous_assoc_item_path( + span, + &[self_ty.to_string()], + &traits, + ident, + assoc_tag, + ) + } + } + + pub(super) fn report_ambiguous_assoc_item_path( &self, span: Span, types: &[String], traits: &[String], - name: Symbol, + ident: Ident, assoc_tag: ty::AssocTag, ) -> ErrorGuaranteed { let kind_str = assoc_tag_str(assoc_tag); @@ -421,6 +588,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Applicability::MachineApplicable, ); } else { + let sugg_sp = span.until(ident.span); + let mut types = types.to_vec(); types.sort(); let mut traits = traits.to_vec(); @@ -428,76 +597,79 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { match (&types[..], &traits[..]) { ([], []) => { err.span_suggestion_verbose( - span, + sugg_sp, format!( "if there were a type named `Type` that implements a trait named \ - `Trait` with associated {kind_str} `{name}`, you could use the \ + `Trait` with associated {kind_str} `{ident}`, you could use the \ fully-qualified path", ), - format!("::{name}"), + "::", Applicability::HasPlaceholders, ); } ([], [trait_str]) => { err.span_suggestion_verbose( - span, + sugg_sp, format!( "if there were a type named `Example` that implemented `{trait_str}`, \ you could use the fully-qualified path", ), - format!("::{name}"), + format!("::"), Applicability::HasPlaceholders, ); } ([], traits) => { - err.span_suggestions( - span, + err.span_suggestions_with_style( + sugg_sp, format!( "if there were a type named `Example` that implemented one of the \ - traits with associated {kind_str} `{name}`, you could use the \ + traits with associated {kind_str} `{ident}`, you could use the \ fully-qualified path", ), - traits.iter().map(|trait_str| format!("::{name}")), + traits.iter().map(|trait_str| format!("::")), Applicability::HasPlaceholders, + SuggestionStyle::ShowAlways, ); } ([type_str], []) => { err.span_suggestion_verbose( - span, + sugg_sp, format!( - "if there were a trait named `Example` with associated {kind_str} `{name}` \ + "if there were a trait named `Example` with associated {kind_str} `{ident}` \ implemented for `{type_str}`, you could use the fully-qualified path", ), - format!("<{type_str} as Example>::{name}"), + format!("<{type_str} as Example>::"), Applicability::HasPlaceholders, ); } (types, []) => { - err.span_suggestions( - span, + err.span_suggestions_with_style( + sugg_sp, format!( - "if there were a trait named `Example` with associated {kind_str} `{name}` \ + "if there were a trait named `Example` with associated {kind_str} `{ident}` \ implemented for one of the types, you could use the fully-qualified \ path", ), types .into_iter() - .map(|type_str| format!("<{type_str} as Example>::{name}")), + .map(|type_str| format!("<{type_str} as Example>::")), Applicability::HasPlaceholders, + SuggestionStyle::ShowAlways, ); } (types, traits) => { let mut suggestions = vec![]; for type_str in types { for trait_str in traits { - suggestions.push(format!("<{type_str} as {trait_str}>::{name}")); + suggestions.push(format!("<{type_str} as {trait_str}>::")); } } - err.span_suggestions( - span, + err.span_suggestions_with_style( + sugg_sp, "use fully-qualified syntax", suggestions, Applicability::MachineApplicable, + SuggestionStyle::ShowAlways, ); } } @@ -505,7 +677,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { err.emit() } - pub(crate) fn complain_about_ambiguous_inherent_assoc( + pub(crate) fn report_ambiguous_inherent_assoc_item( &self, name: Ident, candidates: Vec, @@ -518,12 +690,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { "multiple applicable items in scope" ); err.span_label(name.span, format!("multiple `{name}` found")); - self.note_ambiguous_inherent_assoc_ty(&mut err, candidates, span); + self.note_ambiguous_inherent_assoc_item(&mut err, candidates, span); err.emit() } // FIXME(fmease): Heavily adapted from `rustc_hir_typeck::method::suggest`. Deduplicate. - fn note_ambiguous_inherent_assoc_ty( + fn note_ambiguous_inherent_assoc_item( &self, err: &mut Diag<'_>, candidates: Vec, @@ -566,7 +738,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } // FIXME(inherent_associated_types): Find similarly named associated types and suggest them. - pub(crate) fn complain_about_inherent_assoc_not_found( + pub(crate) fn report_unresolved_inherent_assoc_item( &self, name: Ident, self_ty: Ty<'tcx>, @@ -1046,7 +1218,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - pub fn report_prohibit_generics_error<'a>( + pub fn report_prohibited_generic_args<'a>( &self, segments: impl Iterator> + Clone, args_visitors: impl Iterator> + Clone, @@ -1128,7 +1300,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { err.emit() } - pub fn report_trait_object_addition_traits_error( + pub fn report_trait_object_addition_traits( &self, regular_traits: &Vec<(ty::PolyTraitPredicate<'tcx>, SmallVec<[Span; 1]>)>, ) -> ErrorGuaranteed { @@ -1171,7 +1343,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { err.emit() } - pub fn report_trait_object_with_no_traits_error( + pub fn report_trait_object_with_no_traits( &self, span: Span, user_written_clauses: impl IntoIterator, Span)>, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs index 483b61add3380..1f4692b19f1ad 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs @@ -103,7 +103,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // In case there is an associated type with the same name // Add the suggestion to this error if let Some(mut sugg) = - tcx.dcx().steal_non_err(self_ty.span, StashKey::AssociatedTypeSuggestion) + self.dcx().steal_non_err(self_ty.span, StashKey::AssociatedTypeSuggestion) && let Suggestions::Enabled(ref mut s1) = diag.suggestions && let Suggestions::Enabled(ref mut s2) = sugg.suggestions { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 5e79e93201531..6b21bbbfcd809 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -38,22 +38,20 @@ use rustc_middle::middle::stability::AllowUnstable; use rustc_middle::mir::interpret::LitToConstInput; use rustc_middle::ty::print::PrintPolyTraitRefExt as _; use rustc_middle::ty::{ - self, AssocTag, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, - TyCtxt, TypeVisitableExt, TypingMode, Upcast, fold_regions, + self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, TyCtxt, + TypeVisitableExt, TypingMode, Upcast, fold_regions, }; use rustc_middle::{bug, span_bug}; use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; use rustc_session::parse::feature_err; -use rustc_span::edit_distance::find_best_match_for_name; -use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; +use rustc_span::{DUMMY_SP, Ident, Span, kw, sym}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::wf::object_region_bounds; use rustc_trait_selection::traits::{self, ObligationCtxt}; use tracing::{debug, instrument}; -use self::errors::assoc_tag_str; use crate::check::check_abi_fn_ptr; -use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, NoVariantNamed}; +use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation}; use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint}; use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args}; use crate::middle::resolve_bound_vars as rbv; @@ -150,7 +148,7 @@ pub trait HirTyLowerer<'tcx> { assoc_ident: Ident, ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]>; - /// Lower an associated type/const (from a trait) to a projection. + /// Lower a path to an associated item (of a trait) to a projection. /// /// This method has to be defined by the concrete lowering context because /// dealing with higher-ranked trait references depends on its capabilities: @@ -162,13 +160,12 @@ pub trait HirTyLowerer<'tcx> { /// /// The canonical example of this is associated type `T::P` where `T` is a type /// param constrained by `T: for<'a> Trait<'a>` and where `Trait` defines `P`. - fn lower_assoc_shared( + fn lower_assoc_item_path( &self, span: Span, item_def_id: DefId, item_segment: &hir::PathSegment<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>, - assoc_tag: ty::AssocTag, ) -> Result<(DefId, GenericArgsRef<'tcx>), ErrorGuaranteed>; fn lower_fn_sig( @@ -245,39 +242,46 @@ pub enum FeedConstTy<'a, 'tcx> { } #[derive(Debug, Clone, Copy)] -enum LowerAssocMode { - Type { permit_variants: bool }, +enum LowerTypeRelativePathMode { + Type(PermitVariants), Const, } -impl LowerAssocMode { +impl LowerTypeRelativePathMode { fn assoc_tag(self) -> ty::AssocTag { match self { - LowerAssocMode::Type { .. } => ty::AssocTag::Type, - LowerAssocMode::Const => ty::AssocTag::Const, + Self::Type(_) => ty::AssocTag::Type, + Self::Const => ty::AssocTag::Const, } } fn def_kind(self) -> DefKind { match self { - LowerAssocMode::Type { .. } => DefKind::AssocTy, - LowerAssocMode::Const => DefKind::AssocConst, + Self::Type(_) => DefKind::AssocTy, + Self::Const => DefKind::AssocConst, } } - fn permit_variants(self) -> bool { + fn permit_variants(self) -> PermitVariants { match self { - LowerAssocMode::Type { permit_variants } => permit_variants, + Self::Type(permit_variants) => permit_variants, // FIXME(mgca): Support paths like `Option::::None` or `Option::::Some` which // resolve to const ctors/fn items respectively. - LowerAssocMode::Const => false, + Self::Const => PermitVariants::No, } } } +/// Whether to permit a path to resolve to an enum variant. #[derive(Debug, Clone, Copy)] -enum LoweredAssoc<'tcx> { - Term(DefId, GenericArgsRef<'tcx>), +pub enum PermitVariants { + Yes, + No, +} + +#[derive(Debug, Clone, Copy)] +enum TypeRelativePath<'tcx> { + AssocItem(DefId, GenericArgsRef<'tcx>), Variant { adt: Ty<'tcx>, variant_did: DefId }, } @@ -745,7 +749,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { trait_ref.path.segments.split_last().unwrap().1.iter(), GenericsArgsErrExtend::None, ); - self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, false); + self.report_internal_fn_trait(span, trait_def_id, trait_segment, false); let (generic_args, arg_count) = self.lower_generic_args_of_path( trait_ref.path.span, @@ -920,7 +924,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { trait_segment: &hir::PathSegment<'tcx>, is_impl: bool, ) -> ty::TraitRef<'tcx> { - self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, is_impl); + self.report_internal_fn_trait(span, trait_def_id, trait_segment, is_impl); let (generic_args, _) = self.lower_generic_args_of_path(span, trait_def_id, &[], trait_segment, Some(self_ty)); @@ -933,7 +937,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { fn probe_trait_that_defines_assoc_item( &self, trait_def_id: DefId, - assoc_tag: AssocTag, + assoc_tag: ty::AssocTag, assoc_ident: Ident, ) -> bool { self.tcx() @@ -976,7 +980,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, ty_param_def_id: LocalDefId, ty_param_span: Span, - assoc_tag: AssocTag, + assoc_tag: ty::AssocTag, assoc_ident: Ident, span: Span, ) -> Result, ErrorGuaranteed> { @@ -1011,7 +1015,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, all_candidates: impl Fn() -> I, qself: AssocItemQSelf, - assoc_tag: AssocTag, + assoc_tag: ty::AssocTag, assoc_ident: Ident, span: Span, constraint: Option<&hir::AssocItemConstraint<'tcx>>, @@ -1026,15 +1030,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }); let Some(bound) = matching_candidates.next() else { - let reported = self.complain_about_assoc_item_not_found( + return Err(self.report_unresolved_assoc_item( all_candidates, qself, assoc_tag, assoc_ident, span, constraint, - ); - return Err(reported); + )); }; debug!(?bound); @@ -1127,7 +1130,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Ok(bound) } - /// Lower a [type-relative] path referring to an associated type or to an enum variant. + /// Lower a [type-relative](hir::QPath::TypeRelative) path in type position to a type. /// /// If the path refers to an enum variant and `permit_variants` holds, /// the returned type is simply the provided self type `qself_ty`. @@ -1148,61 +1151,63 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// described in the previous paragraph and their modeling of projections would likely be /// very similar in nature. /// - /// [type-relative]: hir::QPath::TypeRelative /// [#22519]: https://github.com/rust-lang/rust/issues/22519 /// [iat]: https://github.com/rust-lang/rust/issues/8995#issuecomment-1569208403 // // NOTE: When this function starts resolving `Trait::AssocTy` successfully // it should also start reporting the `BARE_TRAIT_OBJECTS` lint. #[instrument(level = "debug", skip_all, ret)] - pub fn lower_assoc_path_ty( + pub fn lower_type_relative_ty_path( &self, - hir_ref_id: HirId, + self_ty: Ty<'tcx>, + hir_self_ty: &'tcx hir::Ty<'tcx>, + segment: &'tcx hir::PathSegment<'tcx>, + qpath_hir_id: HirId, span: Span, - qself_ty: Ty<'tcx>, - qself: &'tcx hir::Ty<'tcx>, - assoc_segment: &'tcx hir::PathSegment<'tcx>, - permit_variants: bool, + permit_variants: PermitVariants, ) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> { let tcx = self.tcx(); - match self.lower_assoc_path_shared( - hir_ref_id, + match self.lower_type_relative_path( + self_ty, + hir_self_ty, + segment, + qpath_hir_id, span, - qself_ty, - qself, - assoc_segment, - LowerAssocMode::Type { permit_variants }, + LowerTypeRelativePathMode::Type(permit_variants), )? { - LoweredAssoc::Term(def_id, args) => { + TypeRelativePath::AssocItem(def_id, args) => { let alias_ty = ty::AliasTy::new_from_args(tcx, def_id, args); let ty = Ty::new_alias(tcx, alias_ty.kind(tcx), alias_ty); Ok((ty, tcx.def_kind(def_id), def_id)) } - LoweredAssoc::Variant { adt, variant_did } => Ok((adt, DefKind::Variant, variant_did)), + TypeRelativePath::Variant { adt, variant_did } => { + Ok((adt, DefKind::Variant, variant_did)) + } } } + /// Lower a [type-relative][hir::QPath::TypeRelative] path to a (type-level) constant. #[instrument(level = "debug", skip_all, ret)] - fn lower_assoc_path_const( + fn lower_type_relative_const_path( &self, - hir_ref_id: HirId, + self_ty: Ty<'tcx>, + hir_self_ty: &'tcx hir::Ty<'tcx>, + segment: &'tcx hir::PathSegment<'tcx>, + qpath_hir_id: HirId, span: Span, - qself_ty: Ty<'tcx>, - qself: &'tcx hir::Ty<'tcx>, - assoc_segment: &'tcx hir::PathSegment<'tcx>, ) -> Result, ErrorGuaranteed> { let tcx = self.tcx(); - let (def_id, args) = match self.lower_assoc_path_shared( - hir_ref_id, + let (def_id, args) = match self.lower_type_relative_path( + self_ty, + hir_self_ty, + segment, + qpath_hir_id, span, - qself_ty, - qself, - assoc_segment, - LowerAssocMode::Const, + LowerTypeRelativePathMode::Const, )? { - LoweredAssoc::Term(def_id, args) => { + TypeRelativePath::AssocItem(def_id, args) => { if !tcx.associated_item(def_id).is_type_const_capable(tcx) { - let mut err = tcx.dcx().struct_span_err( + let mut err = self.dcx().struct_span_err( span, "use of trait associated const without `#[type_const]`", ); @@ -1213,75 +1218,134 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } // FIXME(mgca): implement support for this once ready to support all adt ctor expressions, // not just const ctors - LoweredAssoc::Variant { .. } => { + TypeRelativePath::Variant { .. } => { span_bug!(span, "unexpected variant res for type associated const path") } }; Ok(Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(def_id, args))) } + /// Lower a [type-relative][hir::QPath::TypeRelative] (and type-level) path. #[instrument(level = "debug", skip_all, ret)] - fn lower_assoc_path_shared( + fn lower_type_relative_path( &self, - hir_ref_id: HirId, + self_ty: Ty<'tcx>, + hir_self_ty: &'tcx hir::Ty<'tcx>, + segment: &'tcx hir::PathSegment<'tcx>, + qpath_hir_id: HirId, span: Span, - qself_ty: Ty<'tcx>, - qself: &'tcx hir::Ty<'tcx>, - assoc_segment: &'tcx hir::PathSegment<'tcx>, - mode: LowerAssocMode, - ) -> Result, ErrorGuaranteed> { - debug!(%qself_ty, ?assoc_segment.ident); + mode: LowerTypeRelativePathMode, + ) -> Result, ErrorGuaranteed> { + debug!(%self_ty, ?segment.ident); let tcx = self.tcx(); - let assoc_ident = assoc_segment.ident; - // Check if we have an enum variant or an inherent associated type. - let mut variant_resolution = None; - if let Some(adt_def) = self.probe_adt(span, qself_ty) { + let mut variant_def_id = None; + if let Some(adt_def) = self.probe_adt(span, self_ty) { if adt_def.is_enum() { let variant_def = adt_def .variants() .iter() - .find(|vd| tcx.hygienic_eq(assoc_ident, vd.ident(tcx), adt_def.did())); + .find(|vd| tcx.hygienic_eq(segment.ident, vd.ident(tcx), adt_def.did())); if let Some(variant_def) = variant_def { - if mode.permit_variants() { - tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span, None); + if let PermitVariants::Yes = mode.permit_variants() { + tcx.check_stability(variant_def.def_id, Some(qpath_hir_id), span, None); let _ = self.prohibit_generic_args( - slice::from_ref(assoc_segment).iter(), - GenericsArgsErrExtend::EnumVariant { qself, assoc_segment, adt_def }, + slice::from_ref(segment).iter(), + GenericsArgsErrExtend::EnumVariant { + qself: hir_self_ty, + assoc_segment: segment, + adt_def, + }, ); - return Ok(LoweredAssoc::Variant { - adt: qself_ty, + return Ok(TypeRelativePath::Variant { + adt: self_ty, variant_did: variant_def.def_id, }); } else { - variant_resolution = Some(variant_def.def_id); + variant_def_id = Some(variant_def.def_id); } } } // FIXME(inherent_associated_types, #106719): Support self types other than ADTs. - if let Some((did, args)) = self.probe_inherent_assoc_shared( - assoc_segment, + if let Some((did, args)) = self.probe_inherent_assoc_item( + segment, adt_def.did(), - qself_ty, - hir_ref_id, + self_ty, + qpath_hir_id, span, mode.assoc_tag(), )? { - return Ok(LoweredAssoc::Term(did, args)); + return Ok(TypeRelativePath::AssocItem(did, args)); } } - let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind { - path.res - } else { - Res::Err + let (item_def_id, bound) = self.resolve_type_relative_path( + self_ty, + hir_self_ty, + mode.assoc_tag(), + segment, + qpath_hir_id, + span, + variant_def_id, + )?; + + let (item_def_id, args) = self.lower_assoc_item_path(span, item_def_id, segment, bound)?; + + if let Some(variant_def_id) = variant_def_id { + tcx.node_span_lint(AMBIGUOUS_ASSOCIATED_ITEMS, qpath_hir_id, span, |lint| { + lint.primary_message("ambiguous associated item"); + let mut could_refer_to = |kind: DefKind, def_id, also| { + let note_msg = format!( + "`{}` could{} refer to the {} defined here", + segment.ident, + also, + tcx.def_kind_descr(kind, def_id) + ); + lint.span_note(tcx.def_span(def_id), note_msg); + }; + + could_refer_to(DefKind::Variant, variant_def_id, ""); + could_refer_to(mode.def_kind(), item_def_id, " also"); + + lint.span_suggestion( + span, + "use fully-qualified syntax", + format!( + "<{} as {}>::{}", + self_ty, + tcx.item_name(bound.def_id()), + segment.ident + ), + Applicability::MachineApplicable, + ); + }); + } + + Ok(TypeRelativePath::AssocItem(item_def_id, args)) + } + + /// Resolve a [type-relative](hir::QPath::TypeRelative) (and type-level) path. + fn resolve_type_relative_path( + &self, + self_ty: Ty<'tcx>, + hir_self_ty: &'tcx hir::Ty<'tcx>, + assoc_tag: ty::AssocTag, + segment: &'tcx hir::PathSegment<'tcx>, + qpath_hir_id: HirId, + span: Span, + variant_def_id: Option, + ) -> Result<(DefId, ty::PolyTraitRef<'tcx>), ErrorGuaranteed> { + let tcx = self.tcx(); + + let self_ty_res = match hir_self_ty.kind { + hir::TyKind::Path(hir::QPath::Resolved(_, path)) => path.res, + _ => Res::Err, }; - // Find the type of the associated item, and the trait where the associated - // item is declared. - let bound = match (qself_ty.kind(), qself_res) { + // Find the type of the assoc item, and the trait where the associated item is declared. + let bound = match (self_ty.kind(), self_ty_res) { (_, Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true, .. }) => { // `Self` in an impl of a trait -- we have a concrete self type and a // trait reference. @@ -1292,14 +1356,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self.probe_single_bound_for_assoc_item( || { - traits::supertraits( - tcx, - ty::Binder::dummy(trait_ref.instantiate_identity()), - ) + let trait_ref = ty::Binder::dummy(trait_ref.instantiate_identity()); + traits::supertraits(tcx, trait_ref) }, AssocItemQSelf::SelfTyAlias, - mode.assoc_tag(), - assoc_ident, + assoc_tag, + segment.ident, span, None, )? @@ -1309,167 +1371,33 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Res::SelfTyParam { trait_: param_did } | Res::Def(DefKind::TyParam, param_did), ) => self.probe_single_ty_param_bound_for_assoc_item( param_did.expect_local(), - qself.span, - mode.assoc_tag(), - assoc_ident, + hir_self_ty.span, + assoc_tag, + segment.ident, span, )?, _ => { - let kind_str = assoc_tag_str(mode.assoc_tag()); - let reported = if variant_resolution.is_some() { - // Variant in type position - let msg = format!("expected {kind_str}, found variant `{assoc_ident}`"); - self.dcx().span_err(span, msg) - } else if qself_ty.is_enum() { - let mut err = self.dcx().create_err(NoVariantNamed { - span: assoc_ident.span, - ident: assoc_ident, - ty: qself_ty, - }); - - let adt_def = qself_ty.ty_adt_def().expect("enum is not an ADT"); - if let Some(variant_name) = find_best_match_for_name( - &adt_def - .variants() - .iter() - .map(|variant| variant.name) - .collect::>(), - assoc_ident.name, - None, - ) && let Some(variant) = - adt_def.variants().iter().find(|s| s.name == variant_name) - { - let mut suggestion = vec![(assoc_ident.span, variant_name.to_string())]; - if let hir::Node::Stmt(&hir::Stmt { - kind: hir::StmtKind::Semi(expr), .. - }) - | hir::Node::Expr(expr) = tcx.parent_hir_node(hir_ref_id) - && let hir::ExprKind::Struct(..) = expr.kind - { - match variant.ctor { - None => { - // struct - suggestion = vec![( - assoc_ident.span.with_hi(expr.span.hi()), - if variant.fields.is_empty() { - format!("{variant_name} {{}}") - } else { - format!( - "{variant_name} {{ {} }}", - variant - .fields - .iter() - .map(|f| format!("{}: /* value */", f.name)) - .collect::>() - .join(", ") - ) - }, - )]; - } - Some((hir::def::CtorKind::Fn, def_id)) => { - // tuple - let fn_sig = tcx.fn_sig(def_id).instantiate_identity(); - let inputs = fn_sig.inputs().skip_binder(); - suggestion = vec![( - assoc_ident.span.with_hi(expr.span.hi()), - format!( - "{variant_name}({})", - inputs - .iter() - .map(|i| format!("/* {i} */")) - .collect::>() - .join(", ") - ), - )]; - } - Some((hir::def::CtorKind::Const, _)) => { - // unit - suggestion = vec![( - assoc_ident.span.with_hi(expr.span.hi()), - variant_name.to_string(), - )]; - } - } - } - err.multipart_suggestion_verbose( - "there is a variant with a similar name", - suggestion, - Applicability::HasPlaceholders, - ); - } else { - err.span_label( - assoc_ident.span, - format!("variant not found in `{qself_ty}`"), - ); - } - - if let Some(sp) = tcx.hir_span_if_local(adt_def.did()) { - err.span_label(sp, format!("variant `{assoc_ident}` not found here")); - } - - err.emit() - } else if let Err(reported) = qself_ty.error_reported() { - reported - } else { - self.maybe_report_similar_assoc_fn(span, qself_ty, qself)?; - - let traits: Vec<_> = - self.probe_traits_that_match_assoc_ty(qself_ty, assoc_ident); - - // Don't print `ty::Error` to the user. - self.report_ambiguous_assoc( - span, - &[qself_ty.to_string()], - &traits, - assoc_ident.name, - mode.assoc_tag(), - ) - }; - return Err(reported); + return Err(self.report_unresolved_type_relative_path( + self_ty, + hir_self_ty, + assoc_tag, + segment.ident, + qpath_hir_id, + span, + variant_def_id, + )); } }; - let trait_did = bound.def_id(); let assoc_item = self - .probe_assoc_item(assoc_ident, mode.assoc_tag(), hir_ref_id, span, trait_did) + .probe_assoc_item(segment.ident, assoc_tag, qpath_hir_id, span, bound.def_id()) .expect("failed to find associated item"); - let (def_id, args) = self.lower_assoc_shared( - span, - assoc_item.def_id, - assoc_segment, - bound, - mode.assoc_tag(), - )?; - let result = LoweredAssoc::Term(def_id, args); - - if let Some(variant_def_id) = variant_resolution { - tcx.node_span_lint(AMBIGUOUS_ASSOCIATED_ITEMS, hir_ref_id, span, |lint| { - lint.primary_message("ambiguous associated item"); - let mut could_refer_to = |kind: DefKind, def_id, also| { - let note_msg = format!( - "`{}` could{} refer to the {} defined here", - assoc_ident, - also, - tcx.def_kind_descr(kind, def_id) - ); - lint.span_note(tcx.def_span(def_id), note_msg); - }; - could_refer_to(DefKind::Variant, variant_def_id, ""); - could_refer_to(mode.def_kind(), assoc_item.def_id, " also"); - - lint.span_suggestion( - span, - "use fully-qualified syntax", - format!("<{} as {}>::{}", qself_ty, tcx.item_name(trait_did), assoc_ident), - Applicability::MachineApplicable, - ); - }); - } - Ok(result) + Ok((assoc_item.def_id, bound)) } - fn probe_inherent_assoc_shared( + /// Search for inherent associated items for use at the type level. + fn probe_inherent_assoc_item( &self, segment: &hir::PathSegment<'tcx>, adt_did: DefId, @@ -1624,7 +1552,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .collect(); match &applicable_candidates[..] { - &[] => Err(self.complain_about_inherent_assoc_not_found( + &[] => Err(self.report_unresolved_inherent_assoc_item( name, self_ty, candidates, @@ -1635,7 +1563,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &[applicable_candidate] => Ok(applicable_candidate), - &[_, ..] => Err(self.complain_about_ambiguous_inherent_assoc( + &[_, ..] => Err(self.report_ambiguous_inherent_assoc_item( name, applicable_candidates.into_iter().map(|(_, (candidate, _))| candidate).collect(), span, @@ -1763,9 +1691,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .collect() } - /// Lower a qualified path to a type. + /// Lower a [resolved][hir::QPath::Resolved] associated type path to a projection. #[instrument(level = "debug", skip_all)] - fn lower_qpath_ty( + fn lower_resolved_assoc_ty_path( &self, span: Span, opt_self_ty: Option>, @@ -1773,7 +1701,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { trait_segment: Option<&hir::PathSegment<'tcx>>, item_segment: &hir::PathSegment<'tcx>, ) -> Ty<'tcx> { - match self.lower_qpath_shared( + match self.lower_resolved_assoc_item_path( span, opt_self_ty, item_def_id, @@ -1788,9 +1716,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - /// Lower a qualified path to a const. + /// Lower a [resolved][hir::QPath::Resolved] associated const path to a (type-level) constant. #[instrument(level = "debug", skip_all)] - fn lower_qpath_const( + fn lower_resolved_assoc_const_path( &self, span: Span, opt_self_ty: Option>, @@ -1798,7 +1726,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { trait_segment: Option<&hir::PathSegment<'tcx>>, item_segment: &hir::PathSegment<'tcx>, ) -> Const<'tcx> { - match self.lower_qpath_shared( + match self.lower_resolved_assoc_item_path( span, opt_self_ty, item_def_id, @@ -1814,8 +1742,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } + /// Lower a [resolved][hir::QPath::Resolved] (type-level) associated item path. #[instrument(level = "debug", skip_all)] - fn lower_qpath_shared( + fn lower_resolved_assoc_item_path( &self, span: Span, opt_self_ty: Option>, @@ -1830,7 +1759,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { debug!(?trait_def_id); let Some(self_ty) = opt_self_ty else { - return Err(self.error_missing_qpath_self_ty( + return Err(self.report_missing_self_ty_for_resolved_path( trait_def_id, span, item_segment, @@ -1849,57 +1778,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Ok((item_def_id, item_args)) } - fn error_missing_qpath_self_ty( - &self, - trait_def_id: DefId, - span: Span, - item_segment: &hir::PathSegment<'tcx>, - assoc_tag: ty::AssocTag, - ) -> ErrorGuaranteed { - let tcx = self.tcx(); - let path_str = tcx.def_path_str(trait_def_id); - - let def_id = self.item_def_id(); - debug!(item_def_id = ?def_id); - - // FIXME: document why/how this is different from `tcx.local_parent(def_id)` - let parent_def_id = tcx.hir_get_parent_item(tcx.local_def_id_to_hir_id(def_id)).to_def_id(); - debug!(?parent_def_id); - - // If the trait in segment is the same as the trait defining the item, - // use the `` syntax in the error. - let is_part_of_self_trait_constraints = def_id.to_def_id() == trait_def_id; - let is_part_of_fn_in_self_trait = parent_def_id == trait_def_id; - - let type_names = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait { - vec!["Self".to_string()] - } else { - // Find all the types that have an `impl` for the trait. - tcx.all_impls(trait_def_id) - .filter_map(|impl_def_id| tcx.impl_trait_header(impl_def_id)) - .filter(|header| { - // Consider only accessible traits - tcx.visibility(trait_def_id).is_accessible_from(self.item_def_id(), tcx) - && header.polarity != ty::ImplPolarity::Negative - }) - .map(|header| header.trait_ref.instantiate_identity().self_ty()) - // We don't care about blanket impls. - .filter(|self_ty| !self_ty.has_non_region_param()) - .map(|self_ty| tcx.erase_regions(self_ty).to_string()) - .collect() - }; - // FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that - // references the trait. Relevant for the first case in - // `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs` - self.report_ambiguous_assoc( - span, - &type_names, - &[path_str], - item_segment.ident.name, - assoc_tag, - ) - } - pub fn prohibit_generic_args<'a>( &self, segments: impl Iterator> + Clone, @@ -1908,7 +1786,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let args_visitors = segments.clone().flat_map(|segment| segment.args().args); let mut result = Ok(()); if let Some(_) = args_visitors.clone().next() { - result = Err(self.report_prohibit_generics_error( + result = Err(self.report_prohibited_generic_args( segments.clone(), args_visitors, err_extend, @@ -2069,14 +1947,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { generic_segments } - /// Lower a type `Path` to a type. + /// Lower a [resolved][hir::QPath::Resolved] path to a type. #[instrument(level = "debug", skip_all)] - pub fn lower_path( + pub fn lower_resolved_ty_path( &self, opt_self_ty: Option>, path: &hir::Path<'tcx>, hir_id: HirId, - permit_variants: bool, + permit_variants: PermitVariants, ) -> Ty<'tcx> { debug!(?path.res, ?opt_self_ty, ?path.segments); let tcx = self.tcx(); @@ -2107,7 +1985,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ); self.lower_path_segment(span, did, path.segments.last().unwrap()) } - Res::Def(kind @ DefKind::Variant, def_id) if permit_variants => { + Res::Def(kind @ DefKind::Variant, def_id) + if let PermitVariants::Yes = permit_variants => + { // Lower "variant type" as if it were a real type. // The resulting `Ty` is type of the variant's enum for now. assert_eq!(opt_self_ty, None); @@ -2202,7 +2082,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } else { None }; - self.lower_qpath_ty( + self.lower_resolved_assoc_ty_path( span, opt_self_ty, def_id, @@ -2298,7 +2178,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - /// Convert a [`hir::ConstArg`] to a [`ty::Const`](Const). + /// Lower a [`hir::ConstArg`] to a (type-level) [`ty::Const`](Const). #[instrument(skip(self), level = "debug")] pub fn lower_const_arg( &self, @@ -2323,7 +2203,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { if tcx.features().generic_const_parameter_types() && (anon_const_type.has_free_regions() || anon_const_type.has_erased_regions()) { - let e = tcx.dcx().span_err( + let e = self.dcx().span_err( const_arg.span(), "anonymous constants with lifetimes in their type are not yet supported", ); @@ -2334,7 +2214,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // use this type to feed the `type_of` and query results must not contain inference // variables otherwise we will ICE. if anon_const_type.has_non_region_infer() { - let e = tcx.dcx().span_err( + let e = self.dcx().span_err( const_arg.span(), "anonymous constants with inferred types are not yet supported", ); @@ -2344,7 +2224,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // We error when the type contains unsubstituted generics since we do not currently // give the anon const any of the generics from the parent. if anon_const_type.has_non_region_param() { - let e = tcx.dcx().span_err( + let e = self.dcx().span_err( const_arg.span(), "anonymous constants referencing generics are not yet supported", ); @@ -2363,13 +2243,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir::ConstArgKind::Path(hir::QPath::Resolved(maybe_qself, path)) => { debug!(?maybe_qself, ?path); let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself)); - self.lower_const_path_resolved(opt_self_ty, path, hir_id) + self.lower_resolved_const_path(opt_self_ty, path, hir_id) } - hir::ConstArgKind::Path(hir::QPath::TypeRelative(qself, segment)) => { - debug!(?qself, ?segment); - let ty = self.lower_ty(qself); - self.lower_assoc_path_const(hir_id, const_arg.span(), ty, qself, segment) - .unwrap_or_else(|guar| Const::new_error(tcx, guar)) + hir::ConstArgKind::Path(hir::QPath::TypeRelative(hir_self_ty, segment)) => { + debug!(?hir_self_ty, ?segment); + let self_ty = self.lower_ty(hir_self_ty); + self.lower_type_relative_const_path( + self_ty, + hir_self_ty, + segment, + hir_id, + const_arg.span(), + ) + .unwrap_or_else(|guar| Const::new_error(tcx, guar)) } hir::ConstArgKind::Path(qpath @ hir::QPath::LangItem(..)) => { ty::Const::new_error_with_message( @@ -2383,7 +2269,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - fn lower_const_path_resolved( + /// Lower a [resolved][hir::QPath::Resolved] path to a (type-level) constant. + fn lower_resolved_const_path( &self, opt_self_ty: Option>, path: &hir::Path<'tcx>, @@ -2420,7 +2307,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } else { None }; - self.lower_qpath_const( + self.lower_resolved_assoc_const_path( span, opt_self_ty, did, @@ -2630,7 +2517,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir::TyKind::Path(hir::QPath::Resolved(maybe_qself, path)) => { debug!(?maybe_qself, ?path); let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself)); - self.lower_path(opt_self_ty, path, hir_ty.hir_id, false) + self.lower_resolved_ty_path(opt_self_ty, path, hir_ty.hir_id, PermitVariants::No) } &hir::TyKind::OpaqueDef(opaque_ty) => { // If this is an RPITIT and we are using the new RPITIT lowering scheme, we @@ -2684,12 +2571,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let guar = self.dcx().emit_err(BadReturnTypeNotation { span: hir_ty.span }); Ty::new_error(tcx, guar) } - hir::TyKind::Path(hir::QPath::TypeRelative(qself, segment)) => { - debug!(?qself, ?segment); - let ty = self.lower_ty(qself); - self.lower_assoc_path_ty(hir_ty.hir_id, hir_ty.span, ty, qself, segment, false) - .map(|(ty, _, _)| ty) - .unwrap_or_else(|guar| Ty::new_error(tcx, guar)) + hir::TyKind::Path(hir::QPath::TypeRelative(hir_self_ty, segment)) => { + debug!(?hir_self_ty, ?segment); + let self_ty = self.lower_ty(hir_self_ty); + self.lower_type_relative_ty_path( + self_ty, + hir_self_ty, + segment, + hir_ty.hir_id, + hir_ty.span, + PermitVariants::No, + ) + .map(|(ty, _, _)| ty) + .unwrap_or_else(|guar| Ty::new_error(tcx, guar)) } &hir::TyKind::Path(hir::QPath::LangItem(lang_item, span)) => { let def_id = tcx.require_lang_item(lang_item, Some(span)); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 6cc7e82bbf735..54c7819fc7b13 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -9,7 +9,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_hir::{ExprKind, HirId, Node, QPath}; use rustc_hir_analysis::check::potentially_plural_count; -use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; +use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, PermitVariants}; use rustc_index::IndexVec; use rustc_infer::infer::{DefineOpaqueTypes, InferOk, TypeTrace}; use rustc_middle::ty::adjustment::AllowTwoPhase; @@ -2105,15 +2105,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match *qpath { QPath::Resolved(ref maybe_qself, path) => { let self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself).raw); - let ty = self.lowerer().lower_path(self_ty, path, hir_id, true); + let ty = self.lowerer().lower_resolved_ty_path( + self_ty, + path, + hir_id, + PermitVariants::Yes, + ); (path.res, LoweredTy::from_raw(self, path_span, ty)) } - QPath::TypeRelative(qself, segment) => { - let ty = self.lower_ty(qself); + QPath::TypeRelative(hir_self_ty, segment) => { + let self_ty = self.lower_ty(hir_self_ty); - let result = self - .lowerer() - .lower_assoc_path_ty(hir_id, path_span, ty.raw, qself, segment, true); + let result = self.lowerer().lower_type_relative_ty_path( + self_ty.raw, + hir_self_ty, + segment, + hir_id, + path_span, + PermitVariants::Yes, + ); let ty = result .map(|(ty, _, _)| ty) .unwrap_or_else(|guar| Ty::new_error(self.tcx(), guar)); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index de189b301092c..ea0adf16b1a36 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -308,17 +308,16 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> { )) } - fn lower_assoc_shared( + fn lower_assoc_item_path( &self, span: Span, item_def_id: DefId, item_segment: &rustc_hir::PathSegment<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>, - _assoc_tag: ty::AssocTag, ) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> { let trait_ref = self.instantiate_binder_with_fresh_vars( span, - // FIXME(mgca): this should be assoc const if that is the `kind` + // FIXME(mgca): `item_def_id` can be an AssocConst; rename this variant. infer::BoundRegionConversionTime::AssocTypeProjection(item_def_id), poly_trait_ref, ); diff --git a/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.uncovered.stderr b/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.uncovered.stderr index 978305c2ce355..3e914e0538d0b 100644 --- a/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.uncovered.stderr +++ b/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.uncovered.stderr @@ -2,7 +2,13 @@ error[E0223]: ambiguous associated type --> $DIR/not-found-self-type-differs-shadowing-trait-item.rs:28:12 | LL | let _: S::::Pr = (); - | ^^^^^^^^^^^^^ help: use fully-qualified syntax: ` as Tr>::Pr` + | ^^^^^^^^^^^^^ + | +help: use fully-qualified syntax + | +LL - let _: S::::Pr = (); +LL + let _: as Tr>::Pr = (); + | error: aborting due to 1 previous error diff --git a/tests/ui/associated-item/ambiguous-associated-type-with-generics.stderr b/tests/ui/associated-item/ambiguous-associated-type-with-generics.stderr index 9e1dd73980792..fcf6b4c3e7361 100644 --- a/tests/ui/associated-item/ambiguous-associated-type-with-generics.stderr +++ b/tests/ui/associated-item/ambiguous-associated-type-with-generics.stderr @@ -2,7 +2,12 @@ error[E0223]: ambiguous associated type --> $DIR/ambiguous-associated-type-with-generics.rs:13:13 | LL | let _x: >::Ty; - | ^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: ` as Assoc>::Ty` + | ^^^^^^^^^^^^^^^^^^^^ + | +help: use fully-qualified syntax + | +LL | let _x: as Assoc>::Ty; + | ++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/associated-item/associated-item-duplicate-names-3.stderr b/tests/ui/associated-item/associated-item-duplicate-names-3.stderr index a2346e292ac40..84a9da0998832 100644 --- a/tests/ui/associated-item/associated-item-duplicate-names-3.stderr +++ b/tests/ui/associated-item/associated-item-duplicate-names-3.stderr @@ -13,7 +13,13 @@ error[E0223]: ambiguous associated type --> $DIR/associated-item-duplicate-names-3.rs:18:12 | LL | let x: Baz::Bar = 5; - | ^^^^^^^^ help: use fully-qualified syntax: `::Bar` + | ^^^^^^^^ + | +help: use fully-qualified syntax + | +LL - let x: Baz::Bar = 5; +LL + let x: ::Bar = 5; + | error: aborting due to 2 previous errors diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-no-qself.stderr b/tests/ui/associated-type-bounds/return-type-notation/path-no-qself.stderr index aad6dfc496b75..a13fdbda1bf7a 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/path-no-qself.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/path-no-qself.stderr @@ -7,7 +7,7 @@ LL | Trait::method(..): Send, help: if there were a type named `Example` that implemented `Trait`, you could use the fully-qualified path | LL - Trait::method(..): Send, -LL + ::method: Send, +LL + ::method(..): Send, | error: aborting due to 1 previous error diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-non-param-qself.stderr b/tests/ui/associated-type-bounds/return-type-notation/path-non-param-qself.stderr index 38202bdbf0727..4c4c2c24079be 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/path-non-param-qself.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/path-non-param-qself.stderr @@ -3,18 +3,35 @@ error[E0223]: ambiguous associated function | LL | <()>::method(..): Send, | ^^^^^^^^^^^^^^^^ + | +help: if there were a trait named `Example` with associated function `method` implemented for `()`, you could use the fully-qualified path + | +LL | <() as Example>::method(..): Send, + | ++++++++++ error[E0223]: ambiguous associated function --> $DIR/path-non-param-qself.rs:13:5 | LL | i32::method(..): Send, | ^^^^^^^^^^^^^^^ + | +help: if there were a trait named `Example` with associated function `method` implemented for `i32`, you could use the fully-qualified path + | +LL - i32::method(..): Send, +LL + ::method(..): Send, + | error[E0223]: ambiguous associated function --> $DIR/path-non-param-qself.rs:15:5 | LL | Adt::method(..): Send, | ^^^^^^^^^^^^^^^ + | +help: if there were a trait named `Example` with associated function `method` implemented for `Adt`, you could use the fully-qualified path + | +LL - Adt::method(..): Send, +LL + ::method(..): Send, + | error: aborting due to 3 previous errors diff --git a/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr b/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr index 1be8db5ddf44f..a7647cf26aadf 100644 --- a/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr +++ b/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr @@ -14,7 +14,13 @@ error[E0223]: ambiguous associated type --> $DIR/associated-types-in-ambiguous-context.rs:22:17 | LL | trait Foo where Foo::Assoc: Bar { - | ^^^^^^^^^^ help: use fully-qualified syntax: `::Assoc` + | ^^^^^^^^^^ + | +help: use fully-qualified syntax + | +LL - trait Foo where Foo::Assoc: Bar { +LL + trait Foo where ::Assoc: Bar { + | error[E0223]: ambiguous associated type --> $DIR/associated-types-in-ambiguous-context.rs:27:10 @@ -42,7 +48,13 @@ error[E0223]: ambiguous associated type --> $DIR/associated-types-in-ambiguous-context.rs:13:23 | LL | fn grab(&self) -> Grab::Value; - | ^^^^^^^^^^^ help: use fully-qualified syntax: `::Value` + | ^^^^^^^^^^^ + | +help: use fully-qualified syntax + | +LL - fn grab(&self) -> Grab::Value; +LL + fn grab(&self) -> ::Value; + | error[E0223]: ambiguous associated type --> $DIR/associated-types-in-ambiguous-context.rs:16:22 diff --git a/tests/ui/error-codes/E0223.stderr b/tests/ui/error-codes/E0223.stderr index e985a4c9bf0d9..fbfdce5689a70 100644 --- a/tests/ui/error-codes/E0223.stderr +++ b/tests/ui/error-codes/E0223.stderr @@ -2,7 +2,13 @@ error[E0223]: ambiguous associated type --> $DIR/E0223.rs:8:14 | LL | let foo: MyTrait::X; - | ^^^^^^^^^^ help: use fully-qualified syntax: `::X` + | ^^^^^^^^^^ + | +help: use fully-qualified syntax + | +LL - let foo: MyTrait::X; +LL + let foo: ::X; + | error: aborting due to 1 previous error diff --git a/tests/ui/lint/bare-trait-objects-path.stderr b/tests/ui/lint/bare-trait-objects-path.stderr index fbb647c37c5ae..e611abd31f3b4 100644 --- a/tests/ui/lint/bare-trait-objects-path.stderr +++ b/tests/ui/lint/bare-trait-objects-path.stderr @@ -55,7 +55,13 @@ error[E0223]: ambiguous associated type --> $DIR/bare-trait-objects-path.rs:23:12 | LL | let _: Dyn::Ty; - | ^^^^^^^ help: use fully-qualified syntax: `::Ty` + | ^^^^^^^ + | +help: use fully-qualified syntax + | +LL - let _: Dyn::Ty; +LL + let _: ::Ty; + | error: aborting due to 1 previous error; 4 warnings emitted diff --git a/tests/ui/qualified/qualified-path-params-2.stderr b/tests/ui/qualified/qualified-path-params-2.stderr index 6641e81013f05..e70cdbdc3f49e 100644 --- a/tests/ui/qualified/qualified-path-params-2.stderr +++ b/tests/ui/qualified/qualified-path-params-2.stderr @@ -7,7 +7,7 @@ LL | type A = ::A::f; help: if there were a trait named `Example` with associated type `f` implemented for `::A`, you could use the fully-qualified path | LL - type A = ::A::f; -LL + type A = <::A as Example>::f; +LL + type A = <::A as Example>::f; | error: aborting due to 1 previous error diff --git a/tests/ui/self/self-impl.stderr b/tests/ui/self/self-impl.stderr index 18ffd15427f81..1bda307d0eb3a 100644 --- a/tests/ui/self/self-impl.stderr +++ b/tests/ui/self/self-impl.stderr @@ -2,13 +2,25 @@ error[E0223]: ambiguous associated type --> $DIR/self-impl.rs:23:16 | LL | let _: ::Baz = true; - | ^^^^^^^^^^^ help: use fully-qualified syntax: `::Baz` + | ^^^^^^^^^^^ + | +help: use fully-qualified syntax + | +LL - let _: ::Baz = true; +LL + let _: ::Baz = true; + | error[E0223]: ambiguous associated type --> $DIR/self-impl.rs:25:16 | LL | let _: Self::Baz = true; - | ^^^^^^^^^ help: use fully-qualified syntax: `::Baz` + | ^^^^^^^^^ + | +help: use fully-qualified syntax + | +LL - let _: Self::Baz = true; +LL + let _: ::Baz = true; + | error: aborting due to 2 previous errors diff --git a/tests/ui/structs/struct-path-associated-type.stderr b/tests/ui/structs/struct-path-associated-type.stderr index de396e875b0cf..110362293ac32 100644 --- a/tests/ui/structs/struct-path-associated-type.stderr +++ b/tests/ui/structs/struct-path-associated-type.stderr @@ -48,19 +48,37 @@ error[E0223]: ambiguous associated type --> $DIR/struct-path-associated-type.rs:32:13 | LL | let s = S::A {}; - | ^^^^ help: use fully-qualified syntax: `::A` + | ^^^^ + | +help: use fully-qualified syntax + | +LL - let s = S::A {}; +LL + let s = ::A {}; + | error[E0223]: ambiguous associated type --> $DIR/struct-path-associated-type.rs:33:13 | LL | let z = S::A:: {}; - | ^^^^ help: use fully-qualified syntax: `::A` + | ^^^^ + | +help: use fully-qualified syntax + | +LL - let z = S::A:: {}; +LL + let z = ::A:: {}; + | error[E0223]: ambiguous associated type --> $DIR/struct-path-associated-type.rs:35:9 | LL | S::A {} => {} - | ^^^^ help: use fully-qualified syntax: `::A` + | ^^^^ + | +help: use fully-qualified syntax + | +LL - S::A {} => {} +LL + ::A {} => {} + | error: aborting due to 8 previous errors diff --git a/tests/ui/traits/item-privacy.stderr b/tests/ui/traits/item-privacy.stderr index 4fd9ef9119257..1d3d8cb98437c 100644 --- a/tests/ui/traits/item-privacy.stderr +++ b/tests/ui/traits/item-privacy.stderr @@ -230,13 +230,25 @@ error[E0223]: ambiguous associated type --> $DIR/item-privacy.rs:119:12 | LL | let _: S::B; - | ^^^^ help: use fully-qualified syntax: `::B` + | ^^^^ + | +help: use fully-qualified syntax + | +LL - let _: S::B; +LL + let _: ::B; + | error[E0223]: ambiguous associated type --> $DIR/item-privacy.rs:120:12 | LL | let _: S::C; - | ^^^^ help: use fully-qualified syntax: `::C` + | ^^^^ + | +help: use fully-qualified syntax + | +LL - let _: S::C; +LL + let _: ::C; + | error[E0624]: associated type `A` is private --> $DIR/item-privacy.rs:122:12 diff --git a/tests/ui/typeck/ice-unexpected-region-123863.stderr b/tests/ui/typeck/ice-unexpected-region-123863.stderr index 8a4d767c14350..e5050b4d3167a 100644 --- a/tests/ui/typeck/ice-unexpected-region-123863.stderr +++ b/tests/ui/typeck/ice-unexpected-region-123863.stderr @@ -39,7 +39,7 @@ LL | Inner::concat_strs::<"a">::A help: if there were a trait named `Example` with associated type `concat_strs` implemented for `Inner<_>`, you could use the fully-qualified path | LL - Inner::concat_strs::<"a">::A -LL + as Example>::concat_strs::A +LL + as Example>::concat_strs::<"a">::A | error: aborting due to 3 previous errors diff --git a/tests/ui/typeck/issue-107087.stderr b/tests/ui/typeck/issue-107087.stderr index 289c8d161ae86..157ba5a167219 100644 --- a/tests/ui/typeck/issue-107087.stderr +++ b/tests/ui/typeck/issue-107087.stderr @@ -2,7 +2,13 @@ error[E0223]: ambiguous associated type --> $DIR/issue-107087.rs:16:5 | LL | A::B::<>::C - | ^^^^^^^^ help: use fully-qualified syntax: ` as Foo>::B` + | ^^^^^^^^ + | +help: use fully-qualified syntax + | +LL - A::B::<>::C +LL + as Foo>::B::<>::C + | error: aborting due to 1 previous error