mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
Auto merge of #112900 - GuillaumeGomez:rollup-1blf4io, r=GuillaumeGomez
Rollup of 4 pull requests Successful merges: - #112538 (Removed unnecessary &String -> &str, now that &String implements StableOrd as well) - #112868 (Liberate bound vars properly when suggesting missing async-fn-in-trait) - #112892 (resolve: Minor cleanup to `fn resolve_path_with_ribs`) - #112894 (Fix union fields display) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
065a1f5df9
@ -107,6 +107,10 @@ impl<T, I: Iterator<Item = T>> UnordItems<T, I> {
|
||||
{
|
||||
UnordItems(self.0.flat_map(f))
|
||||
}
|
||||
|
||||
pub fn collect<C: From<UnordItems<T, I>>>(self) -> C {
|
||||
self.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> UnordItems<T, std::iter::Empty<T>> {
|
||||
@ -161,10 +165,6 @@ impl<T: Ord, I: Iterator<Item = T>> UnordItems<T, I> {
|
||||
items.sort_by_cached_key(|x| x.to_stable_hash_key(hcx));
|
||||
items
|
||||
}
|
||||
|
||||
pub fn collect<C: From<UnordItems<T, I>>>(self) -> C {
|
||||
self.into()
|
||||
}
|
||||
}
|
||||
|
||||
/// This is a set collection type that tries very hard to not expose
|
||||
|
@ -470,19 +470,16 @@ fn suggestion_signature<'tcx>(
|
||||
);
|
||||
|
||||
match assoc.kind {
|
||||
ty::AssocKind::Fn => {
|
||||
// We skip the binder here because the binder would deanonymize all
|
||||
// late-bound regions, and we don't want method signatures to show up
|
||||
// `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound
|
||||
// regions just fine, showing `fn(&MyType)`.
|
||||
fn_sig_suggestion(
|
||||
tcx,
|
||||
tcx.fn_sig(assoc.def_id).subst(tcx, substs).skip_binder(),
|
||||
assoc.ident(tcx),
|
||||
tcx.predicates_of(assoc.def_id).instantiate_own(tcx, substs),
|
||||
assoc,
|
||||
)
|
||||
}
|
||||
ty::AssocKind::Fn => fn_sig_suggestion(
|
||||
tcx,
|
||||
tcx.liberate_late_bound_regions(
|
||||
assoc.def_id,
|
||||
tcx.fn_sig(assoc.def_id).subst(tcx, substs),
|
||||
),
|
||||
assoc.ident(tcx),
|
||||
tcx.predicates_of(assoc.def_id).instantiate_own(tcx, substs),
|
||||
assoc,
|
||||
),
|
||||
ty::AssocKind::Type => {
|
||||
let (generics, where_clauses) = bounds_from_generic_predicates(
|
||||
tcx,
|
||||
|
@ -198,7 +198,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> {
|
||||
let (name, mut auto) = self.auto_labels(item_id, attr);
|
||||
let except = self.except(attr);
|
||||
let loaded_from_disk = self.loaded_from_disk(attr);
|
||||
for e in except.items().map(|x| x.as_str()).into_sorted_stable_ord() {
|
||||
for e in except.items().into_sorted_stable_ord() {
|
||||
if !auto.remove(e) {
|
||||
self.tcx.sess.emit_fatal(errors::AssertionAuto { span: attr.span, name, e });
|
||||
}
|
||||
@ -377,17 +377,15 @@ impl<'tcx> DirtyCleanVisitor<'tcx> {
|
||||
continue;
|
||||
};
|
||||
self.checked_attrs.insert(attr.id);
|
||||
for label in assertion.clean.items().map(|x| x.as_str()).into_sorted_stable_ord() {
|
||||
for label in assertion.clean.items().into_sorted_stable_ord() {
|
||||
let dep_node = DepNode::from_label_string(self.tcx, &label, def_path_hash).unwrap();
|
||||
self.assert_clean(item_span, dep_node);
|
||||
}
|
||||
for label in assertion.dirty.items().map(|x| x.as_str()).into_sorted_stable_ord() {
|
||||
for label in assertion.dirty.items().into_sorted_stable_ord() {
|
||||
let dep_node = DepNode::from_label_string(self.tcx, &label, def_path_hash).unwrap();
|
||||
self.assert_dirty(item_span, dep_node);
|
||||
}
|
||||
for label in
|
||||
assertion.loaded_from_disk.items().map(|x| x.as_str()).into_sorted_stable_ord()
|
||||
{
|
||||
for label in assertion.loaded_from_disk.items().into_sorted_stable_ord() {
|
||||
let dep_node = DepNode::from_label_string(self.tcx, &label, def_path_hash).unwrap();
|
||||
self.assert_loaded_from_disk(item_span, dep_node);
|
||||
}
|
||||
|
@ -855,12 +855,11 @@ fn all_except_most_recent(
|
||||
let most_recent = deletion_candidates.items().map(|(&(timestamp, _), _)| timestamp).max();
|
||||
|
||||
if let Some(most_recent) = most_recent {
|
||||
UnordMap::from(
|
||||
deletion_candidates
|
||||
.into_items()
|
||||
.filter(|&((timestamp, _), _)| timestamp != most_recent)
|
||||
.map(|((_, path), lock)| (path, lock)),
|
||||
)
|
||||
deletion_candidates
|
||||
.into_items()
|
||||
.filter(|&((timestamp, _), _)| timestamp != most_recent)
|
||||
.map(|((_, path), lock)| (path, lock))
|
||||
.collect()
|
||||
} else {
|
||||
UnordMap::default()
|
||||
}
|
||||
|
@ -1459,60 +1459,47 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
});
|
||||
}
|
||||
|
||||
enum FindBindingResult<'a> {
|
||||
Binding(Result<&'a NameBinding<'a>, Determinacy>),
|
||||
Res(Res),
|
||||
}
|
||||
let find_binding_in_ns = |this: &mut Self, ns| {
|
||||
let binding = if let Some(module) = module {
|
||||
this.resolve_ident_in_module(
|
||||
module,
|
||||
ident,
|
||||
ns,
|
||||
parent_scope,
|
||||
finalize,
|
||||
ignore_binding,
|
||||
)
|
||||
} else if let Some(ribs) = ribs
|
||||
&& let Some(TypeNS | ValueNS) = opt_ns
|
||||
{
|
||||
match this.resolve_ident_in_lexical_scope(
|
||||
ident,
|
||||
ns,
|
||||
parent_scope,
|
||||
finalize,
|
||||
&ribs[ns],
|
||||
ignore_binding,
|
||||
) {
|
||||
// we found a locally-imported or available item/module
|
||||
Some(LexicalScopeBinding::Item(binding)) => Ok(binding),
|
||||
// we found a local variable or type param
|
||||
Some(LexicalScopeBinding::Res(res)) => return FindBindingResult::Res(res),
|
||||
_ => Err(Determinacy::determined(finalize.is_some())),
|
||||
let binding = if let Some(module) = module {
|
||||
self.resolve_ident_in_module(
|
||||
module,
|
||||
ident,
|
||||
ns,
|
||||
parent_scope,
|
||||
finalize,
|
||||
ignore_binding,
|
||||
)
|
||||
} else if let Some(ribs) = ribs && let Some(TypeNS | ValueNS) = opt_ns {
|
||||
match self.resolve_ident_in_lexical_scope(
|
||||
ident,
|
||||
ns,
|
||||
parent_scope,
|
||||
finalize,
|
||||
&ribs[ns],
|
||||
ignore_binding,
|
||||
) {
|
||||
// we found a locally-imported or available item/module
|
||||
Some(LexicalScopeBinding::Item(binding)) => Ok(binding),
|
||||
// we found a local variable or type param
|
||||
Some(LexicalScopeBinding::Res(res)) => {
|
||||
record_segment_res(self, res);
|
||||
return PathResult::NonModule(PartialRes::with_unresolved_segments(
|
||||
res,
|
||||
path.len() - 1,
|
||||
));
|
||||
}
|
||||
} else {
|
||||
let scopes = ScopeSet::All(ns, opt_ns.is_none());
|
||||
this.early_resolve_ident_in_lexical_scope(
|
||||
ident,
|
||||
scopes,
|
||||
parent_scope,
|
||||
finalize,
|
||||
finalize.is_some(),
|
||||
ignore_binding,
|
||||
)
|
||||
};
|
||||
FindBindingResult::Binding(binding)
|
||||
};
|
||||
let binding = match find_binding_in_ns(self, ns) {
|
||||
FindBindingResult::Res(res) => {
|
||||
record_segment_res(self, res);
|
||||
return PathResult::NonModule(PartialRes::with_unresolved_segments(
|
||||
res,
|
||||
path.len() - 1,
|
||||
));
|
||||
_ => Err(Determinacy::determined(finalize.is_some())),
|
||||
}
|
||||
FindBindingResult::Binding(binding) => binding,
|
||||
} else {
|
||||
self.early_resolve_ident_in_lexical_scope(
|
||||
ident,
|
||||
ScopeSet::All(ns, opt_ns.is_none()),
|
||||
parent_scope,
|
||||
finalize,
|
||||
finalize.is_some(),
|
||||
ignore_binding,
|
||||
)
|
||||
};
|
||||
|
||||
match binding {
|
||||
Ok(binding) => {
|
||||
if segment_idx == 1 {
|
||||
|
@ -421,11 +421,10 @@ fn document<'a, 'cx: 'a>(
|
||||
display_fn(move |f| {
|
||||
document_item_info(cx, item, parent).render_into(f).unwrap();
|
||||
if parent.is_none() {
|
||||
write!(f, "{}", document_full_collapsible(item, cx, heading_offset))?;
|
||||
write!(f, "{}", document_full_collapsible(item, cx, heading_offset))
|
||||
} else {
|
||||
write!(f, "{}", document_full(item, cx, heading_offset))?;
|
||||
write!(f, "{}", document_full(item, cx, heading_offset))
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
{% if !items.is_empty() %}
|
||||
<span class="item-info"> {# #}
|
||||
<span class="item-info">
|
||||
{% for item in items %}
|
||||
{{item|safe}} {# #}
|
||||
{% endfor %}
|
||||
|
@ -4,14 +4,15 @@
|
||||
</code></pre>
|
||||
{{ self.document() | safe }}
|
||||
{% if self.fields_iter().peek().is_some() %}
|
||||
<h2 id="fields" class="fields small-section-header">
|
||||
Fields<a href="#fields" class="anchor">§</a>
|
||||
<h2 id="fields" class="fields small-section-header"> {# #}
|
||||
Fields<a href="#fields" class="anchor">§</a> {# #}
|
||||
</h2>
|
||||
{% for (field, ty) in self.fields_iter() %}
|
||||
{% let name = field.name.expect("union field name") %}
|
||||
<span id="structfield.{{ name }}" class="{{ ItemType::StructField }} small-section-header">
|
||||
<a href="#structfield.{{ name }}" class="anchor field">§</a>
|
||||
<code>{{ name }}: {{ self.print_ty(ty) | safe }}</code>
|
||||
<span id="structfield.{{ name }}" {#+ #}
|
||||
class="{{ ItemType::StructField +}} small-section-header"> {# #}
|
||||
<a href="#structfield.{{ name }}" class="anchor field">§</a> {# #}
|
||||
<code>{{ name }}: {{+ self.print_ty(ty) | safe }}</code> {# #}
|
||||
</span>
|
||||
{% if let Some(stability_class) = self.stability_field(field) %}
|
||||
<span class="stab {{ stability_class }}"></span>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<div class="main-heading"> {# #}
|
||||
<h1> {# #}
|
||||
<h1>
|
||||
{{typ}}
|
||||
{# The breadcrumbs of the item path, like std::string #}
|
||||
{% for component in path_components %}
|
||||
@ -12,7 +12,7 @@
|
||||
alt="Copy item path"> {# #}
|
||||
</button> {# #}
|
||||
</h1> {# #}
|
||||
<span class="out-of-band"> {# #}
|
||||
<span class="out-of-band">
|
||||
{% if !stability_since_raw.is_empty() %}
|
||||
{{ stability_since_raw|safe +}} · {#+ #}
|
||||
{% endif %}
|
||||
|
18
tests/rustdoc-gui/fields.goml
Normal file
18
tests/rustdoc-gui/fields.goml
Normal file
@ -0,0 +1,18 @@
|
||||
// This test checks that fields are displayed as expected (one by line).
|
||||
go-to: "file://" + |DOC_PATH| + "/test_docs/fields/struct.Struct.html"
|
||||
store-position: ("#structfield\.a", {"y": a_y})
|
||||
store-position: ("#structfield\.b", {"y": b_y})
|
||||
assert: |a_y| < |b_y|
|
||||
|
||||
go-to: "file://" + |DOC_PATH| + "/test_docs/fields/union.Union.html"
|
||||
store-position: ("#structfield\.a", {"y": a_y})
|
||||
store-position: ("#structfield\.b", {"y": b_y})
|
||||
assert: |a_y| < |b_y|
|
||||
|
||||
go-to: "file://" + |DOC_PATH| + "/test_docs/fields/enum.Enum.html"
|
||||
store-position: ("#variant\.A\.field\.a", {"y": a_y})
|
||||
store-position: ("#variant\.A\.field\.b", {"y": b_y})
|
||||
assert: |a_y| < |b_y|
|
||||
store-position: ("#variant\.B\.field\.a", {"y": a_y})
|
||||
store-position: ("#variant\.B\.field\.b", {"y": b_y})
|
||||
assert: |a_y| < |b_y|
|
@ -486,3 +486,24 @@ pub mod search_results {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub mod fields {
|
||||
pub struct Struct {
|
||||
pub a: u8,
|
||||
pub b: u32,
|
||||
}
|
||||
pub union Union {
|
||||
pub a: u8,
|
||||
pub b: u32,
|
||||
}
|
||||
pub enum Enum {
|
||||
A {
|
||||
a: u8,
|
||||
b: u32,
|
||||
},
|
||||
B {
|
||||
a: u8,
|
||||
b: u32,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
11
tests/rustdoc/union-fields-html.rs
Normal file
11
tests/rustdoc/union-fields-html.rs
Normal file
@ -0,0 +1,11 @@
|
||||
#![crate_name = "foo"]
|
||||
|
||||
// @has 'foo/union.Union.html'
|
||||
// Checking that there is a whitespace after `:`.
|
||||
// @has - '//*[@id="structfield.a"]/code' 'a: u8'
|
||||
// @has - '//*[@id="structfield.b"]/code' 'b: u32'
|
||||
pub union Union {
|
||||
pub a: u8,
|
||||
/// tadam
|
||||
pub b: u32,
|
||||
}
|
@ -9,11 +9,14 @@ trait Trait {
|
||||
async fn bar() -> i32;
|
||||
|
||||
fn test(&self) -> impl Sized + '_;
|
||||
|
||||
async fn baz(&self) -> &i32;
|
||||
}
|
||||
|
||||
struct S;
|
||||
|
||||
impl Trait for S {fn test(&self) -> impl Sized + '_ { todo!() }
|
||||
impl Trait for S {async fn baz(&self) -> &i32 { todo!() }
|
||||
fn test(&self) -> impl Sized + '_ { todo!() }
|
||||
async fn bar() -> i32 { todo!() }
|
||||
async fn foo() { todo!() }
|
||||
}
|
||||
|
@ -9,6 +9,8 @@ trait Trait {
|
||||
async fn bar() -> i32;
|
||||
|
||||
fn test(&self) -> impl Sized + '_;
|
||||
|
||||
async fn baz(&self) -> &i32;
|
||||
}
|
||||
|
||||
struct S;
|
||||
|
@ -1,5 +1,5 @@
|
||||
error[E0046]: not all trait items implemented, missing: `foo`, `bar`, `test`
|
||||
--> $DIR/suggest-missing-item.rs:16:1
|
||||
error[E0046]: not all trait items implemented, missing: `foo`, `bar`, `test`, `baz`
|
||||
--> $DIR/suggest-missing-item.rs:18:1
|
||||
|
|
||||
LL | async fn foo();
|
||||
| --------------- `foo` from trait
|
||||
@ -9,9 +9,12 @@ LL | async fn bar() -> i32;
|
||||
LL |
|
||||
LL | fn test(&self) -> impl Sized + '_;
|
||||
| ---------------------------------- `test` from trait
|
||||
LL |
|
||||
LL | async fn baz(&self) -> &i32;
|
||||
| ---------------------------- `baz` from trait
|
||||
...
|
||||
LL | impl Trait for S {}
|
||||
| ^^^^^^^^^^^^^^^^ missing `foo`, `bar`, `test` in implementation
|
||||
| ^^^^^^^^^^^^^^^^ missing `foo`, `bar`, `test`, `baz` in implementation
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user