Skip to content

Commit 6906879

Browse files
Rollup merge of rust-lang#157027 - fmease:hirtylo-mv-things, r=nnethercote
HIR ty lowering: Move some things into submodules By commit: 1. Move `compute_object_lifetime_bound` into submodule `dyn_trait` since it's only used there unsurprisingly 2. Move a `impl Diagnostic for AmbiguousAssocItem` into submodule `errors` and rename the diagnostic struct * For what it represents, it was way too prominent right at the start of `lower_type_relative_path` which didn't use to be the case prior to PR rust-lang#153452 3. Move a distractingly lengthy "error builder" into a new fn `report_ambiguous_assoc_item` in submodule `errors` * Since we unconditionally `return Err(_)` after calling this new function, we fix a debug assertion (see commit message & description of added UI test for details) Fixes rust-lang#139387
2 parents 6eda741 + fd36a80 commit 6906879

6 files changed

Lines changed: 302 additions & 241 deletions

File tree

compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,48 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
515515
);
516516
}
517517

518+
/// Given the bounds on an object, determines what single region bound (if any) we can
519+
/// use to summarize this type.
520+
///
521+
/// The basic idea is that we will use the bound the user
522+
/// provided, if they provided one, and otherwise search the supertypes of trait bounds
523+
/// for region bounds. It may be that we can derive no bound at all, in which case
524+
/// we return `None`.
525+
#[instrument(level = "debug", skip(self, span), ret)]
526+
fn compute_object_lifetime_bound(
527+
&self,
528+
span: Span,
529+
existential_predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
530+
) -> Option<ty::Region<'tcx>> // if None, use the default
531+
{
532+
let tcx = self.tcx();
533+
534+
// No explicit region bound specified. Therefore, examine trait
535+
// bounds and see if we can derive region bounds from those.
536+
let derived_region_bounds = traits::wf::object_region_bounds(tcx, existential_predicates);
537+
538+
// If there are no derived region bounds, then report back that we
539+
// can find no region bound. The caller will use the default.
540+
if derived_region_bounds.is_empty() {
541+
return None;
542+
}
543+
544+
// If any of the derived region bounds are 'static, that is always
545+
// the best choice.
546+
if derived_region_bounds.iter().any(|r| r.is_static()) {
547+
return Some(tcx.lifetimes.re_static);
548+
}
549+
550+
// Determine whether there is exactly one unique region in the set
551+
// of derived region bounds. If so, use that. Otherwise, report an
552+
// error.
553+
let r = derived_region_bounds[0];
554+
if derived_region_bounds[1..].iter().any(|r1| r != *r1) {
555+
self.dcx().emit_err(crate::errors::AmbiguousLifetimeBound { span });
556+
}
557+
Some(r)
558+
}
559+
518560
/// Prohibit or lint against *bare* trait object types depending on the edition.
519561
///
520562
/// *Bare* trait object types are ones that aren't preceded by the keyword `dyn`.

compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs

Lines changed: 189 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,141 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
403403
})
404404
}
405405

406+
pub(super) fn report_ambiguous_assoc_item(
407+
&self,
408+
bound1: ty::PolyTraitRef<'tcx>,
409+
bound2: ty::PolyTraitRef<'tcx>,
410+
matching_candidates: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
411+
qself: AssocItemQSelf,
412+
assoc_tag: ty::AssocTag,
413+
assoc_ident: Ident,
414+
span: Span,
415+
constraint: Option<&hir::AssocItemConstraint<'tcx>>,
416+
) -> ErrorGuaranteed {
417+
let tcx = self.tcx();
418+
419+
let assoc_kind_str = assoc_tag_str(assoc_tag);
420+
let qself_str = qself.to_string(tcx);
421+
let mut err = self.dcx().create_err(crate::errors::AmbiguousAssocItem {
422+
span,
423+
assoc_kind: assoc_kind_str,
424+
assoc_ident,
425+
qself: &qself_str,
426+
});
427+
// Provide a more specific error code index entry for equality bindings.
428+
err.code(
429+
if let Some(constraint) = constraint
430+
&& let hir::AssocItemConstraintKind::Equality { .. } = constraint.kind
431+
{
432+
E0222
433+
} else {
434+
E0221
435+
},
436+
);
437+
438+
// FIXME(#97583): Print associated item bindings properly (i.e., not as equality
439+
// predicates!).
440+
// FIXME: Turn this into a structured, translatable & more actionable suggestion.
441+
let mut where_bounds = vec![];
442+
for bound in [bound1, bound2].into_iter().chain(matching_candidates) {
443+
let bound_id = bound.def_id();
444+
let assoc_item = tcx.associated_items(bound_id).find_by_ident_and_kind(
445+
tcx,
446+
assoc_ident,
447+
assoc_tag,
448+
bound_id,
449+
);
450+
let bound_span = assoc_item.and_then(|item| tcx.hir_span_if_local(item.def_id));
451+
452+
if let Some(bound_span) = bound_span {
453+
err.span_label(
454+
bound_span,
455+
format!("ambiguous `{assoc_ident}` from `{}`", bound.print_trait_sugared(),),
456+
);
457+
if let Some(constraint) = constraint {
458+
match constraint.kind {
459+
hir::AssocItemConstraintKind::Equality { term } => {
460+
let term: ty::Term<'_> = match term {
461+
hir::Term::Ty(ty) => self.lower_ty(ty).into(),
462+
hir::Term::Const(ct) => {
463+
let assoc_item =
464+
assoc_item.expect("assoc_item should be present");
465+
let projection_term = bound.map_bound(|trait_ref| {
466+
let item_segment = hir::PathSegment {
467+
ident: constraint.ident,
468+
hir_id: constraint.hir_id,
469+
res: Res::Err,
470+
args: Some(constraint.gen_args),
471+
infer_args: false,
472+
};
473+
474+
let alias_args = self.lower_generic_args_of_assoc_item(
475+
constraint.ident.span,
476+
assoc_item.def_id,
477+
&item_segment,
478+
trait_ref.args,
479+
);
480+
ty::AliasTerm::new_from_def_id(
481+
tcx,
482+
assoc_item.def_id,
483+
alias_args,
484+
)
485+
});
486+
487+
// FIXME(mgca): code duplication with other places we lower
488+
// the rhs' of associated const bindings
489+
let ty = projection_term.map_bound(|alias| {
490+
tcx.type_of(alias.def_id())
491+
.instantiate(tcx, alias.args)
492+
.skip_norm_wip()
493+
});
494+
let ty = super::bounds::check_assoc_const_binding_type(
495+
self,
496+
constraint.ident,
497+
ty,
498+
constraint.hir_id,
499+
);
500+
501+
self.lower_const_arg(ct, ty).into()
502+
}
503+
};
504+
if term.references_error() {
505+
continue;
506+
}
507+
// FIXME(#97583): This isn't syntactically well-formed!
508+
where_bounds.push(format!(
509+
" T: {trait}::{assoc_ident} = {term}",
510+
trait = bound.print_only_trait_path(),
511+
));
512+
}
513+
// FIXME: Provide a suggestion.
514+
hir::AssocItemConstraintKind::Bound { bounds: _ } => {}
515+
}
516+
} else {
517+
err.span_suggestion_verbose(
518+
span.with_hi(assoc_ident.span.lo()),
519+
"use fully-qualified syntax to disambiguate",
520+
format!("<{qself_str} as {}>::", bound.print_only_trait_path()),
521+
Applicability::MaybeIncorrect,
522+
);
523+
}
524+
} else {
525+
let trait_ = tcx.short_string(bound.print_only_trait_path(), err.long_ty_path());
526+
err.note(format!(
527+
"associated {assoc_kind_str} `{assoc_ident}` could derive from `{trait_}`",
528+
));
529+
}
530+
}
531+
if !where_bounds.is_empty() {
532+
err.help(format!(
533+
"consider introducing a new type parameter `T` and adding `where` constraints:\
534+
\n where\n T: {qself_str},\n{}",
535+
where_bounds.join(",\n"),
536+
));
537+
}
538+
err.emit()
539+
}
540+
406541
pub(crate) fn report_missing_self_ty_for_resolved_path(
407542
&self,
408543
trait_def_id: DefId,
@@ -568,7 +703,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
568703
}
569704
}
570705

571-
pub(super) fn report_ambiguous_assoc_item_path(
706+
fn report_ambiguous_assoc_item_path(
572707
&self,
573708
span: Span,
574709
types: &[String],
@@ -1847,7 +1982,59 @@ fn generics_args_err_extend<'a>(
18471982
}
18481983
}
18491984

1850-
pub(crate) fn assoc_tag_str(assoc_tag: ty::AssocTag) -> &'static str {
1985+
pub(super) struct AmbiguityBetweenVariantAndAssocItem<'tcx> {
1986+
pub(super) variant_def_id: DefId,
1987+
pub(super) item_def_id: DefId,
1988+
pub(super) span: Span,
1989+
pub(super) segment_ident: Ident,
1990+
pub(super) bound_def_id: DefId,
1991+
pub(super) self_ty: Ty<'tcx>,
1992+
pub(super) tcx: TyCtxt<'tcx>,
1993+
pub(super) mode: super::LowerTypeRelativePathMode,
1994+
}
1995+
1996+
impl<'a, 'tcx> rustc_errors::Diagnostic<'a, ()> for AmbiguityBetweenVariantAndAssocItem<'tcx> {
1997+
fn into_diag(
1998+
self,
1999+
dcx: rustc_errors::DiagCtxtHandle<'a>,
2000+
level: rustc_errors::Level,
2001+
) -> Diag<'a, ()> {
2002+
let Self {
2003+
variant_def_id,
2004+
item_def_id,
2005+
span,
2006+
segment_ident,
2007+
bound_def_id,
2008+
self_ty,
2009+
tcx,
2010+
mode,
2011+
} = self;
2012+
let mut lint = Diag::new(dcx, level, "ambiguous associated item");
2013+
2014+
let mut could_refer_to = |kind: DefKind, def_id, also| {
2015+
let note_msg = format!(
2016+
"`{}` could{} refer to the {} defined here",
2017+
segment_ident,
2018+
also,
2019+
tcx.def_kind_descr(kind, def_id)
2020+
);
2021+
lint.span_note(tcx.def_span(def_id), note_msg);
2022+
};
2023+
2024+
could_refer_to(DefKind::Variant, variant_def_id, "");
2025+
could_refer_to(mode.def_kind_for_diagnostics(), item_def_id, " also");
2026+
2027+
lint.span_suggestion(
2028+
span,
2029+
"use fully-qualified syntax",
2030+
format!("<{} as {}>::{}", self_ty, tcx.item_name(bound_def_id), segment_ident),
2031+
Applicability::MachineApplicable,
2032+
);
2033+
lint
2034+
}
2035+
}
2036+
2037+
fn assoc_tag_str(assoc_tag: ty::AssocTag) -> &'static str {
18512038
match assoc_tag {
18522039
ty::AssocTag::Fn => "function",
18532040
ty::AssocTag::Const => "constant",

0 commit comments

Comments
 (0)