Rollup merge of #106585 - estebank:issue-46585, r=compiler-errors
When suggesting writing a fully qualified path probe for appropriate types Address the more common part of #46585.
This commit is contained in:
commit
c6e3a47843
21 changed files with 324 additions and 55 deletions
|
@ -27,6 +27,7 @@ use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
|
|||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::intravisit::{walk_generics, Visitor as _};
|
||||
use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin};
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_middle::middle::stability::AllowUnstable;
|
||||
use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef};
|
||||
use rustc_middle::ty::GenericParamDefKind;
|
||||
|
@ -1643,8 +1644,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
fn report_ambiguous_associated_type(
|
||||
&self,
|
||||
span: Span,
|
||||
type_str: &str,
|
||||
trait_str: &str,
|
||||
types: &[String],
|
||||
traits: &[String],
|
||||
name: Symbol,
|
||||
) -> ErrorGuaranteed {
|
||||
let mut err = struct_span_err!(self.tcx().sess, span, E0223, "ambiguous associated type");
|
||||
|
@ -1655,19 +1656,92 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
.keys()
|
||||
.any(|full_span| full_span.contains(span))
|
||||
{
|
||||
err.span_suggestion(
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_lo(),
|
||||
"you are looking for the module in `std`, not the primitive type",
|
||||
"std::",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else {
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"use fully-qualified syntax",
|
||||
format!("<{} as {}>::{}", type_str, trait_str, name),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
match (types, traits) {
|
||||
([], []) => {
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
&format!(
|
||||
"if there were a type named `Type` that implements a trait named \
|
||||
`Trait` with associated type `{name}`, you could use the \
|
||||
fully-qualified path",
|
||||
),
|
||||
format!("<Type as Trait>::{name}"),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
([], [trait_str]) => {
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
&format!(
|
||||
"if there were a type named `Example` that implemented `{trait_str}`, \
|
||||
you could use the fully-qualified path",
|
||||
),
|
||||
format!("<Example as {trait_str}>::{name}"),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
([], traits) => {
|
||||
err.span_suggestions(
|
||||
span,
|
||||
&format!(
|
||||
"if there were a type named `Example` that implemented one of the \
|
||||
traits with associated type `{name}`, you could use the \
|
||||
fully-qualified path",
|
||||
),
|
||||
traits
|
||||
.iter()
|
||||
.map(|trait_str| format!("<Example as {trait_str}>::{name}"))
|
||||
.collect::<Vec<_>>(),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
([type_str], []) => {
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
&format!(
|
||||
"if there were a trait named `Example` with associated type `{name}` \
|
||||
implemented for `{type_str}`, you could use the fully-qualified path",
|
||||
),
|
||||
format!("<{type_str} as Example>::{name}"),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
(types, []) => {
|
||||
err.span_suggestions(
|
||||
span,
|
||||
&format!(
|
||||
"if there were a trait named `Example` with associated type `{name}` \
|
||||
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}")),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
(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}"));
|
||||
}
|
||||
}
|
||||
err.span_suggestions(
|
||||
span,
|
||||
"use the fully-qualified path",
|
||||
suggestions,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
err.emit()
|
||||
}
|
||||
|
@ -2050,12 +2124,64 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
err.emit()
|
||||
} else if let Err(reported) = qself_ty.error_reported() {
|
||||
reported
|
||||
} else if let ty::Alias(ty::Opaque, alias_ty) = qself_ty.kind() {
|
||||
// `<impl Trait as OtherTrait>::Assoc` makes no sense.
|
||||
struct_span_err!(
|
||||
tcx.sess,
|
||||
tcx.def_span(alias_ty.def_id),
|
||||
E0667,
|
||||
"`impl Trait` is not allowed in path parameters"
|
||||
)
|
||||
.emit() // Already reported in an earlier stage.
|
||||
} else {
|
||||
// Find all the `impl`s that `qself_ty` has for any trait that has the
|
||||
// associated type, so that we suggest the right one.
|
||||
let infcx = tcx.infer_ctxt().build();
|
||||
// We create a fresh `ty::ParamEnv` instead of the one for `self.item_def_id()`
|
||||
// to avoid a cycle error in `src/test/ui/resolve/issue-102946.rs`.
|
||||
let param_env = ty::ParamEnv::empty();
|
||||
let traits: Vec<_> = self
|
||||
.tcx()
|
||||
.all_traits()
|
||||
.filter(|trait_def_id| {
|
||||
// Consider only traits with the associated type
|
||||
tcx.associated_items(*trait_def_id)
|
||||
.in_definition_order()
|
||||
.any(|i| {
|
||||
i.kind.namespace() == Namespace::TypeNS
|
||||
&& i.ident(tcx).normalize_to_macros_2_0() == assoc_ident
|
||||
&& matches!(i.kind, ty::AssocKind::Type)
|
||||
})
|
||||
// Consider only accessible traits
|
||||
&& tcx.visibility(*trait_def_id)
|
||||
.is_accessible_from(self.item_def_id(), tcx)
|
||||
&& tcx.all_impls(*trait_def_id)
|
||||
.any(|impl_def_id| {
|
||||
let trait_ref = tcx.bound_impl_trait_ref(impl_def_id);
|
||||
trait_ref.map_or(false, |trait_ref| {
|
||||
let impl_ = trait_ref.subst(
|
||||
tcx,
|
||||
infcx.fresh_substs_for_item(span, impl_def_id),
|
||||
);
|
||||
infcx
|
||||
.can_eq(
|
||||
param_env,
|
||||
tcx.erase_regions(impl_.self_ty()),
|
||||
tcx.erase_regions(qself_ty),
|
||||
)
|
||||
.is_ok()
|
||||
})
|
||||
&& tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative
|
||||
})
|
||||
})
|
||||
.map(|trait_def_id| tcx.def_path_str(trait_def_id))
|
||||
.collect();
|
||||
|
||||
// Don't print `TyErr` to the user.
|
||||
self.report_ambiguous_associated_type(
|
||||
span,
|
||||
&qself_ty.to_string(),
|
||||
"Trait",
|
||||
&[qself_ty.to_string()],
|
||||
&traits,
|
||||
assoc_ident.name,
|
||||
)
|
||||
};
|
||||
|
@ -2173,16 +2299,30 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
let is_part_of_self_trait_constraints = def_id == trait_def_id;
|
||||
let is_part_of_fn_in_self_trait = parent_def_id == Some(trait_def_id);
|
||||
|
||||
let type_name = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait {
|
||||
"Self"
|
||||
let type_names = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait {
|
||||
vec!["Self".to_string()]
|
||||
} else {
|
||||
"Type"
|
||||
// Find all the types that have an `impl` for the trait.
|
||||
tcx.all_impls(trait_def_id)
|
||||
.filter(|impl_def_id| {
|
||||
// Consider only accessible traits
|
||||
tcx.visibility(*impl_def_id).is_accessible_from(self.item_def_id(), tcx)
|
||||
&& tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative
|
||||
})
|
||||
.filter_map(|impl_def_id| tcx.impl_trait_ref(impl_def_id))
|
||||
.map(|impl_| impl_.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`
|
||||
let reported = self.report_ambiguous_associated_type(
|
||||
span,
|
||||
type_name,
|
||||
&path_str,
|
||||
&type_names,
|
||||
&[path_str],
|
||||
item_segment.ident.name,
|
||||
);
|
||||
return tcx.ty_error_with_guaranteed(reported)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue