Skip to content

Rollup of 9 pull requests #98447

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 24 commits into from
Jun 24, 2022
Merged
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
f7d12b4
Session object: Decouple e_flags from FileFlags
mkroening Jun 1, 2022
37fd294
rustc_target: Remove some redundant target properties
petrochenkov Jun 17, 2022
3f12fa7
Add support for macro in "jump to def" feature
GuillaumeGomez Nov 26, 2021
dda980d
Rename ContextInfo into HrefContext
GuillaumeGomez Jun 18, 2022
810254b
Improve code readability and documentation
GuillaumeGomez Jun 18, 2022
f4db07e
Add test for macro support in "jump to def" feature
GuillaumeGomez Nov 26, 2021
987c731
Integrate `generate_macro_def_id_path` into `href_with_root_path`
GuillaumeGomez Jun 20, 2022
beb2f36
Fix panic by checking if `CStore` has the crate data we want before a…
GuillaumeGomez Jun 20, 2022
d15fed7
Improve suggestion for calling closure on type mismatch
compiler-errors Jun 20, 2022
94477e3
Fixup missing renames from `#[main]` to `#[rustc_main]`
Enselic Jun 22, 2022
36ccdbe
Remove (transitive) reliance on sorting by DefId in pretty-printer
Aaron1011 May 11, 2022
04b75a7
Update tendril
ehuss Jun 22, 2022
9730221
Remove excess rib while resolving closures
WaffleLapkin Jun 23, 2022
21625e5
Session object: Set OS/ABI
mkroening Jun 1, 2022
774e814
Fix BTreeSet's range API panic message, document
tnballo Jun 23, 2022
97f4d7b
Rollup merge of #91264 - GuillaumeGomez:macro-jump-to-def, r=jsha
JohnTitor Jun 24, 2022
2c6feb5
Rollup merge of #96955 - Aaron1011:pretty-print-sort, r=petrochenkov
JohnTitor Jun 24, 2022
0af99c9
Rollup merge of #97633 - mkroening:object-osabi, r=petrochenkov
JohnTitor Jun 24, 2022
6580d7e
Rollup merge of #98039 - tnballo:master, r=thomcc
JohnTitor Jun 24, 2022
33eb3c0
Rollup merge of #98214 - petrochenkov:islike, r=compiler-errors
JohnTitor Jun 24, 2022
964fc41
Rollup merge of #98280 - compiler-errors:better-call-closure-on-type-…
JohnTitor Jun 24, 2022
f3078d0
Rollup merge of #98394 - Enselic:fixup-rustc_main-renames, r=petroche…
JohnTitor Jun 24, 2022
d26b03c
Rollup merge of #98411 - ehuss:update-tendril, r=Mark-Simulacrum
JohnTitor Jun 24, 2022
5e98e55
Rollup merge of #98419 - WaffleLapkin:remove_excess_rib, r=compiler-e…
JohnTitor Jun 24, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions Cargo.lock
Original file line number Diff line number Diff line change
@@ -1428,9 +1428,9 @@ checksum = "d79238883cf0307100b90aba4a755d8051a3182305dfe7f649a1e9dc0517006f"

[[package]]
name = "futf"
version = "0.1.4"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c9c1ce3fa9336301af935ab852c437817d14cd33690446569392e65170aac3b"
checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843"
dependencies = [
"mac",
"new_debug_unreachable",
@@ -1713,6 +1713,7 @@ version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c21d40587b92fa6a6c6e3c1bdbf87d75511db5672f9c93175574b3a00df1758"
dependencies = [
"ahash",
"compiler_builtins",
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
@@ -2571,6 +2572,18 @@ dependencies = [
"memchr",
]

[[package]]
name = "object"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53"
dependencies = [
"crc32fast",
"hashbrown 0.12.0",
"indexmap",
"memchr",
]

[[package]]
name = "odht"
version = "0.3.1"
@@ -3720,7 +3733,7 @@ dependencies = [
"itertools",
"jobserver",
"libc",
"object 0.28.4",
"object 0.29.0",
"pathdiff",
"regex",
"rustc_apfloat",
@@ -5191,9 +5204,9 @@ dependencies = [

[[package]]
name = "tendril"
version = "0.4.1"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "707feda9f2582d5d680d733e38755547a3e8fb471e7ba11452ecfd9ce93a5d3b"
checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0"
dependencies = [
"futf",
"mac",
2 changes: 1 addition & 1 deletion compiler/rustc_ast/src/entry.rs
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@
pub enum EntryPointType {
None,
MainNamed,
MainAttr,
RustcMainAttr,
Start,
OtherMain, // Not an entry point, but some other function named main
}
11 changes: 6 additions & 5 deletions compiler/rustc_builtin_macros/src/test_harness.rs
Original file line number Diff line number Diff line change
@@ -147,7 +147,7 @@ fn entry_point_type(sess: &Session, item: &ast::Item, depth: usize) -> EntryPoin
if sess.contains_name(&item.attrs, sym::start) {
EntryPointType::Start
} else if sess.contains_name(&item.attrs, sym::rustc_main) {
EntryPointType::MainAttr
EntryPointType::RustcMainAttr
} else if item.ident.name == sym::main {
if depth == 0 {
// This is a top-level function so can be 'main'
@@ -177,12 +177,12 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> {
let item = noop_flat_map_item(i, self).expect_one("noop did something");
self.depth -= 1;

// Remove any #[main] or #[start] from the AST so it doesn't
// Remove any #[rustc_main] or #[start] from the AST so it doesn't
// clash with the one we're going to add, but mark it as
// #[allow(dead_code)] to avoid printing warnings.
let item = match entry_point_type(self.sess, &item, self.depth) {
EntryPointType::MainNamed | EntryPointType::MainAttr | EntryPointType::Start => item
.map(|ast::Item { id, ident, attrs, kind, vis, span, tokens }| {
EntryPointType::MainNamed | EntryPointType::RustcMainAttr | EntryPointType::Start => {
item.map(|ast::Item { id, ident, attrs, kind, vis, span, tokens }| {
let allow_ident = Ident::new(sym::allow, self.def_site);
let dc_nested =
attr::mk_nested_word_item(Ident::new(sym::dead_code, self.def_site));
@@ -197,7 +197,8 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> {
.collect();

ast::Item { id, ident, attrs, kind, vis, span, tokens }
}),
})
}
EntryPointType::None | EntryPointType::OtherMain => item,
};

2 changes: 1 addition & 1 deletion compiler/rustc_codegen_llvm/src/context.rs
Original file line number Diff line number Diff line change
@@ -906,7 +906,7 @@ impl<'ll> CodegenCx<'ll, '_> {
return eh_catch_typeinfo;
}
let tcx = self.tcx;
assert!(self.sess().target.is_like_emscripten);
assert!(self.sess().target.os == "emscripten");
let eh_catch_typeinfo = match tcx.lang_items().eh_catch_typeinfo() {
Some(def_id) => self.get_static(def_id),
_ => {
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_llvm/src/intrinsic.rs
Original file line number Diff line number Diff line change
@@ -441,7 +441,7 @@ fn try_intrinsic<'ll>(
bx.store(bx.const_i32(0), dest, ret_align);
} else if wants_msvc_seh(bx.sess()) {
codegen_msvc_try(bx, try_func, data, catch_func, dest);
} else if bx.sess().target.is_like_emscripten {
} else if bx.sess().target.os == "emscripten" {
codegen_emcc_try(bx, try_func, data, catch_func, dest);
} else {
codegen_gnu_try(bx, try_func, data, catch_func, dest);
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_ssa/Cargo.toml
Original file line number Diff line number Diff line change
@@ -42,6 +42,6 @@ rustc_target = { path = "../rustc_target" }
rustc_session = { path = "../rustc_session" }

[dependencies.object]
version = "0.28.4"
version = "0.29.0"
default-features = false
features = ["read_core", "elf", "macho", "pe", "unaligned", "archive", "write"]
4 changes: 2 additions & 2 deletions compiler/rustc_codegen_ssa/src/back/link.rs
Original file line number Diff line number Diff line change
@@ -2031,7 +2031,7 @@ fn add_order_independent_options(

add_link_script(cmd, sess, tmpdir, crate_type);

if sess.target.is_like_fuchsia && crate_type == CrateType::Executable {
if sess.target.os == "fuchsia" && crate_type == CrateType::Executable {
let prefix = if sess.opts.debugging_opts.sanitizer.contains(SanitizerSet::ADDRESS) {
"asan/"
} else {
@@ -2051,7 +2051,7 @@ fn add_order_independent_options(
cmd.no_crt_objects();
}

if sess.target.is_like_emscripten {
if sess.target.os == "emscripten" {
cmd.arg("-s");
cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort {
"DISABLE_EXCEPTION_CATCHING=1"
19 changes: 14 additions & 5 deletions compiler/rustc_codegen_ssa/src/back/metadata.rs
Original file line number Diff line number Diff line change
@@ -130,7 +130,7 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
};

let mut file = write::Object::new(binary_format, architecture, endianness);
match architecture {
let e_flags = match architecture {
Architecture::Mips => {
let arch = match sess.target.options.cpu.as_ref() {
"mips1" => elf::EF_MIPS_ARCH_1,
@@ -149,7 +149,7 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
if sess.target.options.cpu.contains("r6") {
e_flags |= elf::EF_MIPS_NAN2008;
}
file.flags = FileFlags::Elf { e_flags };
e_flags
}
Architecture::Mips64 => {
// copied from `mips64el-linux-gnuabi64-gcc foo.c -c`
@@ -160,17 +160,26 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
} else {
elf::EF_MIPS_ARCH_64R2
};
file.flags = FileFlags::Elf { e_flags };
e_flags
}
Architecture::Riscv64 if sess.target.options.features.contains("+d") => {
// copied from `riscv64-linux-gnu-gcc foo.c -c`, note though
// that the `+d` target feature represents whether the double
// float abi is enabled.
let e_flags = elf::EF_RISCV_RVC | elf::EF_RISCV_FLOAT_ABI_DOUBLE;
file.flags = FileFlags::Elf { e_flags };
e_flags
}
_ => {}
_ => 0,
};
// adapted from LLVM's `MCELFObjectTargetWriter::getOSABI`
let os_abi = match sess.target.options.os.as_ref() {
"hermit" => elf::ELFOSABI_STANDALONE,
"freebsd" => elf::ELFOSABI_FREEBSD,
"solaris" => elf::ELFOSABI_SOLARIS,
_ => elf::ELFOSABI_NONE,
};
let abi_version = 0;
file.flags = FileFlags::Elf { os_abi, abi_version, e_flags };
Some(file)
}

4 changes: 4 additions & 0 deletions compiler/rustc_metadata/src/creader.rs
Original file line number Diff line number Diff line change
@@ -133,6 +133,10 @@ impl CStore {
CrateNum::new(self.metas.len() - 1)
}

pub fn has_crate_data(&self, cnum: CrateNum) -> bool {
self.metas[cnum].is_some()
}

pub(crate) fn get_crate_data(&self, cnum: CrateNum) -> CrateMetadataRef<'_> {
let cdata = self.metas[cnum]
.as_ref()
23 changes: 11 additions & 12 deletions compiler/rustc_middle/src/ty/print/pretty.rs
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ use crate::ty::{
TypeSuperFoldable,
};
use rustc_apfloat::ieee::{Double, Single};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_data_structures::sso::SsoHashSet;
use rustc_hir as hir;
use rustc_hir::def::{self, CtorKind, DefKind, Namespace};
@@ -779,8 +779,8 @@ pub trait PrettyPrinter<'tcx>:
// by looking up the projections associated with the def_id.
let bounds = self.tcx().bound_explicit_item_bounds(def_id);

let mut traits = BTreeMap::new();
let mut fn_traits = BTreeMap::new();
let mut traits = FxIndexMap::default();
let mut fn_traits = FxIndexMap::default();
let mut is_sized = false;

for predicate in bounds.transpose_iter().map(|e| e.map_bound(|(p, _)| *p)) {
@@ -856,7 +856,7 @@ pub trait PrettyPrinter<'tcx>:
p!(")");
if let Term::Ty(ty) = return_ty.skip_binder() {
if !ty.is_unit() {
p!("-> ", print(return_ty));
p!(" -> ", print(return_ty));
}
}
p!(write("{}", if paren_needed { ")" } else { "" }));
@@ -970,11 +970,11 @@ pub trait PrettyPrinter<'tcx>:
&mut self,
trait_ref: ty::PolyTraitRef<'tcx>,
proj_ty: Option<(DefId, ty::Binder<'tcx, Term<'tcx>>)>,
traits: &mut BTreeMap<
traits: &mut FxIndexMap<
ty::PolyTraitRef<'tcx>,
BTreeMap<DefId, ty::Binder<'tcx, Term<'tcx>>>,
FxIndexMap<DefId, ty::Binder<'tcx, Term<'tcx>>>,
>,
fn_traits: &mut BTreeMap<ty::PolyTraitRef<'tcx>, OpaqueFnEntry<'tcx>>,
fn_traits: &mut FxIndexMap<ty::PolyTraitRef<'tcx>, OpaqueFnEntry<'tcx>>,
) {
let trait_def_id = trait_ref.def_id();

@@ -1110,19 +1110,18 @@ pub trait PrettyPrinter<'tcx>:
// Builtin bounds.
// FIXME(eddyb) avoid printing twice (needed to ensure
// that the auto traits are sorted *and* printed via cx).
let mut auto_traits: Vec<_> =
predicates.auto_traits().map(|did| (self.tcx().def_path_str(did), did)).collect();
let mut auto_traits: Vec<_> = predicates.auto_traits().collect();

// The auto traits come ordered by `DefPathHash`. While
// `DefPathHash` is *stable* in the sense that it depends on
// neither the host nor the phase of the moon, it depends
// "pseudorandomly" on the compiler version and the target.
//
// To avoid that causing instabilities in compiletest
// To avoid causing instabilities in compiletest
// output, sort the auto-traits alphabetically.
auto_traits.sort();
auto_traits.sort_by_cached_key(|did| self.tcx().def_path_str(*did));

for (_, def_id) in auto_traits {
for def_id in auto_traits {
if !first {
p!(" + ");
}
10 changes: 5 additions & 5 deletions compiler/rustc_passes/src/entry.rs
Original file line number Diff line number Diff line change
@@ -56,7 +56,7 @@ fn entry_point_type(ctxt: &EntryContext<'_>, id: ItemId, at_root: bool) -> Entry
if ctxt.tcx.sess.contains_name(attrs, sym::start) {
EntryPointType::Start
} else if ctxt.tcx.sess.contains_name(attrs, sym::rustc_main) {
EntryPointType::MainAttr
EntryPointType::RustcMainAttr
} else {
if let Some(name) = ctxt.tcx.opt_item_name(id.def_id.to_def_id())
&& name == sym::main {
@@ -95,21 +95,21 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
EntryPointType::OtherMain => {
ctxt.non_main_fns.push(ctxt.tcx.def_span(id.def_id));
}
EntryPointType::MainAttr => {
EntryPointType::RustcMainAttr => {
if ctxt.attr_main_fn.is_none() {
ctxt.attr_main_fn = Some((id.def_id, ctxt.tcx.def_span(id.def_id.to_def_id())));
} else {
struct_span_err!(
ctxt.tcx.sess,
ctxt.tcx.def_span(id.def_id.to_def_id()),
E0137,
"multiple functions with a `#[main]` attribute"
"multiple functions with a `#[rustc_main]` attribute"
)
.span_label(
ctxt.tcx.def_span(id.def_id.to_def_id()),
"additional `#[main]` function",
"additional `#[rustc_main]` function",
)
.span_label(ctxt.attr_main_fn.unwrap().1, "first `#[main]` function")
.span_label(ctxt.attr_main_fn.unwrap().1, "first `#[rustc_main]` function")
.emit();
}
}
2 changes: 1 addition & 1 deletion compiler/rustc_passes/src/weak_lang_items.rs
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@ pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>, items: &mut lang_items::LanguageItem
if items.eh_personality().is_none() {
items.missing.push(LangItem::EhPersonality);
}
if tcx.sess.target.is_like_emscripten && items.eh_catch_typeinfo().is_none() {
if tcx.sess.target.os == "emscripten" && items.eh_catch_typeinfo().is_none() {
items.missing.push(LangItem::EhCatchTypeinfo);
}

4 changes: 3 additions & 1 deletion compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
@@ -3514,7 +3514,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
})
});
}
ExprKind::Async(..) | ExprKind::Closure(..) => {
// For closures, ClosureOrAsyncRibKind is added in visit_fn
ExprKind::Closure(..) => visit::walk_expr(self, expr),
ExprKind::Async(..) => {
self.with_label_rib(ClosureOrAsyncRibKind, |this| visit::walk_expr(this, expr));
}
ExprKind::Repeat(ref elem, ref ct) => {
2 changes: 1 addition & 1 deletion compiler/rustc_target/src/asm/aarch64.rs
Original file line number Diff line number Diff line change
@@ -74,7 +74,7 @@ impl AArch64InlineAsmRegClass {
}

pub fn target_reserves_x18(target: &Target) -> bool {
target.os == "android" || target.is_like_fuchsia || target.is_like_osx || target.is_like_windows
target.os == "android" || target.os == "fuchsia" || target.is_like_osx || target.is_like_windows
}

fn reserved_x18(
1 change: 0 additions & 1 deletion compiler/rustc_target/src/spec/fuchsia_base.rs
Original file line number Diff line number Diff line change
@@ -28,7 +28,6 @@ pub fn opts() -> TargetOptions {
dynamic_linking: true,
executables: true,
families: cvs!["unix"],
is_like_fuchsia: true,
pre_link_args,
pre_link_objects: crt_objects::new(&[
(LinkOutputKind::DynamicNoPicExe, &["Scrt1.o"]),
12 changes: 0 additions & 12 deletions compiler/rustc_target/src/spec/mod.rs
Original file line number Diff line number Diff line change
@@ -1273,12 +1273,6 @@ pub struct TargetOptions {
/// - uses SEH-based unwinding,
/// - supports control flow guard mechanism.
pub is_like_msvc: bool,
/// Whether the target toolchain is like Emscripten's. Only useful for compiling with
/// Emscripten toolchain.
/// Defaults to false.
pub is_like_emscripten: bool,
/// Whether the target toolchain is like Fuchsia's.
pub is_like_fuchsia: bool,
/// Whether a target toolchain is like WASM.
pub is_like_wasm: bool,
/// Version of DWARF to use if not using the default.
@@ -1505,9 +1499,7 @@ impl Default for TargetOptions {
is_like_osx: false,
is_like_solaris: false,
is_like_windows: false,
is_like_emscripten: false,
is_like_msvc: false,
is_like_fuchsia: false,
is_like_wasm: false,
dwarf_version: None,
linker_is_gnu: true,
@@ -2112,8 +2104,6 @@ impl Target {
key!(is_like_solaris, bool);
key!(is_like_windows, bool);
key!(is_like_msvc, bool);
key!(is_like_emscripten, bool);
key!(is_like_fuchsia, bool);
key!(is_like_wasm, bool);
key!(dwarf_version, Option<u32>);
key!(linker_is_gnu, bool);
@@ -2358,8 +2348,6 @@ impl ToJson for Target {
target_option_val!(is_like_solaris);
target_option_val!(is_like_windows);
target_option_val!(is_like_msvc);
target_option_val!(is_like_emscripten);
target_option_val!(is_like_fuchsia);
target_option_val!(is_like_wasm);
target_option_val!(dwarf_version);
target_option_val!(linker_is_gnu);
5 changes: 5 additions & 0 deletions compiler/rustc_target/src/spec/tests/tests_impl.rs
Original file line number Diff line number Diff line change
@@ -8,7 +8,12 @@ pub(super) fn test_target(target: Target) {

impl Target {
fn check_consistency(&self) {
assert_eq!(self.is_like_osx, self.vendor == "apple");
assert_eq!(self.is_like_solaris, self.os == "solaris" || self.os == "illumos");
assert_eq!(self.is_like_windows, self.os == "windows" || self.os == "uefi");
assert_eq!(self.is_like_wasm, self.arch == "wasm32" || self.arch == "wasm64");
assert!(self.is_like_windows || !self.is_like_msvc);

// Check that LLD with the given flavor is treated identically to the linker it emulates.
// If your target really needs to deviate from the rules below, except it and document the
// reasons.
Original file line number Diff line number Diff line change
@@ -26,7 +26,6 @@ pub fn target() -> Target {
// functionality, and a .wasm file.
exe_suffix: ".js".into(),
linker: None,
is_like_emscripten: true,
panic_strategy: PanicStrategy::Unwind,
no_default_libraries: false,
post_link_args,
189 changes: 76 additions & 113 deletions compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
Original file line number Diff line number Diff line change
@@ -8,15 +8,14 @@ use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind};
use rustc_hir::lang_items::LangItem;
use rustc_hir::{
Expr, ExprKind, GenericBound, ItemKind, Node, Path, QPath, Stmt, StmtKind, TyKind,
WherePredicate,
Expr, ExprKind, GenericBound, Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
};
use rustc_infer::infer::{self, TyCtxtInferExt};
use rustc_infer::traits;
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::{self, Binder, IsSuggestable, ToPredicate, Ty};
use rustc_span::symbol::{kw, sym};
use rustc_middle::ty::{self, Binder, IsSuggestable, Subst, ToPredicate, Ty};
use rustc_span::symbol::sym;
use rustc_span::Span;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;

@@ -78,124 +77,88 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected: Ty<'tcx>,
found: Ty<'tcx>,
) -> bool {
let hir = self.tcx.hir();
let (def_id, sig) = match *found.kind() {
ty::FnDef(def_id, _) => (def_id, found.fn_sig(self.tcx)),
ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig()),
let (def_id, output, inputs) = match *found.kind() {
ty::FnDef(def_id, _) => {
let fn_sig = found.fn_sig(self.tcx);
(def_id, fn_sig.output(), fn_sig.inputs().skip_binder().len())
}
ty::Closure(def_id, substs) => {
let fn_sig = substs.as_closure().sig();
(def_id, fn_sig.output(), fn_sig.inputs().skip_binder().len() - 1)
}
ty::Opaque(def_id, substs) => {
let sig = self.tcx.bound_item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| {
if let ty::PredicateKind::Projection(proj) = pred.kind().skip_binder()
&& Some(proj.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output()
// args tuple will always be substs[1]
&& let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
{
Some((
pred.kind().rebind(proj.term.ty().unwrap()),
args.len(),
))
} else {
None
}
});
if let Some((output, inputs)) = sig {
(def_id, output, inputs)
} else {
return false;
}
}
_ => return false,
};

let sig = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, sig);
let sig = self.normalize_associated_types_in(expr.span, sig);
if self.can_coerce(sig.output(), expected) {
let (mut sugg_call, applicability) = if sig.inputs().is_empty() {
(String::new(), Applicability::MachineApplicable)
} else {
("...".to_string(), Applicability::HasPlaceholders)
let output = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, output);
let output = self.normalize_associated_types_in(expr.span, output);
if !output.is_ty_var() && self.can_coerce(output, expected) {
let (sugg_call, mut applicability) = match inputs {
0 => ("".to_string(), Applicability::MachineApplicable),
1..=4 => (
(0..inputs).map(|_| "_").collect::<Vec<_>>().join(", "),
Applicability::MachineApplicable,
),
_ => ("...".to_string(), Applicability::HasPlaceholders),
};
let mut msg = "call this function";
match hir.get_if_local(def_id) {
Some(
Node::Item(hir::Item { kind: ItemKind::Fn(.., body_id), .. })
| Node::ImplItem(hir::ImplItem {
kind: hir::ImplItemKind::Fn(_, body_id), ..
})
| Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Fn(.., hir::TraitFn::Provided(body_id)),
..
}),
) => {
let body = hir.body(*body_id);
sugg_call = body
.params
.iter()
.map(|param| match &param.pat.kind {
hir::PatKind::Binding(_, _, ident, None)
if ident.name != kw::SelfLower =>
{
ident.to_string()
}
_ => "_".to_string(),
})
.collect::<Vec<_>>()
.join(", ");
}
Some(Node::Expr(hir::Expr {
kind: ExprKind::Closure { body: body_id, .. },
span: full_closure_span,
..
})) => {
if *full_closure_span == expr.span {
return false;
}
msg = "call this closure";
let body = hir.body(*body_id);
sugg_call = body
.params
.iter()
.map(|param| match &param.pat.kind {
hir::PatKind::Binding(_, _, ident, None)
if ident.name != kw::SelfLower =>
{
ident.to_string()
}
_ => "_".to_string(),
})
.collect::<Vec<_>>()
.join(", ");
}
Some(Node::Ctor(hir::VariantData::Tuple(fields, _))) => {
sugg_call = fields.iter().map(|_| "_").collect::<Vec<_>>().join(", ");
match def_id.as_local().map(|def_id| self.tcx.def_kind(def_id)) {
Some(DefKind::Ctor(hir::def::CtorOf::Variant, _)) => {
msg = "instantiate this tuple variant";
}
Some(DefKind::Ctor(CtorOf::Struct, _)) => {
msg = "instantiate this tuple struct";
}
_ => {}
}

let msg = match self.tcx.def_kind(def_id) {
DefKind::Fn => "call this function",
DefKind::Closure | DefKind::OpaqueTy => "call this closure",
DefKind::Ctor(CtorOf::Struct, _) => "instantiate this tuple struct",
DefKind::Ctor(CtorOf::Variant, _) => "instantiate this tuple variant",
_ => "call this function",
};

let sugg = match expr.kind {
hir::ExprKind::Call(..)
| hir::ExprKind::Path(..)
| hir::ExprKind::Index(..)
| hir::ExprKind::Lit(..) => {
vec![(expr.span.shrink_to_hi(), format!("({sugg_call})"))]
}
Some(Node::ForeignItem(hir::ForeignItem {
kind: hir::ForeignItemKind::Fn(_, idents, _),
..
})) => {
sugg_call = idents
.iter()
.map(|ident| {
if ident.name != kw::SelfLower {
ident.to_string()
} else {
"_".to_string()
}
})
.collect::<Vec<_>>()
.join(", ")
hir::ExprKind::Closure { .. } => {
// Might be `{ expr } || { bool }`
applicability = Applicability::MaybeIncorrect;
vec![
(expr.span.shrink_to_lo(), "(".to_string()),
(expr.span.shrink_to_hi(), format!(")({sugg_call})")),
]
}
Some(Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Fn(.., hir::TraitFn::Required(idents)),
..
})) => {
sugg_call = idents
.iter()
.map(|ident| {
if ident.name != kw::SelfLower {
ident.to_string()
} else {
"_".to_string()
}
})
.collect::<Vec<_>>()
.join(", ")
_ => {
vec![
(expr.span.shrink_to_lo(), "(".to_string()),
(expr.span.shrink_to_hi(), format!(")({sugg_call})")),
]
}
_ => {}
}
err.span_suggestion_verbose(
expr.span.shrink_to_hi(),
&format!("use parentheses to {}", msg),
format!("({})", sugg_call),
};

err.multipart_suggestion_verbose(
format!("use parentheses to {msg}"),
sugg,
applicability,
);

return true;
}
false
5 changes: 3 additions & 2 deletions library/alloc/src/collections/btree/map.rs
Original file line number Diff line number Diff line change
@@ -16,6 +16,7 @@ use super::dedup_sorted_iter::DedupSortedIter;
use super::navigate::{LazyLeafRange, LeafRange};
use super::node::{self, marker, ForceResult::*, Handle, NodeRef, Root};
use super::search::SearchResult::*;
use super::set_val::SetValZST;

mod entry;

@@ -271,7 +272,7 @@ impl<K: Clone, V: Clone, A: Allocator + Clone> Clone for BTreeMap<K, V, A> {
}
}

impl<K, Q: ?Sized, A: Allocator + Clone> super::Recover<Q> for BTreeMap<K, (), A>
impl<K, Q: ?Sized, A: Allocator + Clone> super::Recover<Q> for BTreeMap<K, SetValZST, A>
where
K: Borrow<Q> + Ord,
Q: Ord,
@@ -318,7 +319,7 @@ where
alloc: (*map.alloc).clone(),
_marker: PhantomData,
}
.insert(());
.insert(SetValZST::default());
None
}
}
33 changes: 33 additions & 0 deletions library/alloc/src/collections/btree/map/tests.rs
Original file line number Diff line number Diff line change
@@ -897,6 +897,39 @@ fn test_range_mut() {
map.check();
}

#[should_panic(expected = "range start is greater than range end in BTreeMap")]
#[test]
fn test_range_panic_1() {
let mut map = BTreeMap::new();
map.insert(3, "a");
map.insert(5, "b");
map.insert(8, "c");

let _invalid_range = map.range((Included(&8), Included(&3)));
}

#[should_panic(expected = "range start and end are equal and excluded in BTreeMap")]
#[test]
fn test_range_panic_2() {
let mut map = BTreeMap::new();
map.insert(3, "a");
map.insert(5, "b");
map.insert(8, "c");

let _invalid_range = map.range((Excluded(&5), Excluded(&5)));
}

#[should_panic(expected = "range start and end are equal and excluded in BTreeMap")]
#[test]
fn test_range_panic_3() {
let mut map: BTreeMap<i32, ()> = BTreeMap::new();
map.insert(3, ());
map.insert(5, ());
map.insert(8, ());

let _invalid_range = map.range((Excluded(&5), Excluded(&5)));
}

#[test]
fn test_retain() {
let mut map = BTreeMap::from_iter((0..100).map(|x| (x, x * 10)));
1 change: 1 addition & 0 deletions library/alloc/src/collections/btree/mod.rs
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@ mod node;
mod remove;
mod search;
pub mod set;
mod set_val;
mod split;

#[doc(hidden)]
15 changes: 13 additions & 2 deletions library/alloc/src/collections/btree/search.rs
Original file line number Diff line number Diff line change
@@ -97,17 +97,28 @@ impl<BorrowType: marker::BorrowType, K, V> NodeRef<BorrowType, K, V, marker::Lea
K: Borrow<Q>,
R: RangeBounds<Q>,
{
// Determine if map or set is being searched
let is_set = <V as super::set_val::IsSetVal>::is_set_val();

// Inlining these variables should be avoided. We assume the bounds reported by `range`
// remain the same, but an adversarial implementation could change between calls (#81138).
let (start, end) = (range.start_bound(), range.end_bound());
match (start, end) {
(Bound::Excluded(s), Bound::Excluded(e)) if s == e => {
panic!("range start and end are equal and excluded in BTreeMap")
if is_set {
panic!("range start and end are equal and excluded in BTreeSet")
} else {
panic!("range start and end are equal and excluded in BTreeMap")
}
}
(Bound::Included(s) | Bound::Excluded(s), Bound::Included(e) | Bound::Excluded(e))
if s > e =>
{
panic!("range start is greater than range end in BTreeMap")
if is_set {
panic!("range start is greater than range end in BTreeSet")
} else {
panic!("range start is greater than range end in BTreeMap")
}
}
_ => {}
}
24 changes: 15 additions & 9 deletions library/alloc/src/collections/btree/set.rs
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@ use core::ops::{BitAnd, BitOr, BitXor, RangeBounds, Sub};

use super::map::{BTreeMap, Keys};
use super::merge_iter::MergeIterInner;
use super::set_val::SetValZST;
use super::Recover;

use crate::alloc::{Allocator, Global};
@@ -81,7 +82,7 @@ pub struct BTreeSet<
T,
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + Clone = Global,
> {
map: BTreeMap<T, (), A>,
map: BTreeMap<T, SetValZST, A>,
}

#[stable(feature = "rust1", since = "1.0.0")]
@@ -135,7 +136,7 @@ impl<T: Clone, A: Allocator + Clone> Clone for BTreeSet<T, A> {
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Iter<'a, T: 'a> {
iter: Keys<'a, T, ()>,
iter: Keys<'a, T, SetValZST>,
}

#[stable(feature = "collection_debug", since = "1.17.0")]
@@ -158,7 +159,7 @@ pub struct IntoIter<
T,
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + Clone = Global,
> {
iter: super::map::IntoIter<T, (), A>,
iter: super::map::IntoIter<T, SetValZST, A>,
}

/// An iterator over a sub-range of items in a `BTreeSet`.
@@ -171,7 +172,7 @@ pub struct IntoIter<
#[derive(Debug)]
#[stable(feature = "btree_range", since = "1.17.0")]
pub struct Range<'a, T: 'a> {
iter: super::map::Range<'a, T, ()>,
iter: super::map::Range<'a, T, SetValZST>,
}

/// A lazy iterator producing elements in the difference of `BTreeSet`s.
@@ -375,6 +376,11 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
/// `range((Excluded(4), Included(10)))` will yield a left-exclusive, right-inclusive
/// range from 4 to 10.
///
/// # Panics
///
/// Panics if range `start > end`.
/// Panics if range `start == end` and both bounds are `Excluded`.
///
/// # Examples
///
/// ```
@@ -905,7 +911,7 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
where
T: Ord,
{
self.map.insert(value, ()).is_none()
self.map.insert(value, SetValZST::default()).is_none()
}

/// Adds a value to the set, replacing the existing element, if any, that is
@@ -1210,7 +1216,7 @@ impl<T: Ord> FromIterator<T> for BTreeSet<T> {

impl<T: Ord, A: Allocator + Clone> BTreeSet<T, A> {
fn from_sorted_iter<I: Iterator<Item = T>>(iter: I, alloc: A) -> BTreeSet<T, A> {
let iter = iter.map(|k| (k, ()));
let iter = iter.map(|k| (k, SetValZST::default()));
let map = BTreeMap::bulk_build_from_sorted_iter(iter, alloc);
BTreeSet { map }
}
@@ -1234,7 +1240,7 @@ impl<T: Ord, const N: usize> From<[T; N]> for BTreeSet<T> {

// use stable sort to preserve the insertion order.
arr.sort();
let iter = IntoIterator::into_iter(arr).map(|k| (k, ()));
let iter = IntoIterator::into_iter(arr).map(|k| (k, SetValZST::default()));
let map = BTreeMap::bulk_build_from_sorted_iter(iter, Global);
BTreeSet { map }
}
@@ -1284,7 +1290,7 @@ pub struct DrainFilter<
F: 'a + FnMut(&T) -> bool,
{
pred: F,
inner: super::map::DrainFilterInner<'a, T, ()>,
inner: super::map::DrainFilterInner<'a, T, SetValZST>,
/// The BTreeMap will outlive this IntoIter so we don't care about drop order for `alloc`.
alloc: A,
}
@@ -1319,7 +1325,7 @@ where

fn next(&mut self) -> Option<T> {
let pred = &mut self.pred;
let mut mapped_pred = |k: &T, _v: &mut ()| pred(k);
let mut mapped_pred = |k: &T, _v: &mut SetValZST| pred(k);
self.inner.next(&mut mapped_pred, self.alloc.clone()).map(|(k, _)| k)
}

23 changes: 23 additions & 0 deletions library/alloc/src/collections/btree/set/tests.rs
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@ use crate::vec::Vec;
use std::cmp::Ordering;
use std::hash::{Hash, Hasher};
use std::iter::FromIterator;
use std::ops::Bound::{Excluded, Included};
use std::panic::{catch_unwind, AssertUnwindSafe};

#[test]
@@ -831,3 +832,25 @@ fn from_array() {
let unordered_duplicates = BTreeSet::from([4, 1, 4, 3, 2]);
assert_eq!(set, unordered_duplicates);
}

#[should_panic(expected = "range start is greater than range end in BTreeSet")]
#[test]
fn test_range_panic_1() {
let mut set = BTreeSet::new();
set.insert(3);
set.insert(5);
set.insert(8);

let _invalid_range = set.range((Included(&8), Included(&3)));
}

#[should_panic(expected = "range start and end are equal and excluded in BTreeSet")]
#[test]
fn test_range_panic_2() {
let mut set = BTreeSet::new();
set.insert(3);
set.insert(5);
set.insert(8);

let _invalid_range = set.range((Excluded(&5), Excluded(&5)));
}
29 changes: 29 additions & 0 deletions library/alloc/src/collections/btree/set_val.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/// Zero-Sized Type (ZST) for internal `BTreeSet` values.
/// Used instead of `()` to differentiate between:
/// * `BTreeMap<T, ()>` (possible user-defined map)
/// * `BTreeMap<T, SetValZST>` (internal set representation)
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Default)]
pub struct SetValZST;

/// A trait to differentiate between `BTreeMap` and `BTreeSet` values.
/// Returns `true` only for type `SetValZST`, `false` for all other types (blanket implementation).
/// `TypeId` requires a `'static` lifetime, use of this trait avoids that restriction.
///
/// [`TypeId`]: std::any::TypeId
pub trait IsSetVal {
fn is_set_val() -> bool;
}

// Blanket implementation
impl<V> IsSetVal for V {
default fn is_set_val() -> bool {
false
}
}

// Specialization
impl IsSetVal for SetValZST {
fn is_set_val() -> bool {
true
}
}
80 changes: 79 additions & 1 deletion src/librustdoc/html/format.rs
Original file line number Diff line number Diff line change
@@ -8,14 +8,16 @@
use std::borrow::Cow;
use std::cell::Cell;
use std::fmt;
use std::iter;
use std::iter::{self, once};

use rustc_ast as ast;
use rustc_attr::{ConstStability, StabilityLevel};
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
use rustc_metadata::creader::{CStore, LoadedMacro};
use rustc_middle::ty;
use rustc_middle::ty::DefIdTree;
use rustc_middle::ty::TyCtxt;
@@ -519,6 +521,7 @@ impl clean::GenericArgs {
}

// Possible errors when computing href link source for a `DefId`
#[derive(PartialEq, Eq)]
pub(crate) enum HrefError {
/// This item is known to rustdoc, but from a crate that does not have documentation generated.
///
@@ -556,6 +559,79 @@ pub(crate) fn join_with_double_colon(syms: &[Symbol]) -> String {
s
}

/// This function is to get the external macro path because they are not in the cache used in
/// `href_with_root_path`.
fn generate_macro_def_id_path(
def_id: DefId,
cx: &Context<'_>,
root_path: Option<&str>,
) -> Result<(String, ItemType, Vec<Symbol>), HrefError> {
let tcx = cx.shared.tcx;
let crate_name = tcx.crate_name(def_id.krate).to_string();
let cache = cx.cache();

let fqp: Vec<Symbol> = tcx
.def_path(def_id)
.data
.into_iter()
.filter_map(|elem| {
// extern blocks (and a few others things) have an empty name.
match elem.data.get_opt_name() {
Some(s) if !s.is_empty() => Some(s),
_ => None,
}
})
.collect();
let relative = fqp.iter().map(|elem| elem.to_string());
let cstore = CStore::from_tcx(tcx);
// We need this to prevent a `panic` when this function is used from intra doc links...
if !cstore.has_crate_data(def_id.krate) {
debug!("No data for crate {}", crate_name);
return Err(HrefError::NotInExternalCache);
}
// Check to see if it is a macro 2.0 or built-in macro.
// More information in <https://rust-lang.github.io/rfcs/1584-macros.html>.
let is_macro_2 = match cstore.load_macro_untracked(def_id, tcx.sess) {
LoadedMacro::MacroDef(def, _) => {
// If `ast_def.macro_rules` is `true`, then it's not a macro 2.0.
matches!(&def.kind, ast::ItemKind::MacroDef(ast_def) if !ast_def.macro_rules)
}
_ => false,
};

let mut path = if is_macro_2 {
once(crate_name.clone()).chain(relative).collect()
} else {
vec![crate_name.clone(), relative.last().unwrap()]
};
if path.len() < 2 {
// The minimum we can have is the crate name followed by the macro name. If shorter, then
// it means that that `relative` was empty, which is an error.
debug!("macro path cannot be empty!");
return Err(HrefError::NotInExternalCache);
}

if let Some(last) = path.last_mut() {
*last = format!("macro.{}.html", last);
}

let url = match cache.extern_locations[&def_id.krate] {
ExternalLocation::Remote(ref s) => {
// `ExternalLocation::Remote` always end with a `/`.
format!("{}{}", s, path.join("/"))
}
ExternalLocation::Local => {
// `root_path` always end with a `/`.
format!("{}{}/{}", root_path.unwrap_or(""), crate_name, path.join("/"))
}
ExternalLocation::Unknown => {
debug!("crate {} not in cache when linkifying macros", crate_name);
return Err(HrefError::NotInExternalCache);
}
};
Ok((url, ItemType::Macro, fqp))
}

pub(crate) fn href_with_root_path(
did: DefId,
cx: &Context<'_>,
@@ -611,6 +687,8 @@ pub(crate) fn href_with_root_path(
ExternalLocation::Unknown => return Err(HrefError::DocumentationNotBuilt),
},
)
} else if matches!(def_kind, DefKind::Macro(_)) {
return generate_macro_def_id_path(did, cx, root_path);
} else {
return Err(HrefError::NotInExternalCache);
}
115 changes: 83 additions & 32 deletions src/librustdoc/html/highlight.rs
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@ use super::format::{self, Buffer};
use super::render::LinkFromSrc;

/// This type is needed in case we want to render links on items to allow to go to their definition.
pub(crate) struct ContextInfo<'a, 'b, 'c> {
pub(crate) struct HrefContext<'a, 'b, 'c> {
pub(crate) context: &'a Context<'b>,
/// This span contains the current file we're going through.
pub(crate) file_span: Span,
@@ -44,7 +44,7 @@ pub(crate) fn render_with_highlighting(
tooltip: Option<(Option<Edition>, &str)>,
edition: Edition,
extra_content: Option<Buffer>,
context_info: Option<ContextInfo<'_, '_, '_>>,
href_context: Option<HrefContext<'_, '_, '_>>,
decoration_info: Option<DecorationInfo>,
) {
debug!("highlighting: ================\n{}\n==============", src);
@@ -62,7 +62,7 @@ pub(crate) fn render_with_highlighting(
}

write_header(out, class, extra_content);
write_code(out, src, edition, context_info, decoration_info);
write_code(out, src, edition, href_context, decoration_info);
write_footer(out, playground_button);
}

@@ -85,31 +85,36 @@ fn write_header(out: &mut Buffer, class: Option<&str>, extra_content: Option<Buf
///
/// Some explanations on the last arguments:
///
/// In case we are rendering a code block and not a source code file, `context_info` will be `None`.
/// To put it more simply: if `context_info` is `None`, the code won't try to generate links to an
/// In case we are rendering a code block and not a source code file, `href_context` will be `None`.
/// To put it more simply: if `href_context` is `None`, the code won't try to generate links to an
/// item definition.
///
/// More explanations about spans and how we use them here are provided in the
fn write_code(
out: &mut Buffer,
src: &str,
edition: Edition,
context_info: Option<ContextInfo<'_, '_, '_>>,
href_context: Option<HrefContext<'_, '_, '_>>,
decoration_info: Option<DecorationInfo>,
) {
// This replace allows to fix how the code source with DOS backline characters is displayed.
let src = src.replace("\r\n", "\n");
let mut closing_tags: Vec<&'static str> = Vec::new();
Classifier::new(
&src,
edition,
context_info.as_ref().map(|c| c.file_span).unwrap_or(DUMMY_SP),
href_context.as_ref().map(|c| c.file_span).unwrap_or(DUMMY_SP),
decoration_info,
)
.highlight(&mut |highlight| {
match highlight {
Highlight::Token { text, class } => string(out, Escape(text), class, &context_info),
Highlight::EnterSpan { class } => enter_span(out, class),
Highlight::ExitSpan => exit_span(out),
Highlight::Token { text, class } => string(out, Escape(text), class, &href_context),
Highlight::EnterSpan { class } => {
closing_tags.push(enter_span(out, class, &href_context))
}
Highlight::ExitSpan => {
exit_span(out, closing_tags.pop().expect("ExitSpan without EnterSpan"))
}
};
});
}
@@ -129,7 +134,7 @@ enum Class {
RefKeyWord,
Self_(Span),
Op,
Macro,
Macro(Span),
MacroNonTerminal,
String,
Number,
@@ -153,7 +158,7 @@ impl Class {
Class::RefKeyWord => "kw-2",
Class::Self_(_) => "self",
Class::Op => "op",
Class::Macro => "macro",
Class::Macro(_) => "macro",
Class::MacroNonTerminal => "macro-nonterminal",
Class::String => "string",
Class::Number => "number",
@@ -171,8 +176,22 @@ impl Class {
/// a "span" (a tuple representing `(lo, hi)` equivalent of `Span`).
fn get_span(self) -> Option<Span> {
match self {
Self::Ident(sp) | Self::Self_(sp) => Some(sp),
_ => None,
Self::Ident(sp) | Self::Self_(sp) | Self::Macro(sp) => Some(sp),
Self::Comment
| Self::DocComment
| Self::Attribute
| Self::KeyWord
| Self::RefKeyWord
| Self::Op
| Self::MacroNonTerminal
| Self::String
| Self::Number
| Self::Bool
| Self::Lifetime
| Self::PreludeTy
| Self::PreludeVal
| Self::QuestionMark
| Self::Decoration(_) => None,
}
}
}
@@ -611,7 +630,7 @@ impl<'a> Classifier<'a> {
},
TokenKind::Ident | TokenKind::RawIdent if lookahead == Some(TokenKind::Bang) => {
self.in_macro = true;
sink(Highlight::EnterSpan { class: Class::Macro });
sink(Highlight::EnterSpan { class: Class::Macro(self.new_span(before, text)) });
sink(Highlight::Token { text, class: None });
return;
}
@@ -658,13 +677,20 @@ impl<'a> Classifier<'a> {

/// Called when we start processing a span of text that should be highlighted.
/// The `Class` argument specifies how it should be highlighted.
fn enter_span(out: &mut Buffer, klass: Class) {
write!(out, "<span class=\"{}\">", klass.as_html());
fn enter_span(
out: &mut Buffer,
klass: Class,
href_context: &Option<HrefContext<'_, '_, '_>>,
) -> &'static str {
string_without_closing_tag(out, "", Some(klass), href_context).expect(
"internal error: enter_span was called with Some(klass) but did not return a \
closing HTML tag",
)
}

/// Called at the end of a span of highlighted text.
fn exit_span(out: &mut Buffer) {
out.write_str("</span>");
fn exit_span(out: &mut Buffer, closing_tag: &str) {
out.write_str(closing_tag);
}

/// Called for a span of text. If the text should be highlighted differently
@@ -687,15 +713,39 @@ fn string<T: Display>(
out: &mut Buffer,
text: T,
klass: Option<Class>,
context_info: &Option<ContextInfo<'_, '_, '_>>,
href_context: &Option<HrefContext<'_, '_, '_>>,
) {
if let Some(closing_tag) = string_without_closing_tag(out, text, klass, href_context) {
out.write_str(closing_tag);
}
}

/// This function writes `text` into `out` with some modifications depending on `klass`:
///
/// * If `klass` is `None`, `text` is written into `out` with no modification.
/// * If `klass` is `Some` but `klass.get_span()` is `None`, it writes the text wrapped in a
/// `<span>` with the provided `klass`.
/// * If `klass` is `Some` and has a [`rustc_span::Span`], it then tries to generate a link (`<a>`
/// element) by retrieving the link information from the `span_correspondance_map` that was filled
/// in `span_map.rs::collect_spans_and_sources`. If it cannot retrieve the information, then it's
/// the same as the second point (`klass` is `Some` but doesn't have a [`rustc_span::Span`]).
fn string_without_closing_tag<T: Display>(
out: &mut Buffer,
text: T,
klass: Option<Class>,
href_context: &Option<HrefContext<'_, '_, '_>>,
) -> Option<&'static str> {
let Some(klass) = klass
else { return write!(out, "{}", text) };
else {
write!(out, "{}", text);
return None;
};
let Some(def_span) = klass.get_span()
else {
write!(out, "<span class=\"{}\">{}</span>", klass.as_html(), text);
return;
write!(out, "<span class=\"{}\">{}", klass.as_html(), text);
return Some("</span>");
};

let mut text_s = text.to_string();
if text_s.contains("::") {
text_s = text_s.split("::").intersperse("::").fold(String::new(), |mut path, t| {
@@ -715,10 +765,10 @@ fn string<T: Display>(
path
});
}
if let Some(context_info) = context_info {
if let Some(href_context) = href_context {
if let Some(href) =
context_info.context.shared.span_correspondance_map.get(&def_span).and_then(|href| {
let context = context_info.context;
href_context.context.shared.span_correspondance_map.get(&def_span).and_then(|href| {
let context = href_context.context;
// FIXME: later on, it'd be nice to provide two links (if possible) for all items:
// one to the documentation page and one to the source definition.
// FIXME: currently, external items only generate a link to their documentation,
@@ -727,27 +777,28 @@ fn string<T: Display>(
match href {
LinkFromSrc::Local(span) => context
.href_from_span(*span, true)
.map(|s| format!("{}{}", context_info.root_path, s)),
.map(|s| format!("{}{}", href_context.root_path, s)),
LinkFromSrc::External(def_id) => {
format::href_with_root_path(*def_id, context, Some(context_info.root_path))
format::href_with_root_path(*def_id, context, Some(href_context.root_path))
.ok()
.map(|(url, _, _)| url)
}
LinkFromSrc::Primitive(prim) => format::href_with_root_path(
PrimitiveType::primitive_locations(context.tcx())[prim],
context,
Some(context_info.root_path),
Some(href_context.root_path),
)
.ok()
.map(|(url, _, _)| url),
}
})
{
write!(out, "<a class=\"{}\" href=\"{}\">{}</a>", klass.as_html(), href, text_s);
return;
write!(out, "<a class=\"{}\" href=\"{}\">{}", klass.as_html(), href, text_s);
return Some("</a>");
}
}
write!(out, "<span class=\"{}\">{}</span>", klass.as_html(), text_s);
write!(out, "<span class=\"{}\">{}", klass.as_html(), text_s);
Some("</span>")
}

#[cfg(test)]
83 changes: 66 additions & 17 deletions src/librustdoc/html/render/span_map.rs
Original file line number Diff line number Diff line change
@@ -8,7 +8,8 @@ use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{ExprKind, HirId, Mod, Node};
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::TyCtxt;
use rustc_span::Span;
use rustc_span::hygiene::MacroKind;
use rustc_span::{BytePos, ExpnKind, Span};

use std::path::{Path, PathBuf};

@@ -63,33 +64,72 @@ struct SpanMapVisitor<'tcx> {

impl<'tcx> SpanMapVisitor<'tcx> {
/// This function is where we handle `hir::Path` elements and add them into the "span map".
fn handle_path(&mut self, path: &rustc_hir::Path<'_>, path_span: Option<Span>) {
fn handle_path(&mut self, path: &rustc_hir::Path<'_>) {
let info = match path.res {
// FIXME: For now, we only handle `DefKind` if it's not `DefKind::TyParam` or
// `DefKind::Macro`. Would be nice to support them too alongside the other `DefKind`
// FIXME: For now, we handle `DefKind` if it's not a `DefKind::TyParam`.
// Would be nice to support them too alongside the other `DefKind`
// (such as primitive types!).
Res::Def(kind, def_id) if kind != DefKind::TyParam => {
if matches!(kind, DefKind::Macro(_)) {
return;
}
Some(def_id)
}
Res::Def(kind, def_id) if kind != DefKind::TyParam => Some(def_id),
Res::Local(_) => None,
Res::PrimTy(p) => {
// FIXME: Doesn't handle "path-like" primitives like arrays or tuples.
let span = path_span.unwrap_or(path.span);
self.matches.insert(span, LinkFromSrc::Primitive(PrimitiveType::from(p)));
self.matches.insert(path.span, LinkFromSrc::Primitive(PrimitiveType::from(p)));
return;
}
Res::Err => return,
_ => return,
};
if let Some(span) = self.tcx.hir().res_span(path.res) {
self.matches
.insert(path_span.unwrap_or(path.span), LinkFromSrc::Local(clean::Span::new(span)));
self.matches.insert(path.span, LinkFromSrc::Local(clean::Span::new(span)));
} else if let Some(def_id) = info {
self.matches.insert(path_span.unwrap_or(path.span), LinkFromSrc::External(def_id));
self.matches.insert(path.span, LinkFromSrc::External(def_id));
}
}

/// Adds the macro call into the span map. Returns `true` if the `span` was inside a macro
/// expansion, whether or not it was added to the span map.
///
/// The idea for the macro support is to check if the current `Span` comes from expansion. If
/// so, we loop until we find the macro definition by using `outer_expn_data` in a loop.
/// Finally, we get the information about the macro itself (`span` if "local", `DefId`
/// otherwise) and store it inside the span map.
fn handle_macro(&mut self, span: Span) -> bool {
if !span.from_expansion() {
return false;
}
// So if the `span` comes from a macro expansion, we need to get the original
// macro's `DefId`.
let mut data = span.ctxt().outer_expn_data();
let mut call_site = data.call_site;
// Macros can expand to code containing macros, which will in turn be expanded, etc.
// So the idea here is to "go up" until we're back to code that was generated from
// macro expansion so that we can get the `DefId` of the original macro that was at the
// origin of this expansion.
while call_site.from_expansion() {
data = call_site.ctxt().outer_expn_data();
call_site = data.call_site;
}

let macro_name = match data.kind {
ExpnKind::Macro(MacroKind::Bang, macro_name) => macro_name,
// Even though we don't handle this kind of macro, this `data` still comes from
// expansion so we return `true` so we don't go any deeper in this code.
_ => return true,
};
let link_from_src = match data.macro_def_id {
Some(macro_def_id) if macro_def_id.is_local() => {
LinkFromSrc::Local(clean::Span::new(data.def_site))
}
Some(macro_def_id) => LinkFromSrc::External(macro_def_id),
None => return true,
};
let new_span = data.call_site;
let macro_name = macro_name.as_str();
// The "call_site" includes the whole macro with its "arguments". We only want
// the macro name.
let new_span = new_span.with_hi(new_span.lo() + BytePos(macro_name.len() as u32));
self.matches.insert(new_span, link_from_src);
true
}
}

@@ -101,7 +141,10 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
}

fn visit_path(&mut self, path: &'tcx rustc_hir::Path<'tcx>, _id: HirId) {
self.handle_path(path, None);
if self.handle_macro(path.span) {
return;
}
self.handle_path(path);
intravisit::walk_path(self, path);
}

@@ -143,12 +186,18 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
);
}
}
} else if self.handle_macro(expr.span) {
// We don't want to go deeper into the macro.
return;
}
intravisit::walk_expr(self, expr);
}

fn visit_use(&mut self, path: &'tcx rustc_hir::Path<'tcx>, id: HirId) {
self.handle_path(path, None);
if self.handle_macro(path.span) {
return;
}
self.handle_path(path);
intravisit::walk_use(self, path, id);
}
}
2 changes: 1 addition & 1 deletion src/librustdoc/html/sources.rs
Original file line number Diff line number Diff line change
@@ -297,7 +297,7 @@ pub(crate) fn print_src(
None,
edition,
Some(line_numbers),
Some(highlight::ContextInfo { context, file_span, root_path }),
Some(highlight::HrefContext { context, file_span, root_path }),
decoration_info,
);
}
25 changes: 25 additions & 0 deletions src/test/rustdoc/check-source-code-urls-to-def-std.rs
Original file line number Diff line number Diff line change
@@ -15,3 +15,28 @@ pub fn foo(a: u32, b: &str, c: String) {
let y: bool = true;
babar();
}

macro_rules! yolo { () => {}}

fn bar(a: i32) {}

macro_rules! bar {
($a:ident) => { bar($a) }
}

macro_rules! data {
($x:expr) => { $x * 2 }
}

pub fn another_foo() {
// This is known limitation: if the macro doesn't generate anything, the visitor
// can't find any item or anything that could tell us that it comes from expansion.
// @!has - '//a[@href="../../src/foo/check-source-code-urls-to-def-std.rs.html#19"]' 'yolo!'
yolo!();
// @has - '//a[@href="{{channel}}/std/macro.eprintln.html"]' 'eprintln!'
eprintln!();
// @has - '//a[@href="../../src/foo/check-source-code-urls-to-def-std.rs.html#27-29"]' 'data!'
let x = data!(4);
// @has - '//a[@href="../../src/foo/check-source-code-urls-to-def-std.rs.html#23-25"]' 'bar!'
bar!(x);
}
8 changes: 4 additions & 4 deletions src/test/ui/associated-types/issue-87261.rs
Original file line number Diff line number Diff line change
@@ -83,17 +83,17 @@ fn main() {
//~^ ERROR type mismatch resolving `<impl DerivedTrait as Trait>::Associated == ()`

accepts_trait(returns_opaque_foo());
//~^ ERROR type mismatch resolving `<impl Foo + Trait as Trait>::Associated == ()`
//~^ ERROR type mismatch resolving `<impl Trait + Foo as Trait>::Associated == ()`

accepts_trait(returns_opaque_derived_foo());
//~^ ERROR type mismatch resolving `<impl Foo + DerivedTrait as Trait>::Associated == ()`
//~^ ERROR type mismatch resolving `<impl DerivedTrait + Foo as Trait>::Associated == ()`

accepts_generic_trait(returns_opaque_generic());
//~^ ERROR type mismatch resolving `<impl GenericTrait<()> as GenericTrait<()>>::Associated == ()`

accepts_generic_trait(returns_opaque_generic_foo());
//~^ ERROR type mismatch resolving `<impl Foo + GenericTrait<()> as GenericTrait<()>>::Associated == ()`
//~^ ERROR type mismatch resolving `<impl GenericTrait<()> + Foo as GenericTrait<()>>::Associated == ()`

accepts_generic_trait(returns_opaque_generic_duplicate());
//~^ ERROR type mismatch resolving `<impl GenericTrait<u8> + GenericTrait<()> as GenericTrait<()>>::Associated == ()`
//~^ ERROR type mismatch resolving `<impl GenericTrait<()> + GenericTrait<u8> as GenericTrait<()>>::Associated == ()`
}
24 changes: 12 additions & 12 deletions src/test/ui/associated-types/issue-87261.stderr
Original file line number Diff line number Diff line change
@@ -160,7 +160,7 @@ help: consider constraining the associated type `<impl DerivedTrait as Trait>::A
LL | fn returns_opaque_derived() -> impl DerivedTrait<Associated = ()> + 'static {
| +++++++++++++++++

error[E0271]: type mismatch resolving `<impl Foo + Trait as Trait>::Associated == ()`
error[E0271]: type mismatch resolving `<impl Trait + Foo as Trait>::Associated == ()`
--> $DIR/issue-87261.rs:85:5
|
LL | fn returns_opaque_foo() -> impl Trait + Foo {
@@ -170,18 +170,18 @@ LL | accepts_trait(returns_opaque_foo());
| ^^^^^^^^^^^^^ expected `()`, found associated type
|
= note: expected unit type `()`
found associated type `<impl Foo + Trait as Trait>::Associated`
found associated type `<impl Trait + Foo as Trait>::Associated`
note: required by a bound in `accepts_trait`
--> $DIR/issue-87261.rs:43:27
|
LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
| ^^^^^^^^^^^^^^^ required by this bound in `accepts_trait`
help: consider constraining the associated type `<impl Foo + Trait as Trait>::Associated` to `()`
help: consider constraining the associated type `<impl Trait + Foo as Trait>::Associated` to `()`
|
LL | fn returns_opaque_foo() -> impl Trait<Associated = ()> + Foo {
| +++++++++++++++++

error[E0271]: type mismatch resolving `<impl Foo + DerivedTrait as Trait>::Associated == ()`
error[E0271]: type mismatch resolving `<impl DerivedTrait + Foo as Trait>::Associated == ()`
--> $DIR/issue-87261.rs:88:5
|
LL | fn returns_opaque_derived_foo() -> impl DerivedTrait + Foo {
@@ -191,8 +191,8 @@ LL | accepts_trait(returns_opaque_derived_foo());
| ^^^^^^^^^^^^^ expected `()`, found associated type
|
= note: expected unit type `()`
found associated type `<impl Foo + DerivedTrait as Trait>::Associated`
= help: consider constraining the associated type `<impl Foo + DerivedTrait as Trait>::Associated` to `()`
found associated type `<impl DerivedTrait + Foo as Trait>::Associated`
= help: consider constraining the associated type `<impl DerivedTrait + Foo as Trait>::Associated` to `()`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
note: required by a bound in `accepts_trait`
--> $DIR/issue-87261.rs:43:27
@@ -221,7 +221,7 @@ help: consider constraining the associated type `<impl GenericTrait<()> as Gener
LL | fn returns_opaque_generic() -> impl GenericTrait<(), Associated = ()> + 'static {
| +++++++++++++++++

error[E0271]: type mismatch resolving `<impl Foo + GenericTrait<()> as GenericTrait<()>>::Associated == ()`
error[E0271]: type mismatch resolving `<impl GenericTrait<()> + Foo as GenericTrait<()>>::Associated == ()`
--> $DIR/issue-87261.rs:94:5
|
LL | fn returns_opaque_generic_foo() -> impl GenericTrait<()> + Foo {
@@ -231,18 +231,18 @@ LL | accepts_generic_trait(returns_opaque_generic_foo());
| ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
|
= note: expected unit type `()`
found associated type `<impl Foo + GenericTrait<()> as GenericTrait<()>>::Associated`
found associated type `<impl GenericTrait<()> + Foo as GenericTrait<()>>::Associated`
note: required by a bound in `accepts_generic_trait`
--> $DIR/issue-87261.rs:44:46
|
LL | fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: T) {}
| ^^^^^^^^^^^^^^^ required by this bound in `accepts_generic_trait`
help: consider constraining the associated type `<impl Foo + GenericTrait<()> as GenericTrait<()>>::Associated` to `()`
help: consider constraining the associated type `<impl GenericTrait<()> + Foo as GenericTrait<()>>::Associated` to `()`
|
LL | fn returns_opaque_generic_foo() -> impl GenericTrait<(), Associated = ()> + Foo {
| +++++++++++++++++

error[E0271]: type mismatch resolving `<impl GenericTrait<u8> + GenericTrait<()> as GenericTrait<()>>::Associated == ()`
error[E0271]: type mismatch resolving `<impl GenericTrait<()> + GenericTrait<u8> as GenericTrait<()>>::Associated == ()`
--> $DIR/issue-87261.rs:97:5
|
LL | fn returns_opaque_generic_duplicate() -> impl GenericTrait<()> + GenericTrait<u8> {
@@ -252,8 +252,8 @@ LL | accepts_generic_trait(returns_opaque_generic_duplicate());
| ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
|
= note: expected unit type `()`
found associated type `<impl GenericTrait<u8> + GenericTrait<()> as GenericTrait<()>>::Associated`
= help: consider constraining the associated type `<impl GenericTrait<u8> + GenericTrait<()> as GenericTrait<()>>::Associated` to `()`
found associated type `<impl GenericTrait<()> + GenericTrait<u8> as GenericTrait<()>>::Associated`
= help: consider constraining the associated type `<impl GenericTrait<()> + GenericTrait<u8> as GenericTrait<()>>::Associated` to `()`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
note: required by a bound in `accepts_generic_trait`
--> $DIR/issue-87261.rs:44:46
12 changes: 12 additions & 0 deletions src/test/ui/impl-trait/suggest-calling-rpit-closure.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
fn whatever() -> i32 {
opaque()
//~^ ERROR mismatched types
}

fn opaque() -> impl Fn() -> i32 {
|| 0
}

fn main() {
let _ = whatever();
}
21 changes: 21 additions & 0 deletions src/test/ui/impl-trait/suggest-calling-rpit-closure.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
error[E0308]: mismatched types
--> $DIR/suggest-calling-rpit-closure.rs:2:5
|
LL | fn whatever() -> i32 {
| --- expected `i32` because of return type
LL | opaque()
| ^^^^^^^^ expected `i32`, found opaque type
...
LL | fn opaque() -> impl Fn() -> i32 {
| ---------------- the found opaque type
|
= note: expected type `i32`
found opaque type `impl Fn() -> i32`
help: use parentheses to call this closure
|
LL | opaque()()
| ++

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
4 changes: 4 additions & 0 deletions src/test/ui/parser/expr-as-stmt.stderr
Original file line number Diff line number Diff line change
@@ -201,6 +201,10 @@ LL | { true } || { true }
|
= note: expected type `bool`
found closure `[closure@$DIR/expr-as-stmt.rs:51:14: 51:25]`
help: use parentheses to call this closure
|
LL | { true } (|| { true })()
| + +++
help: parentheses are required to parse this as an expression
|
LL | ({ true }) || { true }
Original file line number Diff line number Diff line change
@@ -25,6 +25,12 @@ LL | | }.hi() {
|
= note: expected type `bool`
found closure `[closure@$DIR/struct-literal-restrictions-in-lamda.rs:12:11: 14:11]`
help: use parentheses to call this closure
|
LL ~ while (|| Foo {
LL | x: 3
LL ~ }.hi())() {
|

error: aborting due to 2 previous errors

4 changes: 0 additions & 4 deletions src/test/ui/reify-intrinsic.stderr
Original file line number Diff line number Diff line change
@@ -8,10 +8,6 @@ LL | let _: unsafe extern "rust-intrinsic" fn(isize) -> usize = std::mem::tr
|
= note: expected fn pointer `unsafe extern "rust-intrinsic" fn(isize) -> usize`
found fn item `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_, _>}`
help: use parentheses to call this function
|
LL | let _: unsafe extern "rust-intrinsic" fn(isize) -> usize = std::mem::transmute(...);
| +++++

error[E0606]: casting `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_, _>}` as `unsafe extern "rust-intrinsic" fn(isize) -> usize` is invalid
--> $DIR/reify-intrinsic.rs:11:13
Original file line number Diff line number Diff line change
@@ -1118,6 +1118,10 @@ LL | if let Range { start: F, end } = F..|| true {}
|
= note: expected type `bool`
found closure `[closure@$DIR/disallowed-positions.rs:136:41: 136:48]`
help: use parentheses to call this closure
|
LL | if let Range { start: F, end } = F..(|| true)() {}
| + +++

error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:136:8
@@ -1314,6 +1318,10 @@ LL | while let Range { start: F, end } = F..|| true {}
|
= note: expected type `bool`
found closure `[closure@$DIR/disallowed-positions.rs:200:44: 200:51]`
help: use parentheses to call this closure
|
LL | while let Range { start: F, end } = F..(|| true)() {}
| + +++

error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:200:11
4 changes: 4 additions & 0 deletions src/test/ui/span/move-closure.stderr
Original file line number Diff line number Diff line change
@@ -8,6 +8,10 @@ LL | let x: () = move || ();
|
= note: expected unit type `()`
found closure `[closure@$DIR/move-closure.rs:5:17: 5:27]`
help: use parentheses to call this closure
|
LL | let x: () = (move || ())();
| + +++

error: aborting due to previous error

14 changes: 7 additions & 7 deletions src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr
Original file line number Diff line number Diff line change
@@ -33,7 +33,7 @@ LL | let _: usize = foo;
found fn item `fn(usize, usize) -> usize {foo}`
help: use parentheses to call this function
|
LL | let _: usize = foo(a, b);
LL | let _: usize = foo(_, _);
| ++++++

error[E0308]: mismatched types
@@ -105,7 +105,7 @@ LL | let _: usize = T::baz;
found fn item `fn(usize, usize) -> usize {<_ as T>::baz}`
help: use parentheses to call this function
|
LL | let _: usize = T::baz(x, y);
LL | let _: usize = T::baz(_, _);
| ++++++

error[E0308]: mismatched types
@@ -123,7 +123,7 @@ LL | let _: usize = T::bat;
found fn item `fn(usize) -> usize {<_ as T>::bat}`
help: use parentheses to call this function
|
LL | let _: usize = T::bat(x);
LL | let _: usize = T::bat(_);
| +++

error[E0308]: mismatched types
@@ -159,7 +159,7 @@ LL | let _: usize = X::baz;
found fn item `fn(usize, usize) -> usize {<X as T>::baz}`
help: use parentheses to call this function
|
LL | let _: usize = X::baz(x, y);
LL | let _: usize = X::baz(_, _);
| ++++++

error[E0308]: mismatched types
@@ -177,7 +177,7 @@ LL | let _: usize = X::bat;
found fn item `fn(usize) -> usize {<X as T>::bat}`
help: use parentheses to call this function
|
LL | let _: usize = X::bat(x);
LL | let _: usize = X::bat(_);
| +++

error[E0308]: mismatched types
@@ -195,7 +195,7 @@ LL | let _: usize = X::bax;
found fn item `fn(usize) -> usize {<X as T>::bax}`
help: use parentheses to call this function
|
LL | let _: usize = X::bax(x);
LL | let _: usize = X::bax(_);
| +++

error[E0308]: mismatched types
@@ -213,7 +213,7 @@ LL | let _: usize = X::bach;
found fn item `fn(usize) -> usize {<X as T>::bach}`
help: use parentheses to call this function
|
LL | let _: usize = X::bach(x);
LL | let _: usize = X::bach(_);
| +++

error[E0308]: mismatched types
4 changes: 4 additions & 0 deletions src/test/ui/type-alias-impl-trait/issue-63279.stderr
Original file line number Diff line number Diff line change
@@ -15,6 +15,10 @@ LL | || -> Closure { || () }
|
= note: expected unit type `()`
found closure `[closure@$DIR/issue-63279.rs:8:21: 8:26]`
help: use parentheses to call this closure
|
LL | || -> Closure { (|| ())() }
| + +++

error[E0308]: mismatched types
--> $DIR/issue-63279.rs:8:5