Auto merge of #102896 - matthiaskrgr:rollup-jg5xawz, r=matthiaskrgr
Rollup of 6 pull requests Successful merges: - #101360 (Point out incompatible closure bounds) - #101789 (`let`'s not needed in struct field definitions) - #102846 (update to syn-1.0.102) - #102871 (rustdoc: clean up overly complex `.trait-impl` CSS selectors) - #102876 (suggest candidates for unresolved import) - #102888 (Improve rustdoc-gui search-color test) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
518263d889
23 changed files with 514 additions and 719 deletions
|
@ -1788,7 +1788,23 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
self.expected_ident_found()
|
||||
let mut err = self.expected_ident_found();
|
||||
if let Some((ident, _)) = self.token.ident() && ident.as_str() == "let" {
|
||||
self.bump(); // `let`
|
||||
let span = self.prev_token.span.until(self.token.span);
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"remove the let, the `let` keyword is not allowed in struct field definitions",
|
||||
String::new(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
err.note("the `let` keyword is not allowed in `struct` fields");
|
||||
err.note("see <https://doc.rust-lang.org/book/ch05-01-defining-structs.html> for more information");
|
||||
err.emit();
|
||||
self.bump();
|
||||
return Ok(ident);
|
||||
}
|
||||
err
|
||||
};
|
||||
return Err(err);
|
||||
}
|
||||
|
|
|
@ -70,6 +70,7 @@ impl TypoSuggestion {
|
|||
}
|
||||
|
||||
/// A free importable items suggested in case of resolution failure.
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct ImportSuggestion {
|
||||
pub did: Option<DefId>,
|
||||
pub descr: &'static str,
|
||||
|
@ -139,6 +140,7 @@ impl<'a> Resolver<'a> {
|
|||
if instead { Instead::Yes } else { Instead::No },
|
||||
found_use,
|
||||
IsPattern::No,
|
||||
IsImport::No,
|
||||
path,
|
||||
);
|
||||
err.emit();
|
||||
|
@ -698,6 +700,7 @@ impl<'a> Resolver<'a> {
|
|||
Instead::No,
|
||||
FoundUse::Yes,
|
||||
IsPattern::Yes,
|
||||
IsImport::No,
|
||||
vec![],
|
||||
);
|
||||
}
|
||||
|
@ -1481,6 +1484,7 @@ impl<'a> Resolver<'a> {
|
|||
Instead::No,
|
||||
FoundUse::Yes,
|
||||
IsPattern::No,
|
||||
IsImport::No,
|
||||
vec![],
|
||||
);
|
||||
|
||||
|
@ -2449,6 +2453,34 @@ enum IsPattern {
|
|||
No,
|
||||
}
|
||||
|
||||
/// Whether a binding is part of a use statement. Used for diagnostics.
|
||||
enum IsImport {
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
|
||||
pub(crate) fn import_candidates(
|
||||
session: &Session,
|
||||
source_span: &IndexVec<LocalDefId, Span>,
|
||||
err: &mut Diagnostic,
|
||||
// This is `None` if all placement locations are inside expansions
|
||||
use_placement_span: Option<Span>,
|
||||
candidates: &[ImportSuggestion],
|
||||
) {
|
||||
show_candidates(
|
||||
session,
|
||||
source_span,
|
||||
err,
|
||||
use_placement_span,
|
||||
candidates,
|
||||
Instead::Yes,
|
||||
FoundUse::Yes,
|
||||
IsPattern::No,
|
||||
IsImport::Yes,
|
||||
vec![],
|
||||
);
|
||||
}
|
||||
|
||||
/// When an entity with a given name is not available in scope, we search for
|
||||
/// entities with that name in all crates. This method allows outputting the
|
||||
/// results of this search in a programmer-friendly way
|
||||
|
@ -2462,6 +2494,7 @@ fn show_candidates(
|
|||
instead: Instead,
|
||||
found_use: FoundUse,
|
||||
is_pattern: IsPattern,
|
||||
is_import: IsImport,
|
||||
path: Vec<Segment>,
|
||||
) {
|
||||
if candidates.is_empty() {
|
||||
|
@ -2521,7 +2554,8 @@ fn show_candidates(
|
|||
// produce an additional newline to separate the new use statement
|
||||
// from the directly following item.
|
||||
let additional_newline = if let FoundUse::Yes = found_use { "" } else { "\n" };
|
||||
candidate.0 = format!("use {};\n{}", &candidate.0, additional_newline);
|
||||
let add_use = if let IsImport::Yes = is_import { "" } else { "use " };
|
||||
candidate.0 = format!("{}{};\n{}", add_use, &candidate.0, additional_newline);
|
||||
}
|
||||
|
||||
err.span_suggestions(
|
||||
|
@ -2551,7 +2585,7 @@ fn show_candidates(
|
|||
|
||||
err.note(&msg);
|
||||
}
|
||||
} else {
|
||||
} else if matches!(is_import, IsImport::No) {
|
||||
assert!(!inaccessible_path_strings.is_empty());
|
||||
|
||||
let prefix =
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
//! A bunch of methods and structures more or less related to resolving imports.
|
||||
|
||||
use crate::diagnostics::Suggestion;
|
||||
use crate::diagnostics::{import_candidates, Suggestion};
|
||||
use crate::Determinacy::{self, *};
|
||||
use crate::Namespace::{self, *};
|
||||
use crate::{module_to_string, names_to_string};
|
||||
use crate::{module_to_string, names_to_string, ImportSuggestion};
|
||||
use crate::{AmbiguityKind, BindingKey, ModuleKind, ResolutionError, Resolver, Segment};
|
||||
use crate::{Finalize, Module, ModuleOrUniformRoot, ParentScope, PerNS, ScopeSet};
|
||||
use crate::{NameBinding, NameBindingKind, PathResult};
|
||||
|
@ -406,6 +406,7 @@ struct UnresolvedImportError {
|
|||
label: Option<String>,
|
||||
note: Option<String>,
|
||||
suggestion: Option<Suggestion>,
|
||||
candidate: Option<Vec<ImportSuggestion>>,
|
||||
}
|
||||
|
||||
pub struct ImportResolver<'a, 'b> {
|
||||
|
@ -497,6 +498,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
label: None,
|
||||
note: None,
|
||||
suggestion: None,
|
||||
candidate: None,
|
||||
};
|
||||
if path.contains("::") {
|
||||
errors.push((path, err))
|
||||
|
@ -547,6 +549,16 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
}
|
||||
diag.multipart_suggestion(&msg, suggestions, applicability);
|
||||
}
|
||||
|
||||
if let Some(candidate) = &err.candidate {
|
||||
import_candidates(
|
||||
self.r.session,
|
||||
&self.r.source_span,
|
||||
&mut diag,
|
||||
Some(err.span),
|
||||
&candidate,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
diag.emit();
|
||||
|
@ -664,6 +676,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
Some(finalize),
|
||||
ignore_binding,
|
||||
);
|
||||
|
||||
let no_ambiguity = self.r.ambiguity_errors.len() == prev_ambiguity_errors_len;
|
||||
import.vis.set(orig_vis);
|
||||
let module = match path_res {
|
||||
|
@ -706,12 +719,14 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
String::from("a similar path exists"),
|
||||
Applicability::MaybeIncorrect,
|
||||
)),
|
||||
candidate: None,
|
||||
},
|
||||
None => UnresolvedImportError {
|
||||
span,
|
||||
label: Some(label),
|
||||
note: None,
|
||||
suggestion,
|
||||
candidate: None,
|
||||
},
|
||||
};
|
||||
return Some(err);
|
||||
|
@ -754,6 +769,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
label: Some(String::from("cannot glob-import a module into itself")),
|
||||
note: None,
|
||||
suggestion: None,
|
||||
candidate: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -919,11 +935,19 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
}
|
||||
};
|
||||
|
||||
let parent_suggestion =
|
||||
self.r.lookup_import_candidates(ident, TypeNS, &import.parent_scope, |_| true);
|
||||
|
||||
Some(UnresolvedImportError {
|
||||
span: import.span,
|
||||
label: Some(label),
|
||||
note,
|
||||
suggestion,
|
||||
candidate: if !parent_suggestion.is_empty() {
|
||||
Some(parent_suggestion)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
})
|
||||
} else {
|
||||
// `resolve_ident_in_module` reported a privacy error.
|
||||
|
|
|
@ -1255,6 +1255,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
found_span,
|
||||
found_trait_ref,
|
||||
expected_trait_ref,
|
||||
obligation.cause.code(),
|
||||
)
|
||||
} else {
|
||||
let (closure_span, found) = found_did
|
||||
|
|
|
@ -254,8 +254,15 @@ pub trait TypeErrCtxtExt<'tcx> {
|
|||
found_span: Option<Span>,
|
||||
found: ty::PolyTraitRef<'tcx>,
|
||||
expected: ty::PolyTraitRef<'tcx>,
|
||||
cause: &ObligationCauseCode<'tcx>,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
|
||||
|
||||
fn note_conflicting_closure_bounds(
|
||||
&self,
|
||||
cause: &ObligationCauseCode<'tcx>,
|
||||
err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
|
||||
);
|
||||
|
||||
fn suggest_fully_qualified_path(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
|
@ -1584,6 +1591,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
found_span: Option<Span>,
|
||||
found: ty::PolyTraitRef<'tcx>,
|
||||
expected: ty::PolyTraitRef<'tcx>,
|
||||
cause: &ObligationCauseCode<'tcx>,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
pub(crate) fn build_fn_sig_ty<'tcx>(
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
|
@ -1645,9 +1653,68 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
let signature_kind = format!("{argument_kind} signature");
|
||||
err.note_expected_found(&signature_kind, expected_str, &signature_kind, found_str);
|
||||
|
||||
self.note_conflicting_closure_bounds(cause, &mut err);
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
// Add a note if there are two `Fn`-family bounds that have conflicting argument
|
||||
// requirements, which will always cause a closure to have a type error.
|
||||
fn note_conflicting_closure_bounds(
|
||||
&self,
|
||||
cause: &ObligationCauseCode<'tcx>,
|
||||
err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
|
||||
) {
|
||||
// First, look for an `ExprBindingObligation`, which means we can get
|
||||
// the unsubstituted predicate list of the called function. And check
|
||||
// that the predicate that we failed to satisfy is a `Fn`-like trait.
|
||||
if let ObligationCauseCode::ExprBindingObligation(def_id, _, _, idx) = cause
|
||||
&& let predicates = self.tcx.predicates_of(def_id).instantiate_identity(self.tcx)
|
||||
&& let Some(pred) = predicates.predicates.get(*idx)
|
||||
&& let ty::PredicateKind::Trait(trait_pred) = pred.kind().skip_binder()
|
||||
&& ty::ClosureKind::from_def_id(self.tcx, trait_pred.def_id()).is_some()
|
||||
{
|
||||
let expected_self =
|
||||
self.tcx.anonymize_late_bound_regions(pred.kind().rebind(trait_pred.self_ty()));
|
||||
let expected_substs = self
|
||||
.tcx
|
||||
.anonymize_late_bound_regions(pred.kind().rebind(trait_pred.trait_ref.substs));
|
||||
|
||||
// Find another predicate whose self-type is equal to the expected self type,
|
||||
// but whose substs don't match.
|
||||
let other_pred = std::iter::zip(&predicates.predicates, &predicates.spans)
|
||||
.enumerate()
|
||||
.find(|(other_idx, (pred, _))| match pred.kind().skip_binder() {
|
||||
ty::PredicateKind::Trait(trait_pred)
|
||||
if ty::ClosureKind::from_def_id(self.tcx, trait_pred.def_id())
|
||||
.is_some()
|
||||
&& other_idx != idx
|
||||
// Make sure that the self type matches
|
||||
// (i.e. constraining this closure)
|
||||
&& expected_self
|
||||
== self.tcx.anonymize_late_bound_regions(
|
||||
pred.kind().rebind(trait_pred.self_ty()),
|
||||
)
|
||||
// But the substs don't match (i.e. incompatible args)
|
||||
&& expected_substs
|
||||
!= self.tcx.anonymize_late_bound_regions(
|
||||
pred.kind().rebind(trait_pred.trait_ref.substs),
|
||||
) =>
|
||||
{
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
});
|
||||
// If we found one, then it's very likely the cause of the error.
|
||||
if let Some((_, (_, other_pred_span))) = other_pred {
|
||||
err.span_note(
|
||||
*other_pred_span,
|
||||
"closure inferred to have a different signature due to this bound",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn suggest_fully_qualified_path(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue