diff options
| author | León Orell Valerian Liehr <me@fmease.dev> | 2023-02-17 17:06:27 +0100 |
|---|---|---|
| committer | León Orell Valerian Liehr <me@fmease.dev> | 2023-02-19 18:35:35 +0100 |
| commit | b5e73bfe90f7b4905829f1a6509b61ac5577ee07 (patch) | |
| tree | ac8880bf2099c4b08cd2aadba41264e776567de8 | |
| parent | cc65ebd0d29a79a2a1d3fd77e679c763837b33c4 (diff) | |
| download | rust-b5e73bfe90f7b4905829f1a6509b61ac5577ee07.tar.gz rust-b5e73bfe90f7b4905829f1a6509b61ac5577ee07.zip | |
Groundwork for detecting ambiguous candidates
NB: Since we are using the same InferCtxt in each iteration, we essentially *spoil* the inference variables and we only ever get at most *one* applicable candidate (only the 1st candidate has clean variables that can still unify correctly).
| -rw-r--r-- | compiler/rustc_hir_analysis/src/astconv/errors.rs | 60 | ||||
| -rw-r--r-- | compiler/rustc_hir_analysis/src/astconv/mod.rs | 27 |
2 files changed, 85 insertions, 2 deletions
diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs index 0e9f5fb3dae..f3a03805a44 100644 --- a/compiler/rustc_hir_analysis/src/astconv/errors.rs +++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs @@ -222,6 +222,66 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { err.emit() } + pub(crate) fn complain_about_ambiguous_inherent_assoc_type( + &self, + name: Ident, + candidates: Vec<(DefId, DefId)>, + span: Span, + ) -> ErrorGuaranteed { + let mut err = struct_span_err!( + self.tcx().sess, + name.span, + E0034, + "multiple applicable items in scope" + ); + err.span_label(name.span, format!("multiple `{name}` found")); + self.note_ambiguous_inherent_assoc_type(&mut err, candidates, span); + err.emit() + } + + // FIXME(fmease): Heavily adapted from `rustc_hir_typeck::method::suggest`. Deduplicate. + fn note_ambiguous_inherent_assoc_type( + &self, + err: &mut Diagnostic, + candidates: Vec<(DefId, DefId)>, + span: Span, + ) { + let tcx = self.tcx(); + + // Dynamic limit to avoid hiding just one candidate, which is silly. + let limit = if candidates.len() == 5 { 5 } else { 4 }; + + for (index, &(assoc_item, _)) in candidates.iter().take(limit).enumerate() { + let impl_ = tcx.impl_of_method(assoc_item).unwrap(); + + let note_span = if assoc_item.is_local() { + Some(tcx.def_span(assoc_item)) + } else if impl_.is_local() { + Some(tcx.def_span(impl_)) + } else { + None + }; + + let title = if candidates.len() > 1 { + format!("candidate #{}", index + 1) + } else { + "the candidate".into() + }; + + let impl_ty = tcx.at(span).type_of(impl_).subst_identity(); + let note = format!("{title} is defined in an impl for the type `{impl_ty}`"); + + if let Some(span) = note_span { + err.span_note(span, ¬e); + } else { + err.note(¬e); + } + } + if candidates.len() > limit { + err.note(&format!("and {} others", candidates.len() - limit)); + } + } + // FIXME(inherent_associated_types): Find similarly named associated types and suggest them. pub(crate) fn complain_about_inherent_assoc_type_not_found( &self, diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index d3468f03eed..43db8af7bac 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -2217,12 +2217,24 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { return Ok(None); } + // In contexts that have no inference context, just make a new one. + // We do need a local variable to store it, though. + let infcx_; + let infcx = match self.infcx() { + Some(infcx) => infcx, + None => { + assert!(!self_ty.needs_infer()); + infcx_ = tcx.infer_ctxt().ignoring_regions().build(); + &infcx_ + } + }; + let param_env = tcx.param_env(block.owner.to_def_id()); let cause = ObligationCause::misc(span, block.owner.def_id); let mut fulfillment_errors = Vec::new(); + let mut applicable_candidates = Vec::new(); for &(impl_, (assoc_item, def_scope)) in &candidates { - let infcx = tcx.infer_ctxt().ignoring_regions().build(); let ocx = ObligationCtxt::new(&infcx); let impl_ty = tcx.type_of(impl_); @@ -2253,6 +2265,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { continue; } + applicable_candidates.push((assoc_item, def_scope)); + } + + if applicable_candidates.len() > 1 { + return Err(self.complain_about_ambiguous_inherent_assoc_type( + name, + applicable_candidates, + span, + )); + } + + if let Some((assoc_item, def_scope)) = applicable_candidates.pop() { self.check_assoc_ty(assoc_item, name, def_scope, block, span); let ty::Adt(_, adt_substs) = self_ty.kind() else { @@ -2269,7 +2293,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // associated type hold, if any. let ty = tcx.type_of(assoc_item).subst(tcx, item_substs); - // FIXME(fmease): Don't return early here! There might be multiple applicable candidates. return Ok(Some((ty, assoc_item))); } |
