Auto merge of #139845 - Zalathar:rollup-u5u5y1v, r=Zalathar
Rollup of 17 pull requests Successful merges: - #138374 (Enable contracts for const functions) - #138380 (ci: add runners for vanilla LLVM 20) - #138393 (Allow const patterns of matches to contain pattern types) - #139517 (std: sys: process: uefi: Use NULL stdin by default) - #139554 (std: add Output::exit_ok) - #139660 (compiletest: Add an experimental new executor to replace libtest) - #139669 (Overhaul `AssocItem`) - #139671 (Proc macro span API redesign: Replace proc_macro::SourceFile by Span::{file, local_file}) - #139750 (std/thread: Use default stack size from menuconfig for NuttX) - #139772 (Remove `hir::Map`) - #139785 (Let CStrings be either 1 or 2 byte aligned.) - #139789 (do not unnecessarily leak auto traits in item bounds) - #139791 (drop global where-bounds before merging candidates) - #139798 (normalize: prefer `ParamEnv` over `AliasBound` candidates) - #139822 (Fix: Map EOPNOTSUPP to ErrorKind::Unsupported on Unix) - #139833 (Fix some HIR pretty-printing problems) - #139836 (Basic tests of MPMC receiver cloning) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
f433fa46b0
173 changed files with 2499 additions and 994 deletions
|
@ -85,7 +85,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
.delegation_fn_sigs
|
.delegation_fn_sigs
|
||||||
.get(&local_def_id)
|
.get(&local_def_id)
|
||||||
.is_some_and(|sig| sig.has_self),
|
.is_some_and(|sig| sig.has_self),
|
||||||
None => self.tcx.associated_item(def_id).fn_has_self_parameter,
|
None => self.tcx.associated_item(def_id).is_method(),
|
||||||
},
|
},
|
||||||
_ => span_bug!(span, "unexpected DefKind for delegation item"),
|
_ => span_bug!(span, "unexpected DefKind for delegation item"),
|
||||||
}
|
}
|
||||||
|
|
|
@ -399,12 +399,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
&mut self,
|
&mut self,
|
||||||
expr: &'hir hir::Expr<'hir>,
|
expr: &'hir hir::Expr<'hir>,
|
||||||
span: Span,
|
span: Span,
|
||||||
check_ident: Ident,
|
cond_ident: Ident,
|
||||||
check_hir_id: HirId,
|
cond_hir_id: HirId,
|
||||||
) -> &'hir hir::Expr<'hir> {
|
) -> &'hir hir::Expr<'hir> {
|
||||||
let checker_fn = self.expr_ident(span, check_ident, check_hir_id);
|
let cond_fn = self.expr_ident(span, cond_ident, cond_hir_id);
|
||||||
let span = self.mark_span_with_reason(DesugaringKind::Contract, span, None);
|
let call_expr = self.expr_call_lang_item_fn_mut(
|
||||||
self.expr_call(span, checker_fn, std::slice::from_ref(expr))
|
span,
|
||||||
|
hir::LangItem::ContractCheckEnsures,
|
||||||
|
arena_vec![self; *cond_fn, *expr],
|
||||||
|
);
|
||||||
|
self.arena.alloc(call_expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn lower_const_block(&mut self, c: &AnonConst) -> hir::ConstBlock {
|
pub(crate) fn lower_const_block(&mut self, c: &AnonConst) -> hir::ConstBlock {
|
||||||
|
|
|
@ -1206,8 +1206,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
let precond = if let Some(req) = &contract.requires {
|
let precond = if let Some(req) = &contract.requires {
|
||||||
// Lower the precondition check intrinsic.
|
// Lower the precondition check intrinsic.
|
||||||
let lowered_req = this.lower_expr_mut(&req);
|
let lowered_req = this.lower_expr_mut(&req);
|
||||||
|
let req_span = this.mark_span_with_reason(
|
||||||
|
DesugaringKind::Contract,
|
||||||
|
lowered_req.span,
|
||||||
|
None,
|
||||||
|
);
|
||||||
let precond = this.expr_call_lang_item_fn_mut(
|
let precond = this.expr_call_lang_item_fn_mut(
|
||||||
req.span,
|
req_span,
|
||||||
hir::LangItem::ContractCheckRequires,
|
hir::LangItem::ContractCheckRequires,
|
||||||
&*arena_vec![this; lowered_req],
|
&*arena_vec![this; lowered_req],
|
||||||
);
|
);
|
||||||
|
@ -1217,6 +1222,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
};
|
};
|
||||||
let (postcond, body) = if let Some(ens) = &contract.ensures {
|
let (postcond, body) = if let Some(ens) = &contract.ensures {
|
||||||
let ens_span = this.lower_span(ens.span);
|
let ens_span = this.lower_span(ens.span);
|
||||||
|
let ens_span =
|
||||||
|
this.mark_span_with_reason(DesugaringKind::Contract, ens_span, None);
|
||||||
// Set up the postcondition `let` statement.
|
// Set up the postcondition `let` statement.
|
||||||
let check_ident: Ident =
|
let check_ident: Ident =
|
||||||
Ident::from_str_and_span("__ensures_checker", ens_span);
|
Ident::from_str_and_span("__ensures_checker", ens_span);
|
||||||
|
|
|
@ -647,7 +647,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
&& tc.polarity() == ty::PredicatePolarity::Positive
|
&& tc.polarity() == ty::PredicatePolarity::Positive
|
||||||
&& supertrait_def_ids(tcx, tc.def_id())
|
&& supertrait_def_ids(tcx, tc.def_id())
|
||||||
.flat_map(|trait_did| tcx.associated_items(trait_did).in_definition_order())
|
.flat_map(|trait_did| tcx.associated_items(trait_did).in_definition_order())
|
||||||
.any(|item| item.fn_has_self_parameter)
|
.any(|item| item.is_method())
|
||||||
})
|
})
|
||||||
}) {
|
}) {
|
||||||
return None;
|
return None;
|
||||||
|
|
|
@ -1557,11 +1557,15 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CastKind::Transmute => {
|
CastKind::Transmute => {
|
||||||
span_mirbug!(
|
let ty_from = op.ty(self.body, tcx);
|
||||||
|
match ty_from.kind() {
|
||||||
|
ty::Pat(base, _) if base == ty => {}
|
||||||
|
_ => span_mirbug!(
|
||||||
self,
|
self,
|
||||||
rvalue,
|
rvalue,
|
||||||
"Unexpected CastKind::Transmute, which is not permitted in Analysis MIR",
|
"Unexpected CastKind::Transmute {ty_from:?} -> {ty:?}, which is not permitted in Analysis MIR",
|
||||||
);
|
),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
|
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
|
||||||
use rustc_hir::LangItem;
|
use rustc_hir::LangItem;
|
||||||
use rustc_middle::ty::{AssocKind, GenericArg};
|
use rustc_middle::ty::{AssocTag, GenericArg};
|
||||||
use rustc_session::config::EntryFnType;
|
use rustc_session::config::EntryFnType;
|
||||||
use rustc_span::{DUMMY_SP, Ident};
|
use rustc_span::{DUMMY_SP, Ident};
|
||||||
|
|
||||||
|
@ -107,7 +107,7 @@ pub(crate) fn maybe_create_entry_wrapper(
|
||||||
.find_by_ident_and_kind(
|
.find_by_ident_and_kind(
|
||||||
tcx,
|
tcx,
|
||||||
Ident::from_str("report"),
|
Ident::from_str("report"),
|
||||||
AssocKind::Fn,
|
AssocTag::Fn,
|
||||||
termination_trait,
|
termination_trait,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use std::ops::{Bound, Range};
|
use std::ops::{Bound, Range};
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use ast::token::IdentIsRaw;
|
use ast::token::IdentIsRaw;
|
||||||
use pm::bridge::{
|
use pm::bridge::{
|
||||||
|
@ -18,7 +17,7 @@ use rustc_parse::parser::Parser;
|
||||||
use rustc_parse::{exp, new_parser_from_source_str, source_str_to_stream, unwrap_or_emit_fatal};
|
use rustc_parse::{exp, new_parser_from_source_str, source_str_to_stream, unwrap_or_emit_fatal};
|
||||||
use rustc_session::parse::ParseSess;
|
use rustc_session::parse::ParseSess;
|
||||||
use rustc_span::def_id::CrateNum;
|
use rustc_span::def_id::CrateNum;
|
||||||
use rustc_span::{BytePos, FileName, Pos, SourceFile, Span, Symbol, sym};
|
use rustc_span::{BytePos, FileName, Pos, Span, Symbol, sym};
|
||||||
use smallvec::{SmallVec, smallvec};
|
use smallvec::{SmallVec, smallvec};
|
||||||
|
|
||||||
use crate::base::ExtCtxt;
|
use crate::base::ExtCtxt;
|
||||||
|
@ -458,7 +457,6 @@ impl<'a, 'b> Rustc<'a, 'b> {
|
||||||
impl server::Types for Rustc<'_, '_> {
|
impl server::Types for Rustc<'_, '_> {
|
||||||
type FreeFunctions = FreeFunctions;
|
type FreeFunctions = FreeFunctions;
|
||||||
type TokenStream = TokenStream;
|
type TokenStream = TokenStream;
|
||||||
type SourceFile = Arc<SourceFile>;
|
|
||||||
type Span = Span;
|
type Span = Span;
|
||||||
type Symbol = Symbol;
|
type Symbol = Symbol;
|
||||||
}
|
}
|
||||||
|
@ -664,28 +662,6 @@ impl server::TokenStream for Rustc<'_, '_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl server::SourceFile for Rustc<'_, '_> {
|
|
||||||
fn eq(&mut self, file1: &Self::SourceFile, file2: &Self::SourceFile) -> bool {
|
|
||||||
Arc::ptr_eq(file1, file2)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn path(&mut self, file: &Self::SourceFile) -> String {
|
|
||||||
match &file.name {
|
|
||||||
FileName::Real(name) => name
|
|
||||||
.local_path()
|
|
||||||
.expect("attempting to get a file path in an imported file in `proc_macro::SourceFile::path`")
|
|
||||||
.to_str()
|
|
||||||
.expect("non-UTF8 file path in `proc_macro::SourceFile::path`")
|
|
||||||
.to_string(),
|
|
||||||
_ => file.name.prefer_local().to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_real(&mut self, file: &Self::SourceFile) -> bool {
|
|
||||||
file.is_real_file()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl server::Span for Rustc<'_, '_> {
|
impl server::Span for Rustc<'_, '_> {
|
||||||
fn debug(&mut self, span: Self::Span) -> String {
|
fn debug(&mut self, span: Self::Span) -> String {
|
||||||
if self.ecx.ecfg.span_debug {
|
if self.ecx.ecfg.span_debug {
|
||||||
|
@ -695,8 +671,29 @@ impl server::Span for Rustc<'_, '_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn source_file(&mut self, span: Self::Span) -> Self::SourceFile {
|
fn file(&mut self, span: Self::Span) -> String {
|
||||||
self.psess().source_map().lookup_char_pos(span.lo()).file
|
self.psess()
|
||||||
|
.source_map()
|
||||||
|
.lookup_char_pos(span.lo())
|
||||||
|
.file
|
||||||
|
.name
|
||||||
|
.prefer_remapped_unconditionaly()
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn local_file(&mut self, span: Self::Span) -> Option<String> {
|
||||||
|
self.psess()
|
||||||
|
.source_map()
|
||||||
|
.lookup_char_pos(span.lo())
|
||||||
|
.file
|
||||||
|
.name
|
||||||
|
.clone()
|
||||||
|
.into_local_path()
|
||||||
|
.map(|p| {
|
||||||
|
p.to_str()
|
||||||
|
.expect("non-UTF8 file path in `proc_macro::SourceFile::path`")
|
||||||
|
.to_string()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parent(&mut self, span: Self::Span) -> Option<Self::Span> {
|
fn parent(&mut self, span: Self::Span) -> Option<Self::Span> {
|
||||||
|
|
|
@ -25,7 +25,10 @@ fn invocation_relative_path_to_absolute(span: Span, path: &str) -> PathBuf {
|
||||||
path.to_path_buf()
|
path.to_path_buf()
|
||||||
} else {
|
} else {
|
||||||
// `/a/b/c/foo/bar.rs` contains the current macro invocation
|
// `/a/b/c/foo/bar.rs` contains the current macro invocation
|
||||||
|
#[cfg(bootstrap)]
|
||||||
let mut source_file_path = span.source_file().path();
|
let mut source_file_path = span.source_file().path();
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
let mut source_file_path = span.local_file().unwrap();
|
||||||
// `/a/b/c/foo/`
|
// `/a/b/c/foo/`
|
||||||
source_file_path.pop();
|
source_file_path.pop();
|
||||||
// `/a/b/c/foo/../locales/en-US/example.ftl`
|
// `/a/b/c/foo/../locales/en-US/example.ftl`
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
//! 1. **Shallow visit**: Get a simple callback for every item (or item-like thing) in the HIR.
|
//! 1. **Shallow visit**: Get a simple callback for every item (or item-like thing) in the HIR.
|
||||||
//! - Example: find all items with a `#[foo]` attribute on them.
|
//! - Example: find all items with a `#[foo]` attribute on them.
|
||||||
//! - How: Use the `hir_crate_items` or `hir_module_items` query to traverse over item-like ids
|
//! - How: Use the `hir_crate_items` or `hir_module_items` query to traverse over item-like ids
|
||||||
//! (ItemId, TraitItemId, etc.) and use tcx.def_kind and `tcx.hir().item*(id)` to filter and
|
//! (ItemId, TraitItemId, etc.) and use tcx.def_kind and `tcx.hir_item*(id)` to filter and
|
||||||
//! access actual item-like thing, respectively.
|
//! access actual item-like thing, respectively.
|
||||||
//! - Pro: Efficient; just walks the lists of item ids and gives users control whether to access
|
//! - Pro: Efficient; just walks the lists of item ids and gives users control whether to access
|
||||||
//! the hir_owners themselves or not.
|
//! the hir_owners themselves or not.
|
||||||
|
|
|
@ -442,6 +442,8 @@ language_item_table! {
|
||||||
DefaultTrait3, sym::default_trait3, default_trait3_trait, Target::Trait, GenericRequirement::None;
|
DefaultTrait3, sym::default_trait3, default_trait3_trait, Target::Trait, GenericRequirement::None;
|
||||||
DefaultTrait2, sym::default_trait2, default_trait2_trait, Target::Trait, GenericRequirement::None;
|
DefaultTrait2, sym::default_trait2, default_trait2_trait, Target::Trait, GenericRequirement::None;
|
||||||
DefaultTrait1, sym::default_trait1, default_trait1_trait, Target::Trait, GenericRequirement::None;
|
DefaultTrait1, sym::default_trait1, default_trait1_trait, Target::Trait, GenericRequirement::None;
|
||||||
|
|
||||||
|
ContractCheckEnsures, sym::contract_check_ensures, contract_check_ensures_fn, Target::Fn, GenericRequirement::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The requirement imposed on the generics of a lang item
|
/// The requirement imposed on the generics of a lang item
|
||||||
|
|
|
@ -443,13 +443,13 @@ fn best_definition_site_of_opaque<'tcx>(
|
||||||
let impl_def_id = tcx.local_parent(parent);
|
let impl_def_id = tcx.local_parent(parent);
|
||||||
for assoc in tcx.associated_items(impl_def_id).in_definition_order() {
|
for assoc in tcx.associated_items(impl_def_id).in_definition_order() {
|
||||||
match assoc.kind {
|
match assoc.kind {
|
||||||
ty::AssocKind::Const | ty::AssocKind::Fn => {
|
ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => {
|
||||||
if let ControlFlow::Break(span) = locator.check(assoc.def_id.expect_local())
|
if let ControlFlow::Break(span) = locator.check(assoc.def_id.expect_local())
|
||||||
{
|
{
|
||||||
return Some(span);
|
return Some(span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::AssocKind::Type => {}
|
ty::AssocKind::Type { .. } => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -740,7 +740,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||||
|
|
||||||
for &assoc_item in assoc_items.in_definition_order() {
|
for &assoc_item in assoc_items.in_definition_order() {
|
||||||
match assoc_item.kind {
|
match assoc_item.kind {
|
||||||
ty::AssocKind::Type if assoc_item.defaultness(tcx).has_value() => {
|
ty::AssocKind::Type { .. } if assoc_item.defaultness(tcx).has_value() => {
|
||||||
let trait_args = GenericArgs::identity_for_item(tcx, def_id);
|
let trait_args = GenericArgs::identity_for_item(tcx, def_id);
|
||||||
let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds(
|
let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds(
|
||||||
tcx,
|
tcx,
|
||||||
|
@ -942,7 +942,7 @@ fn check_impl_items_against_trait<'tcx>(
|
||||||
|
|
||||||
if res.is_ok() {
|
if res.is_ok() {
|
||||||
match ty_impl_item.kind {
|
match ty_impl_item.kind {
|
||||||
ty::AssocKind::Fn => {
|
ty::AssocKind::Fn { .. } => {
|
||||||
compare_impl_item::refine::check_refining_return_position_impl_trait_in_trait(
|
compare_impl_item::refine::check_refining_return_position_impl_trait_in_trait(
|
||||||
tcx,
|
tcx,
|
||||||
ty_impl_item,
|
ty_impl_item,
|
||||||
|
@ -952,8 +952,8 @@ fn check_impl_items_against_trait<'tcx>(
|
||||||
.instantiate_identity(),
|
.instantiate_identity(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ty::AssocKind::Const => {}
|
ty::AssocKind::Const { .. } => {}
|
||||||
ty::AssocKind::Type => {}
|
ty::AssocKind::Type { .. } => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,9 +43,11 @@ pub(super) fn compare_impl_item(
|
||||||
debug!(?impl_trait_ref);
|
debug!(?impl_trait_ref);
|
||||||
|
|
||||||
match impl_item.kind {
|
match impl_item.kind {
|
||||||
ty::AssocKind::Fn => compare_impl_method(tcx, impl_item, trait_item, impl_trait_ref),
|
ty::AssocKind::Fn { .. } => compare_impl_method(tcx, impl_item, trait_item, impl_trait_ref),
|
||||||
ty::AssocKind::Type => compare_impl_ty(tcx, impl_item, trait_item, impl_trait_ref),
|
ty::AssocKind::Type { .. } => compare_impl_ty(tcx, impl_item, trait_item, impl_trait_ref),
|
||||||
ty::AssocKind::Const => compare_impl_const(tcx, impl_item, trait_item, impl_trait_ref),
|
ty::AssocKind::Const { .. } => {
|
||||||
|
compare_impl_const(tcx, impl_item, trait_item, impl_trait_ref)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -651,7 +653,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
|
||||||
cause.span,
|
cause.span,
|
||||||
E0053,
|
E0053,
|
||||||
"method `{}` has an incompatible return type for trait",
|
"method `{}` has an incompatible return type for trait",
|
||||||
trait_m.name
|
trait_m.name()
|
||||||
);
|
);
|
||||||
infcx.err_ctxt().note_type_err(
|
infcx.err_ctxt().note_type_err(
|
||||||
&mut diag,
|
&mut diag,
|
||||||
|
@ -1029,11 +1031,11 @@ fn report_trait_method_mismatch<'tcx>(
|
||||||
impl_err_span,
|
impl_err_span,
|
||||||
E0053,
|
E0053,
|
||||||
"method `{}` has an incompatible type for trait",
|
"method `{}` has an incompatible type for trait",
|
||||||
trait_m.name
|
trait_m.name()
|
||||||
);
|
);
|
||||||
match &terr {
|
match &terr {
|
||||||
TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0)
|
TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0)
|
||||||
if trait_m.fn_has_self_parameter =>
|
if trait_m.is_method() =>
|
||||||
{
|
{
|
||||||
let ty = trait_sig.inputs()[0];
|
let ty = trait_sig.inputs()[0];
|
||||||
let sugg = get_self_string(ty, |ty| ty == impl_trait_ref.self_ty());
|
let sugg = get_self_string(ty, |ty| ty == impl_trait_ref.self_ty());
|
||||||
|
@ -1252,7 +1254,7 @@ fn compare_self_type<'tcx>(
|
||||||
get_self_string(self_arg_ty, can_eq_self)
|
get_self_string(self_arg_ty, can_eq_self)
|
||||||
};
|
};
|
||||||
|
|
||||||
match (trait_m.fn_has_self_parameter, impl_m.fn_has_self_parameter) {
|
match (trait_m.is_method(), impl_m.is_method()) {
|
||||||
(false, false) | (true, true) => {}
|
(false, false) | (true, true) => {}
|
||||||
|
|
||||||
(false, true) => {
|
(false, true) => {
|
||||||
|
@ -1263,14 +1265,14 @@ fn compare_self_type<'tcx>(
|
||||||
impl_m_span,
|
impl_m_span,
|
||||||
E0185,
|
E0185,
|
||||||
"method `{}` has a `{}` declaration in the impl, but not in the trait",
|
"method `{}` has a `{}` declaration in the impl, but not in the trait",
|
||||||
trait_m.name,
|
trait_m.name(),
|
||||||
self_descr
|
self_descr
|
||||||
);
|
);
|
||||||
err.span_label(impl_m_span, format!("`{self_descr}` used in impl"));
|
err.span_label(impl_m_span, format!("`{self_descr}` used in impl"));
|
||||||
if let Some(span) = tcx.hir_span_if_local(trait_m.def_id) {
|
if let Some(span) = tcx.hir_span_if_local(trait_m.def_id) {
|
||||||
err.span_label(span, format!("trait method declared without `{self_descr}`"));
|
err.span_label(span, format!("trait method declared without `{self_descr}`"));
|
||||||
} else {
|
} else {
|
||||||
err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
|
err.note_trait_signature(trait_m.name(), trait_m.signature(tcx));
|
||||||
}
|
}
|
||||||
return Err(err.emit_unless(delay));
|
return Err(err.emit_unless(delay));
|
||||||
}
|
}
|
||||||
|
@ -1283,14 +1285,14 @@ fn compare_self_type<'tcx>(
|
||||||
impl_m_span,
|
impl_m_span,
|
||||||
E0186,
|
E0186,
|
||||||
"method `{}` has a `{}` declaration in the trait, but not in the impl",
|
"method `{}` has a `{}` declaration in the trait, but not in the impl",
|
||||||
trait_m.name,
|
trait_m.name(),
|
||||||
self_descr
|
self_descr
|
||||||
);
|
);
|
||||||
err.span_label(impl_m_span, format!("expected `{self_descr}` in impl"));
|
err.span_label(impl_m_span, format!("expected `{self_descr}` in impl"));
|
||||||
if let Some(span) = tcx.hir_span_if_local(trait_m.def_id) {
|
if let Some(span) = tcx.hir_span_if_local(trait_m.def_id) {
|
||||||
err.span_label(span, format!("`{self_descr}` used in trait"));
|
err.span_label(span, format!("`{self_descr}` used in trait"));
|
||||||
} else {
|
} else {
|
||||||
err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
|
err.note_trait_signature(trait_m.name(), trait_m.signature(tcx));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Err(err.emit_unless(delay));
|
return Err(err.emit_unless(delay));
|
||||||
|
@ -1360,7 +1362,7 @@ fn compare_number_of_generics<'tcx>(
|
||||||
let mut err_occurred = None;
|
let mut err_occurred = None;
|
||||||
for (kind, trait_count, impl_count) in matchings {
|
for (kind, trait_count, impl_count) in matchings {
|
||||||
if impl_count != trait_count {
|
if impl_count != trait_count {
|
||||||
let arg_spans = |kind: ty::AssocKind, generics: &hir::Generics<'_>| {
|
let arg_spans = |item: &ty::AssocItem, generics: &hir::Generics<'_>| {
|
||||||
let mut spans = generics
|
let mut spans = generics
|
||||||
.params
|
.params
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -1370,7 +1372,7 @@ fn compare_number_of_generics<'tcx>(
|
||||||
} => {
|
} => {
|
||||||
// A fn can have an arbitrary number of extra elided lifetimes for the
|
// A fn can have an arbitrary number of extra elided lifetimes for the
|
||||||
// same signature.
|
// same signature.
|
||||||
!matches!(kind, ty::AssocKind::Fn)
|
!item.is_fn()
|
||||||
}
|
}
|
||||||
_ => true,
|
_ => true,
|
||||||
})
|
})
|
||||||
|
@ -1383,7 +1385,7 @@ fn compare_number_of_generics<'tcx>(
|
||||||
};
|
};
|
||||||
let (trait_spans, impl_trait_spans) = if let Some(def_id) = trait_.def_id.as_local() {
|
let (trait_spans, impl_trait_spans) = if let Some(def_id) = trait_.def_id.as_local() {
|
||||||
let trait_item = tcx.hir_expect_trait_item(def_id);
|
let trait_item = tcx.hir_expect_trait_item(def_id);
|
||||||
let arg_spans: Vec<Span> = arg_spans(trait_.kind, trait_item.generics);
|
let arg_spans: Vec<Span> = arg_spans(&trait_, trait_item.generics);
|
||||||
let impl_trait_spans: Vec<Span> = trait_item
|
let impl_trait_spans: Vec<Span> = trait_item
|
||||||
.generics
|
.generics
|
||||||
.params
|
.params
|
||||||
|
@ -1409,7 +1411,7 @@ fn compare_number_of_generics<'tcx>(
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let spans = arg_spans(impl_.kind, impl_item.generics);
|
let spans = arg_spans(&impl_, impl_item.generics);
|
||||||
let span = spans.first().copied();
|
let span = spans.first().copied();
|
||||||
|
|
||||||
let mut err = tcx.dcx().struct_span_err(
|
let mut err = tcx.dcx().struct_span_err(
|
||||||
|
@ -1418,7 +1420,7 @@ fn compare_number_of_generics<'tcx>(
|
||||||
"{} `{}` has {} {kind} parameter{} but its trait \
|
"{} `{}` has {} {kind} parameter{} but its trait \
|
||||||
declaration has {} {kind} parameter{}",
|
declaration has {} {kind} parameter{}",
|
||||||
item_kind,
|
item_kind,
|
||||||
trait_.name,
|
trait_.name(),
|
||||||
impl_count,
|
impl_count,
|
||||||
pluralize!(impl_count),
|
pluralize!(impl_count),
|
||||||
trait_count,
|
trait_count,
|
||||||
|
@ -1509,7 +1511,7 @@ fn compare_number_of_method_arguments<'tcx>(
|
||||||
impl_span,
|
impl_span,
|
||||||
E0050,
|
E0050,
|
||||||
"method `{}` has {} but the declaration in trait `{}` has {}",
|
"method `{}` has {} but the declaration in trait `{}` has {}",
|
||||||
trait_m.name,
|
trait_m.name(),
|
||||||
potentially_plural_count(impl_number_args, "parameter"),
|
potentially_plural_count(impl_number_args, "parameter"),
|
||||||
tcx.def_path_str(trait_m.def_id),
|
tcx.def_path_str(trait_m.def_id),
|
||||||
trait_number_args
|
trait_number_args
|
||||||
|
@ -1524,7 +1526,7 @@ fn compare_number_of_method_arguments<'tcx>(
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
|
err.note_trait_signature(trait_m.name(), trait_m.signature(tcx));
|
||||||
}
|
}
|
||||||
|
|
||||||
err.span_label(
|
err.span_label(
|
||||||
|
@ -1578,7 +1580,7 @@ fn compare_synthetic_generics<'tcx>(
|
||||||
impl_span,
|
impl_span,
|
||||||
E0643,
|
E0643,
|
||||||
"method `{}` has incompatible signature for trait",
|
"method `{}` has incompatible signature for trait",
|
||||||
trait_m.name
|
trait_m.name()
|
||||||
);
|
);
|
||||||
err.span_label(trait_span, "declaration in trait here");
|
err.span_label(trait_span, "declaration in trait here");
|
||||||
if impl_synthetic {
|
if impl_synthetic {
|
||||||
|
@ -1700,7 +1702,7 @@ fn compare_generic_param_kinds<'tcx>(
|
||||||
trait_item: ty::AssocItem,
|
trait_item: ty::AssocItem,
|
||||||
delay: bool,
|
delay: bool,
|
||||||
) -> Result<(), ErrorGuaranteed> {
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
assert_eq!(impl_item.kind, trait_item.kind);
|
assert_eq!(impl_item.as_tag(), trait_item.as_tag());
|
||||||
|
|
||||||
let ty_const_params_of = |def_id| {
|
let ty_const_params_of = |def_id| {
|
||||||
tcx.generics_of(def_id).own_params.iter().filter(|param| {
|
tcx.generics_of(def_id).own_params.iter().filter(|param| {
|
||||||
|
@ -1738,7 +1740,7 @@ fn compare_generic_param_kinds<'tcx>(
|
||||||
E0053,
|
E0053,
|
||||||
"{} `{}` has an incompatible generic parameter for trait `{}`",
|
"{} `{}` has an incompatible generic parameter for trait `{}`",
|
||||||
impl_item.descr(),
|
impl_item.descr(),
|
||||||
trait_item.name,
|
trait_item.name(),
|
||||||
&tcx.def_path_str(tcx.parent(trait_item.def_id))
|
&tcx.def_path_str(tcx.parent(trait_item.def_id))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1874,7 +1876,7 @@ fn compare_const_predicate_entailment<'tcx>(
|
||||||
cause.span,
|
cause.span,
|
||||||
E0326,
|
E0326,
|
||||||
"implemented const `{}` has an incompatible type for trait",
|
"implemented const `{}` has an incompatible type for trait",
|
||||||
trait_ct.name
|
trait_ct.name()
|
||||||
);
|
);
|
||||||
|
|
||||||
let trait_c_span = trait_ct.def_id.as_local().map(|trait_ct_def_id| {
|
let trait_c_span = trait_ct.def_id.as_local().map(|trait_ct_def_id| {
|
||||||
|
@ -2232,16 +2234,19 @@ fn param_env_with_gat_bounds<'tcx>(
|
||||||
// of the RPITITs associated with the same body. This is because checking
|
// of the RPITITs associated with the same body. This is because checking
|
||||||
// the item bounds of RPITITs often involves nested RPITITs having to prove
|
// the item bounds of RPITITs often involves nested RPITITs having to prove
|
||||||
// bounds about themselves.
|
// bounds about themselves.
|
||||||
let impl_tys_to_install = match impl_ty.opt_rpitit_info {
|
let impl_tys_to_install = match impl_ty.kind {
|
||||||
None => vec![impl_ty],
|
ty::AssocKind::Type {
|
||||||
Some(
|
data:
|
||||||
|
ty::AssocTypeData::Rpitit(
|
||||||
ty::ImplTraitInTraitData::Impl { fn_def_id }
|
ty::ImplTraitInTraitData::Impl { fn_def_id }
|
||||||
| ty::ImplTraitInTraitData::Trait { fn_def_id, .. },
|
| ty::ImplTraitInTraitData::Trait { fn_def_id, .. },
|
||||||
) => tcx
|
),
|
||||||
|
} => tcx
|
||||||
.associated_types_for_impl_traits_in_associated_fn(fn_def_id)
|
.associated_types_for_impl_traits_in_associated_fn(fn_def_id)
|
||||||
.iter()
|
.iter()
|
||||||
.map(|def_id| tcx.associated_item(*def_id))
|
.map(|def_id| tcx.associated_item(*def_id))
|
||||||
.collect(),
|
.collect(),
|
||||||
|
_ => vec![impl_ty],
|
||||||
};
|
};
|
||||||
|
|
||||||
for impl_ty in impl_tys_to_install {
|
for impl_ty in impl_tys_to_install {
|
||||||
|
|
|
@ -217,15 +217,11 @@ pub(crate) fn check_intrinsic_type(
|
||||||
};
|
};
|
||||||
(n_tps, 0, 0, inputs, output, hir::Safety::Unsafe)
|
(n_tps, 0, 0, inputs, output, hir::Safety::Unsafe)
|
||||||
} else if intrinsic_name == sym::contract_check_ensures {
|
} else if intrinsic_name == sym::contract_check_ensures {
|
||||||
// contract_check_ensures::<'a, Ret, C>(&'a Ret, C)
|
// contract_check_ensures::<Ret, C>(Ret, C) -> Ret
|
||||||
// where C: impl Fn(&'a Ret) -> bool,
|
// where C: for<'a> Fn(&'a Ret) -> bool,
|
||||||
//
|
//
|
||||||
// so: two type params, one lifetime param, 0 const params, two inputs, no return
|
// so: two type params, 0 lifetime param, 0 const params, two inputs, no return
|
||||||
|
(2, 0, 0, vec![param(0), param(1)], param(1), hir::Safety::Safe)
|
||||||
let p = generics.param_at(0, tcx);
|
|
||||||
let r = ty::Region::new_early_param(tcx, p.to_early_bound_region_data());
|
|
||||||
let ref_ret = Ty::new_imm_ref(tcx, r, param(1));
|
|
||||||
(2, 1, 0, vec![ref_ret, param(2)], tcx.types.unit, hir::Safety::Safe)
|
|
||||||
} else {
|
} else {
|
||||||
let safety = intrinsic_operation_unsafety(tcx, intrinsic_id);
|
let safety = intrinsic_operation_unsafety(tcx, intrinsic_id);
|
||||||
let (n_tps, n_cts, inputs, output) = match intrinsic_name {
|
let (n_tps, n_cts, inputs, output) = match intrinsic_name {
|
||||||
|
|
|
@ -205,7 +205,7 @@ fn missing_items_err(
|
||||||
|
|
||||||
let missing_items_msg = missing_items
|
let missing_items_msg = missing_items
|
||||||
.clone()
|
.clone()
|
||||||
.map(|trait_item| trait_item.name.to_string())
|
.map(|trait_item| trait_item.name().to_string())
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join("`, `");
|
.join("`, `");
|
||||||
|
|
||||||
|
@ -236,7 +236,7 @@ fn missing_items_err(
|
||||||
let code = format!("{padding}{snippet}\n{padding}");
|
let code = format!("{padding}{snippet}\n{padding}");
|
||||||
if let Some(span) = tcx.hir_span_if_local(trait_item.def_id) {
|
if let Some(span) = tcx.hir_span_if_local(trait_item.def_id) {
|
||||||
missing_trait_item_label
|
missing_trait_item_label
|
||||||
.push(errors::MissingTraitItemLabel { span, item: trait_item.name });
|
.push(errors::MissingTraitItemLabel { span, item: trait_item.name() });
|
||||||
missing_trait_item.push(errors::MissingTraitItemSuggestion {
|
missing_trait_item.push(errors::MissingTraitItemSuggestion {
|
||||||
span: sugg_sp,
|
span: sugg_sp,
|
||||||
code,
|
code,
|
||||||
|
@ -407,14 +407,14 @@ fn fn_sig_suggestion<'tcx>(
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, ty)| {
|
.map(|(i, ty)| {
|
||||||
Some(match ty.kind() {
|
Some(match ty.kind() {
|
||||||
ty::Param(_) if assoc.fn_has_self_parameter && i == 0 => "self".to_string(),
|
ty::Param(_) if assoc.is_method() && i == 0 => "self".to_string(),
|
||||||
ty::Ref(reg, ref_ty, mutability) if i == 0 => {
|
ty::Ref(reg, ref_ty, mutability) if i == 0 => {
|
||||||
let reg = format!("{reg} ");
|
let reg = format!("{reg} ");
|
||||||
let reg = match ®[..] {
|
let reg = match ®[..] {
|
||||||
"'_ " | " " => "",
|
"'_ " | " " => "",
|
||||||
reg => reg,
|
reg => reg,
|
||||||
};
|
};
|
||||||
if assoc.fn_has_self_parameter {
|
if assoc.is_method() {
|
||||||
match ref_ty.kind() {
|
match ref_ty.kind() {
|
||||||
ty::Param(param) if param.name == kw::SelfUpper => {
|
ty::Param(param) if param.name == kw::SelfUpper => {
|
||||||
format!("&{}{}self", reg, mutability.prefix_str())
|
format!("&{}{}self", reg, mutability.prefix_str())
|
||||||
|
@ -427,7 +427,7 @@ fn fn_sig_suggestion<'tcx>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
if assoc.fn_has_self_parameter && i == 0 {
|
if assoc.is_method() && i == 0 {
|
||||||
format!("self: {ty}")
|
format!("self: {ty}")
|
||||||
} else {
|
} else {
|
||||||
format!("_: {ty}")
|
format!("_: {ty}")
|
||||||
|
@ -489,7 +489,7 @@ fn suggestion_signature<'tcx>(
|
||||||
);
|
);
|
||||||
|
|
||||||
match assoc.kind {
|
match assoc.kind {
|
||||||
ty::AssocKind::Fn => fn_sig_suggestion(
|
ty::AssocKind::Fn { .. } => fn_sig_suggestion(
|
||||||
tcx,
|
tcx,
|
||||||
tcx.liberate_late_bound_regions(
|
tcx.liberate_late_bound_regions(
|
||||||
assoc.def_id,
|
assoc.def_id,
|
||||||
|
@ -499,14 +499,14 @@ fn suggestion_signature<'tcx>(
|
||||||
tcx.predicates_of(assoc.def_id).instantiate_own(tcx, args),
|
tcx.predicates_of(assoc.def_id).instantiate_own(tcx, args),
|
||||||
assoc,
|
assoc,
|
||||||
),
|
),
|
||||||
ty::AssocKind::Type => {
|
ty::AssocKind::Type { .. } => {
|
||||||
let (generics, where_clauses) = bounds_from_generic_predicates(
|
let (generics, where_clauses) = bounds_from_generic_predicates(
|
||||||
tcx,
|
tcx,
|
||||||
tcx.predicates_of(assoc.def_id).instantiate_own(tcx, args),
|
tcx.predicates_of(assoc.def_id).instantiate_own(tcx, args),
|
||||||
);
|
);
|
||||||
format!("type {}{generics} = /* Type */{where_clauses};", assoc.name)
|
format!("type {}{generics} = /* Type */{where_clauses};", assoc.name())
|
||||||
}
|
}
|
||||||
ty::AssocKind::Const => {
|
ty::AssocKind::Const { name } => {
|
||||||
let ty = tcx.type_of(assoc.def_id).instantiate_identity();
|
let ty = tcx.type_of(assoc.def_id).instantiate_identity();
|
||||||
let val = tcx
|
let val = tcx
|
||||||
.infer_ctxt()
|
.infer_ctxt()
|
||||||
|
@ -514,7 +514,7 @@ fn suggestion_signature<'tcx>(
|
||||||
.err_ctxt()
|
.err_ctxt()
|
||||||
.ty_kind_suggestion(tcx.param_env(assoc.def_id), ty)
|
.ty_kind_suggestion(tcx.param_env(assoc.def_id), ty)
|
||||||
.unwrap_or_else(|| "value".to_string());
|
.unwrap_or_else(|| "value".to_string());
|
||||||
format!("const {}: {} = {};", assoc.name, ty, val)
|
format!("const {}: {} = {};", name, ty, val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -408,7 +408,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
|
||||||
let gat_def_id = gat_item.def_id.expect_local();
|
let gat_def_id = gat_item.def_id.expect_local();
|
||||||
let gat_item = tcx.associated_item(gat_def_id);
|
let gat_item = tcx.associated_item(gat_def_id);
|
||||||
// If this item is not an assoc ty, or has no args, then it's not a GAT
|
// If this item is not an assoc ty, or has no args, then it's not a GAT
|
||||||
if gat_item.kind != ty::AssocKind::Type {
|
if !gat_item.is_type() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let gat_generics = tcx.generics_of(gat_def_id);
|
let gat_generics = tcx.generics_of(gat_def_id);
|
||||||
|
@ -432,7 +432,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
|
||||||
|
|
||||||
let item_required_bounds = match tcx.associated_item(item_def_id).kind {
|
let item_required_bounds = match tcx.associated_item(item_def_id).kind {
|
||||||
// In our example, this corresponds to `into_iter` method
|
// In our example, this corresponds to `into_iter` method
|
||||||
ty::AssocKind::Fn => {
|
ty::AssocKind::Fn { .. } => {
|
||||||
// For methods, we check the function signature's return type for any GATs
|
// For methods, we check the function signature's return type for any GATs
|
||||||
// to constrain. In the `into_iter` case, we see that the return type
|
// to constrain. In the `into_iter` case, we see that the return type
|
||||||
// `Self::Iter<'a>` is a GAT we want to gather any potential missing bounds from.
|
// `Self::Iter<'a>` is a GAT we want to gather any potential missing bounds from.
|
||||||
|
@ -453,7 +453,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// In our example, this corresponds to the `Iter` and `Item` associated types
|
// In our example, this corresponds to the `Iter` and `Item` associated types
|
||||||
ty::AssocKind::Type => {
|
ty::AssocKind::Type { .. } => {
|
||||||
// If our associated item is a GAT with missing bounds, add them to
|
// If our associated item is a GAT with missing bounds, add them to
|
||||||
// the param-env here. This allows this GAT to propagate missing bounds
|
// the param-env here. This allows this GAT to propagate missing bounds
|
||||||
// to other GATs.
|
// to other GATs.
|
||||||
|
@ -474,7 +474,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
|
||||||
gat_generics,
|
gat_generics,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ty::AssocKind::Const => None,
|
ty::AssocKind::Const { .. } => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(item_required_bounds) = item_required_bounds {
|
if let Some(item_required_bounds) = item_required_bounds {
|
||||||
|
@ -1076,7 +1076,7 @@ fn check_associated_item(
|
||||||
};
|
};
|
||||||
|
|
||||||
match item.kind {
|
match item.kind {
|
||||||
ty::AssocKind::Const => {
|
ty::AssocKind::Const { .. } => {
|
||||||
let ty = tcx.type_of(item.def_id).instantiate_identity();
|
let ty = tcx.type_of(item.def_id).instantiate_identity();
|
||||||
let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty);
|
let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty);
|
||||||
wfcx.register_wf_obligation(span, loc, ty.into());
|
wfcx.register_wf_obligation(span, loc, ty.into());
|
||||||
|
@ -1089,7 +1089,7 @@ fn check_associated_item(
|
||||||
);
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
ty::AssocKind::Fn => {
|
ty::AssocKind::Fn { .. } => {
|
||||||
let sig = tcx.fn_sig(item.def_id).instantiate_identity();
|
let sig = tcx.fn_sig(item.def_id).instantiate_identity();
|
||||||
let hir_sig = sig_if_method.expect("bad signature for method");
|
let hir_sig = sig_if_method.expect("bad signature for method");
|
||||||
check_fn_or_method(
|
check_fn_or_method(
|
||||||
|
@ -1101,7 +1101,7 @@ fn check_associated_item(
|
||||||
);
|
);
|
||||||
check_method_receiver(wfcx, hir_sig, item, self_ty)
|
check_method_receiver(wfcx, hir_sig, item, self_ty)
|
||||||
}
|
}
|
||||||
ty::AssocKind::Type => {
|
ty::AssocKind::Type { .. } => {
|
||||||
if let ty::AssocItemContainer::Trait = item.container {
|
if let ty::AssocItemContainer::Trait = item.container {
|
||||||
check_associated_type_bounds(wfcx, item, span)
|
check_associated_type_bounds(wfcx, item, span)
|
||||||
}
|
}
|
||||||
|
@ -1716,7 +1716,7 @@ fn check_method_receiver<'tcx>(
|
||||||
) -> Result<(), ErrorGuaranteed> {
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
let tcx = wfcx.tcx();
|
let tcx = wfcx.tcx();
|
||||||
|
|
||||||
if !method.fn_has_self_parameter {
|
if !method.is_method() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
|
||||||
|
|
||||||
for &item1 in impl_items1.in_definition_order() {
|
for &item1 in impl_items1.in_definition_order() {
|
||||||
let collision = impl_items2
|
let collision = impl_items2
|
||||||
.filter_by_name_unhygienic(item1.name)
|
.filter_by_name_unhygienic(item1.name())
|
||||||
.any(|&item2| self.compare_hygienically(item1, item2));
|
.any(|&item2| self.compare_hygienically(item1, item2));
|
||||||
|
|
||||||
if collision {
|
if collision {
|
||||||
|
@ -64,7 +64,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
|
||||||
|
|
||||||
fn compare_hygienically(&self, item1: ty::AssocItem, item2: ty::AssocItem) -> bool {
|
fn compare_hygienically(&self, item1: ty::AssocItem, item2: ty::AssocItem) -> bool {
|
||||||
// Symbols and namespace match, compare hygienically.
|
// Symbols and namespace match, compare hygienically.
|
||||||
item1.kind.namespace() == item2.kind.namespace()
|
item1.namespace() == item2.namespace()
|
||||||
&& item1.ident(self.tcx).normalize_to_macros_2_0()
|
&& item1.ident(self.tcx).normalize_to_macros_2_0()
|
||||||
== item2.ident(self.tcx).normalize_to_macros_2_0()
|
== item2.ident(self.tcx).normalize_to_macros_2_0()
|
||||||
}
|
}
|
||||||
|
@ -113,7 +113,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
|
||||||
let mut res = Ok(());
|
let mut res = Ok(());
|
||||||
for &item1 in impl_items1.in_definition_order() {
|
for &item1 in impl_items1.in_definition_order() {
|
||||||
let collision = impl_items2
|
let collision = impl_items2
|
||||||
.filter_by_name_unhygienic(item1.name)
|
.filter_by_name_unhygienic(item1.name())
|
||||||
.find(|&&item2| self.compare_hygienically(item1, item2));
|
.find(|&&item2| self.compare_hygienically(item1, item2));
|
||||||
|
|
||||||
if let Some(item2) = collision {
|
if let Some(item2) = collision {
|
||||||
|
@ -230,11 +230,11 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
|
||||||
let mut ids = impl_items
|
let mut ids = impl_items
|
||||||
.in_definition_order()
|
.in_definition_order()
|
||||||
.filter_map(|item| {
|
.filter_map(|item| {
|
||||||
let entry = connected_region_ids.entry(item.name);
|
let entry = connected_region_ids.entry(item.name());
|
||||||
if let IndexEntry::Occupied(e) = &entry {
|
if let IndexEntry::Occupied(e) = &entry {
|
||||||
Some(*e.get())
|
Some(*e.get())
|
||||||
} else {
|
} else {
|
||||||
idents_to_add.push(item.name);
|
idents_to_add.push(item.name());
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -44,7 +44,7 @@ use rustc_trait_selection::traits::ObligationCtxt;
|
||||||
use tracing::{debug, instrument};
|
use tracing::{debug, instrument};
|
||||||
|
|
||||||
use crate::errors;
|
use crate::errors;
|
||||||
use crate::hir_ty_lowering::errors::assoc_kind_str;
|
use crate::hir_ty_lowering::errors::assoc_tag_str;
|
||||||
use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer, RegionInferReason};
|
use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer, RegionInferReason};
|
||||||
|
|
||||||
pub(crate) mod dump;
|
pub(crate) mod dump;
|
||||||
|
@ -450,7 +450,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
|
||||||
item_def_id: DefId,
|
item_def_id: DefId,
|
||||||
item_segment: &rustc_hir::PathSegment<'tcx>,
|
item_segment: &rustc_hir::PathSegment<'tcx>,
|
||||||
poly_trait_ref: ty::PolyTraitRef<'tcx>,
|
poly_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||||
kind: ty::AssocKind,
|
assoc_tag: ty::AssocTag,
|
||||||
) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> {
|
) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> {
|
||||||
if let Some(trait_ref) = poly_trait_ref.no_bound_vars() {
|
if let Some(trait_ref) = poly_trait_ref.no_bound_vars() {
|
||||||
let item_args = self.lowerer().lower_generic_args_of_assoc_item(
|
let item_args = self.lowerer().lower_generic_args_of_assoc_item(
|
||||||
|
@ -525,7 +525,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
|
||||||
inferred_sugg,
|
inferred_sugg,
|
||||||
bound,
|
bound,
|
||||||
mpart_sugg,
|
mpart_sugg,
|
||||||
what: assoc_kind_str(kind),
|
what: assoc_tag_str(assoc_tag),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1811,7 +1811,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
||||||
self.tcx,
|
self.tcx,
|
||||||
type_def_id,
|
type_def_id,
|
||||||
constraint.ident,
|
constraint.ident,
|
||||||
ty::AssocKind::Fn,
|
ty::AssocTag::Fn,
|
||||||
) {
|
) {
|
||||||
bound_vars.extend(
|
bound_vars.extend(
|
||||||
self.tcx
|
self.tcx
|
||||||
|
@ -1843,7 +1843,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
||||||
self.tcx,
|
self.tcx,
|
||||||
type_def_id,
|
type_def_id,
|
||||||
constraint.ident,
|
constraint.ident,
|
||||||
ty::AssocKind::Type,
|
ty::AssocTag::Type,
|
||||||
)
|
)
|
||||||
.map(|(bound_vars, _)| bound_vars);
|
.map(|(bound_vars, _)| bound_vars);
|
||||||
self.with(scope, |this| {
|
self.with(scope, |this| {
|
||||||
|
@ -1875,13 +1875,13 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
assoc_ident: Ident,
|
assoc_ident: Ident,
|
||||||
assoc_kind: ty::AssocKind,
|
assoc_tag: ty::AssocTag,
|
||||||
) -> Option<(Vec<ty::BoundVariableKind>, &'tcx ty::AssocItem)> {
|
) -> Option<(Vec<ty::BoundVariableKind>, &'tcx ty::AssocItem)> {
|
||||||
let trait_defines_associated_item_named = |trait_def_id: DefId| {
|
let trait_defines_associated_item_named = |trait_def_id: DefId| {
|
||||||
tcx.associated_items(trait_def_id).find_by_ident_and_kind(
|
tcx.associated_items(trait_def_id).find_by_ident_and_kind(
|
||||||
tcx,
|
tcx,
|
||||||
assoc_ident,
|
assoc_ident,
|
||||||
assoc_kind,
|
assoc_tag,
|
||||||
trait_def_id,
|
trait_def_id,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
@ -1894,8 +1894,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
||||||
let Some((def_id, bound_vars)) = stack.pop() else {
|
let Some((def_id, bound_vars)) = stack.pop() else {
|
||||||
break None;
|
break None;
|
||||||
};
|
};
|
||||||
// See issue #83753. If someone writes an associated type on a non-trait, just treat it as
|
// See issue #83753. If someone writes an associated type on a non-trait, just treat it
|
||||||
// there being no supertrait HRTBs.
|
// as there being no supertrait HRTBs.
|
||||||
match tcx.def_kind(def_id) {
|
match tcx.def_kind(def_id) {
|
||||||
DefKind::Trait | DefKind::TraitAlias | DefKind::Impl { .. } => {}
|
DefKind::Trait | DefKind::TraitAlias | DefKind::Impl { .. } => {}
|
||||||
_ => break None,
|
_ => break None,
|
||||||
|
@ -2067,7 +2067,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
||||||
self.tcx,
|
self.tcx,
|
||||||
trait_def_id,
|
trait_def_id,
|
||||||
item_segment.ident,
|
item_segment.ident,
|
||||||
ty::AssocKind::Fn,
|
ty::AssocTag::Fn,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -2112,7 +2112,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
||||||
self.tcx,
|
self.tcx,
|
||||||
trait_def_id,
|
trait_def_id,
|
||||||
item_segment.ident,
|
item_segment.ident,
|
||||||
ty::AssocKind::Fn,
|
ty::AssocTag::Fn,
|
||||||
) else {
|
) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
|
@ -32,9 +32,11 @@ pub(super) fn find_opaque_ty_constraints_for_impl_trait_in_assoc_type(
|
||||||
for &assoc_id in tcx.associated_item_def_ids(impl_def_id) {
|
for &assoc_id in tcx.associated_item_def_ids(impl_def_id) {
|
||||||
let assoc = tcx.associated_item(assoc_id);
|
let assoc = tcx.associated_item(assoc_id);
|
||||||
match assoc.kind {
|
match assoc.kind {
|
||||||
ty::AssocKind::Const | ty::AssocKind::Fn => locator.check(assoc_id.expect_local()),
|
ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => {
|
||||||
|
locator.check(assoc_id.expect_local())
|
||||||
|
}
|
||||||
// Associated types don't have bodies, so they can't constrain hidden types
|
// Associated types don't have bodies, so they can't constrain hidden types
|
||||||
ty::AssocKind::Type => {}
|
ty::AssocKind::Type { .. } => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ use GenericArgsInfo::*;
|
||||||
use rustc_errors::codes::*;
|
use rustc_errors::codes::*;
|
||||||
use rustc_errors::{Applicability, Diag, Diagnostic, EmissionGuarantee, MultiSpan, pluralize};
|
use rustc_errors::{Applicability, Diag, Diagnostic, EmissionGuarantee, MultiSpan, pluralize};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_middle::ty::{self as ty, AssocItems, AssocKind, TyCtxt};
|
use rustc_middle::ty::{self as ty, AssocItems, TyCtxt};
|
||||||
use rustc_span::def_id::DefId;
|
use rustc_span::def_id::DefId;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
|
@ -486,13 +486,13 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
|
||||||
let items: &AssocItems = self.tcx.associated_items(self.def_id);
|
let items: &AssocItems = self.tcx.associated_items(self.def_id);
|
||||||
items
|
items
|
||||||
.in_definition_order()
|
.in_definition_order()
|
||||||
.filter(|item| item.kind == AssocKind::Type)
|
.filter(|item| item.is_type())
|
||||||
.filter(|item| {
|
.filter(|item| {
|
||||||
!self
|
!self
|
||||||
.gen_args
|
.gen_args
|
||||||
.constraints
|
.constraints
|
||||||
.iter()
|
.iter()
|
||||||
.any(|constraint| constraint.ident.name == item.name)
|
.any(|constraint| constraint.ident.name == item.name())
|
||||||
})
|
})
|
||||||
.filter(|item| !item.is_impl_trait_in_trait())
|
.filter(|item| !item.is_impl_trait_in_trait())
|
||||||
.map(|item| self.tcx.item_ident(item.def_id).to_string())
|
.map(|item| self.tcx.item_ident(item.def_id).to_string())
|
||||||
|
|
|
@ -431,16 +431,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
) -> Result<(), ErrorGuaranteed> {
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
|
|
||||||
let assoc_kind = if constraint.gen_args.parenthesized
|
let assoc_tag = if constraint.gen_args.parenthesized
|
||||||
== hir::GenericArgsParentheses::ReturnTypeNotation
|
== hir::GenericArgsParentheses::ReturnTypeNotation
|
||||||
{
|
{
|
||||||
ty::AssocKind::Fn
|
ty::AssocTag::Fn
|
||||||
} else if let hir::AssocItemConstraintKind::Equality { term: hir::Term::Const(_) } =
|
} else if let hir::AssocItemConstraintKind::Equality { term: hir::Term::Const(_) } =
|
||||||
constraint.kind
|
constraint.kind
|
||||||
{
|
{
|
||||||
ty::AssocKind::Const
|
ty::AssocTag::Const
|
||||||
} else {
|
} else {
|
||||||
ty::AssocKind::Type
|
ty::AssocTag::Type
|
||||||
};
|
};
|
||||||
|
|
||||||
// Given something like `U: Trait<T = X>`, we want to produce a predicate like
|
// Given something like `U: Trait<T = X>`, we want to produce a predicate like
|
||||||
|
@ -453,7 +453,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
// trait SuperTrait<A> { type T; }
|
// trait SuperTrait<A> { type T; }
|
||||||
let candidate = if self.probe_trait_that_defines_assoc_item(
|
let candidate = if self.probe_trait_that_defines_assoc_item(
|
||||||
trait_ref.def_id(),
|
trait_ref.def_id(),
|
||||||
assoc_kind,
|
assoc_tag,
|
||||||
constraint.ident,
|
constraint.ident,
|
||||||
) {
|
) {
|
||||||
// Simple case: The assoc item is defined in the current trait.
|
// Simple case: The assoc item is defined in the current trait.
|
||||||
|
@ -464,7 +464,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
self.probe_single_bound_for_assoc_item(
|
self.probe_single_bound_for_assoc_item(
|
||||||
|| traits::supertraits(tcx, trait_ref),
|
|| traits::supertraits(tcx, trait_ref),
|
||||||
AssocItemQSelf::Trait(trait_ref.def_id()),
|
AssocItemQSelf::Trait(trait_ref.def_id()),
|
||||||
assoc_kind,
|
assoc_tag,
|
||||||
constraint.ident,
|
constraint.ident,
|
||||||
path_span,
|
path_span,
|
||||||
Some(constraint),
|
Some(constraint),
|
||||||
|
@ -474,7 +474,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
let assoc_item = self
|
let assoc_item = self
|
||||||
.probe_assoc_item(
|
.probe_assoc_item(
|
||||||
constraint.ident,
|
constraint.ident,
|
||||||
assoc_kind,
|
assoc_tag,
|
||||||
hir_ref_id,
|
hir_ref_id,
|
||||||
constraint.span,
|
constraint.span,
|
||||||
candidate.def_id(),
|
candidate.def_id(),
|
||||||
|
@ -493,7 +493,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
})
|
})
|
||||||
.or_insert(constraint.span);
|
.or_insert(constraint.span);
|
||||||
|
|
||||||
let projection_term = if let ty::AssocKind::Fn = assoc_kind {
|
let projection_term = if let ty::AssocTag::Fn = assoc_tag {
|
||||||
let bound_vars = tcx.late_bound_vars(constraint.hir_id);
|
let bound_vars = tcx.late_bound_vars(constraint.hir_id);
|
||||||
ty::Binder::bind_with_vars(
|
ty::Binder::bind_with_vars(
|
||||||
self.lower_return_type_notation_ty(candidate, assoc_item.def_id, path_span)?.into(),
|
self.lower_return_type_notation_ty(candidate, assoc_item.def_id, path_span)?.into(),
|
||||||
|
@ -542,7 +542,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
};
|
};
|
||||||
|
|
||||||
match constraint.kind {
|
match constraint.kind {
|
||||||
hir::AssocItemConstraintKind::Equality { .. } if let ty::AssocKind::Fn = assoc_kind => {
|
hir::AssocItemConstraintKind::Equality { .. } if let ty::AssocTag::Fn = assoc_tag => {
|
||||||
return Err(self.dcx().emit_err(crate::errors::ReturnTypeNotationEqualityBound {
|
return Err(self.dcx().emit_err(crate::errors::ReturnTypeNotationEqualityBound {
|
||||||
span: constraint.span,
|
span: constraint.span,
|
||||||
}));
|
}));
|
||||||
|
@ -679,7 +679,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
trait_def_id,
|
trait_def_id,
|
||||||
hir_ty.span,
|
hir_ty.span,
|
||||||
item_segment,
|
item_segment,
|
||||||
ty::AssocKind::Type,
|
ty::AssocTag::Type,
|
||||||
);
|
);
|
||||||
return Ty::new_error(tcx, guar);
|
return Ty::new_error(tcx, guar);
|
||||||
};
|
};
|
||||||
|
@ -771,7 +771,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
AssocItemQSelf::SelfTyAlias,
|
AssocItemQSelf::SelfTyAlias,
|
||||||
ty::AssocKind::Fn,
|
ty::AssocTag::Fn,
|
||||||
assoc_ident,
|
assoc_ident,
|
||||||
span,
|
span,
|
||||||
None,
|
None,
|
||||||
|
@ -783,7 +783,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
) => self.probe_single_ty_param_bound_for_assoc_item(
|
) => self.probe_single_ty_param_bound_for_assoc_item(
|
||||||
param_did.expect_local(),
|
param_did.expect_local(),
|
||||||
qself.span,
|
qself.span,
|
||||||
ty::AssocKind::Fn,
|
ty::AssocTag::Fn,
|
||||||
assoc_ident,
|
assoc_ident,
|
||||||
span,
|
span,
|
||||||
)?,
|
)?,
|
||||||
|
@ -823,7 +823,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
|
|
||||||
let trait_def_id = bound.def_id();
|
let trait_def_id = bound.def_id();
|
||||||
let assoc_ty = self
|
let assoc_ty = self
|
||||||
.probe_assoc_item(assoc_ident, ty::AssocKind::Fn, qpath_hir_id, span, trait_def_id)
|
.probe_assoc_item(assoc_ident, ty::AssocTag::Fn, qpath_hir_id, span, trait_def_id)
|
||||||
.expect("failed to find associated type");
|
.expect("failed to find associated type");
|
||||||
|
|
||||||
Ok((bound, assoc_ty.def_id))
|
Ok((bound, assoc_ty.def_id))
|
||||||
|
|
|
@ -201,7 +201,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
tcx.associated_items(pred.trait_ref.def_id)
|
tcx.associated_items(pred.trait_ref.def_id)
|
||||||
.in_definition_order()
|
.in_definition_order()
|
||||||
// We only care about associated types.
|
// We only care about associated types.
|
||||||
.filter(|item| item.kind == ty::AssocKind::Type)
|
.filter(|item| item.is_type())
|
||||||
// No RPITITs -- they're not dyn-compatible for now.
|
// No RPITITs -- they're not dyn-compatible for now.
|
||||||
.filter(|item| !item.is_impl_trait_in_trait())
|
.filter(|item| !item.is_impl_trait_in_trait())
|
||||||
// If the associated type has a `where Self: Sized` bound,
|
// If the associated type has a `where Self: Sized` bound,
|
||||||
|
|
|
@ -116,7 +116,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
&self,
|
&self,
|
||||||
all_candidates: impl Fn() -> I,
|
all_candidates: impl Fn() -> I,
|
||||||
qself: AssocItemQSelf,
|
qself: AssocItemQSelf,
|
||||||
assoc_kind: ty::AssocKind,
|
assoc_tag: ty::AssocTag,
|
||||||
assoc_ident: Ident,
|
assoc_ident: Ident,
|
||||||
span: Span,
|
span: Span,
|
||||||
constraint: Option<&hir::AssocItemConstraint<'tcx>>,
|
constraint: Option<&hir::AssocItemConstraint<'tcx>>,
|
||||||
|
@ -134,14 +134,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
}) {
|
}) {
|
||||||
return self.complain_about_assoc_kind_mismatch(
|
return self.complain_about_assoc_kind_mismatch(
|
||||||
assoc_item,
|
assoc_item,
|
||||||
assoc_kind,
|
assoc_tag,
|
||||||
assoc_ident,
|
assoc_ident,
|
||||||
span,
|
span,
|
||||||
constraint,
|
constraint,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let assoc_kind_str = assoc_kind_str(assoc_kind);
|
let assoc_kind_str = assoc_tag_str(assoc_tag);
|
||||||
let qself_str = qself.to_string(tcx);
|
let qself_str = qself.to_string(tcx);
|
||||||
|
|
||||||
// The fallback span is needed because `assoc_name` might be an `Fn()`'s `Output` without a
|
// The fallback span is needed because `assoc_name` might be an `Fn()`'s `Output` without a
|
||||||
|
@ -168,7 +168,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
let all_candidate_names: Vec<_> = all_candidates()
|
let all_candidate_names: Vec<_> = all_candidates()
|
||||||
.flat_map(|r| tcx.associated_items(r.def_id()).in_definition_order())
|
.flat_map(|r| tcx.associated_items(r.def_id()).in_definition_order())
|
||||||
.filter_map(|item| {
|
.filter_map(|item| {
|
||||||
(!item.is_impl_trait_in_trait() && item.kind == assoc_kind).then_some(item.name)
|
if !item.is_impl_trait_in_trait() && item.as_tag() == assoc_tag {
|
||||||
|
item.opt_name()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
@ -200,7 +204,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|trait_def_id| tcx.associated_items(*trait_def_id).in_definition_order())
|
.flat_map(|trait_def_id| tcx.associated_items(*trait_def_id).in_definition_order())
|
||||||
.filter_map(|item| {
|
.filter_map(|item| {
|
||||||
(!item.is_impl_trait_in_trait() && item.kind == assoc_kind).then_some(item.name)
|
(!item.is_impl_trait_in_trait() && item.as_tag() == assoc_tag)
|
||||||
|
.then_some(item.name())
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
@ -213,7 +218,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
.filter(|trait_def_id| {
|
.filter(|trait_def_id| {
|
||||||
tcx.associated_items(trait_def_id)
|
tcx.associated_items(trait_def_id)
|
||||||
.filter_by_name_unhygienic(suggested_name)
|
.filter_by_name_unhygienic(suggested_name)
|
||||||
.any(|item| item.kind == assoc_kind)
|
.any(|item| item.as_tag() == assoc_tag)
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>()[..]
|
.collect::<Vec<_>>()[..]
|
||||||
{
|
{
|
||||||
|
@ -330,14 +335,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
fn complain_about_assoc_kind_mismatch(
|
fn complain_about_assoc_kind_mismatch(
|
||||||
&self,
|
&self,
|
||||||
assoc_item: &ty::AssocItem,
|
assoc_item: &ty::AssocItem,
|
||||||
assoc_kind: ty::AssocKind,
|
assoc_tag: ty::AssocTag,
|
||||||
ident: Ident,
|
ident: Ident,
|
||||||
span: Span,
|
span: Span,
|
||||||
constraint: Option<&hir::AssocItemConstraint<'tcx>>,
|
constraint: Option<&hir::AssocItemConstraint<'tcx>>,
|
||||||
) -> ErrorGuaranteed {
|
) -> ErrorGuaranteed {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
|
|
||||||
let bound_on_assoc_const_label = if let ty::AssocKind::Const = assoc_item.kind
|
let bound_on_assoc_const_label = if let ty::AssocKind::Const { .. } = assoc_item.kind
|
||||||
&& let Some(constraint) = constraint
|
&& let Some(constraint) = constraint
|
||||||
&& let hir::AssocItemConstraintKind::Bound { .. } = constraint.kind
|
&& let hir::AssocItemConstraintKind::Bound { .. } = constraint.kind
|
||||||
{
|
{
|
||||||
|
@ -375,17 +380,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
hir::Term::Ty(ty) => ty.span,
|
hir::Term::Ty(ty) => ty.span,
|
||||||
hir::Term::Const(ct) => ct.span(),
|
hir::Term::Const(ct) => ct.span(),
|
||||||
};
|
};
|
||||||
(span, Some(ident.span), assoc_item.kind, assoc_kind)
|
(span, Some(ident.span), assoc_item.as_tag(), assoc_tag)
|
||||||
} else {
|
} else {
|
||||||
(ident.span, None, assoc_kind, assoc_item.kind)
|
(ident.span, None, assoc_tag, assoc_item.as_tag())
|
||||||
};
|
};
|
||||||
|
|
||||||
self.dcx().emit_err(errors::AssocKindMismatch {
|
self.dcx().emit_err(errors::AssocKindMismatch {
|
||||||
span,
|
span,
|
||||||
expected: assoc_kind_str(expected),
|
expected: assoc_tag_str(expected),
|
||||||
got: assoc_kind_str(got),
|
got: assoc_tag_str(got),
|
||||||
expected_because_label,
|
expected_because_label,
|
||||||
assoc_kind: assoc_kind_str(assoc_item.kind),
|
assoc_kind: assoc_tag_str(assoc_item.as_tag()),
|
||||||
def_span: tcx.def_span(assoc_item.def_id),
|
def_span: tcx.def_span(assoc_item.def_id),
|
||||||
bound_on_assoc_const_label,
|
bound_on_assoc_const_label,
|
||||||
wrap_in_braces_sugg,
|
wrap_in_braces_sugg,
|
||||||
|
@ -398,9 +403,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
types: &[String],
|
types: &[String],
|
||||||
traits: &[String],
|
traits: &[String],
|
||||||
name: Symbol,
|
name: Symbol,
|
||||||
kind: ty::AssocKind,
|
assoc_tag: ty::AssocTag,
|
||||||
) -> ErrorGuaranteed {
|
) -> ErrorGuaranteed {
|
||||||
let kind_str = assoc_kind_str(kind);
|
let kind_str = assoc_tag_str(assoc_tag);
|
||||||
let mut err =
|
let mut err =
|
||||||
struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated {kind_str}");
|
struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated {kind_str}");
|
||||||
if self
|
if self
|
||||||
|
@ -569,7 +574,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
candidates: Vec<(DefId, (DefId, DefId))>,
|
candidates: Vec<(DefId, (DefId, DefId))>,
|
||||||
fulfillment_errors: Vec<FulfillmentError<'tcx>>,
|
fulfillment_errors: Vec<FulfillmentError<'tcx>>,
|
||||||
span: Span,
|
span: Span,
|
||||||
kind: ty::AssocKind,
|
assoc_tag: ty::AssocTag,
|
||||||
) -> ErrorGuaranteed {
|
) -> ErrorGuaranteed {
|
||||||
// FIXME(fmease): This was copied in parts from an old version of `rustc_hir_typeck::method::suggest`.
|
// FIXME(fmease): This was copied in parts from an old version of `rustc_hir_typeck::method::suggest`.
|
||||||
// Either
|
// Either
|
||||||
|
@ -579,14 +584,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
|
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
|
|
||||||
let kind_str = assoc_kind_str(kind);
|
let assoc_tag_str = assoc_tag_str(assoc_tag);
|
||||||
let adt_did = self_ty.ty_adt_def().map(|def| def.did());
|
let adt_did = self_ty.ty_adt_def().map(|def| def.did());
|
||||||
let add_def_label = |err: &mut Diag<'_>| {
|
let add_def_label = |err: &mut Diag<'_>| {
|
||||||
if let Some(did) = adt_did {
|
if let Some(did) = adt_did {
|
||||||
err.span_label(
|
err.span_label(
|
||||||
tcx.def_span(did),
|
tcx.def_span(did),
|
||||||
format!(
|
format!(
|
||||||
"associated {kind_str} `{name}` not found for this {}",
|
"associated {assoc_tag_str} `{name}` not found for this {}",
|
||||||
tcx.def_descr(did)
|
tcx.def_descr(did)
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -615,11 +620,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
self.dcx(),
|
self.dcx(),
|
||||||
name.span,
|
name.span,
|
||||||
E0220,
|
E0220,
|
||||||
"associated {kind_str} `{name}` not found for `{self_ty}` in the current scope"
|
"associated {assoc_tag_str} `{name}` not found for `{self_ty}` in the current scope"
|
||||||
);
|
);
|
||||||
err.span_label(name.span, format!("associated item not found in `{self_ty}`"));
|
err.span_label(name.span, format!("associated item not found in `{self_ty}`"));
|
||||||
err.note(format!(
|
err.note(format!(
|
||||||
"the associated {kind_str} was found for\n{type_candidates}{additional_types}",
|
"the associated {assoc_tag_str} was found for\n{type_candidates}{additional_types}",
|
||||||
));
|
));
|
||||||
add_def_label(&mut err);
|
add_def_label(&mut err);
|
||||||
return err.emit();
|
return err.emit();
|
||||||
|
@ -700,7 +705,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
|
|
||||||
let mut err = self.dcx().struct_span_err(
|
let mut err = self.dcx().struct_span_err(
|
||||||
name.span,
|
name.span,
|
||||||
format!("the associated {kind_str} `{name}` exists for `{self_ty}`, but its trait bounds were not satisfied")
|
format!("the associated {assoc_tag_str} `{name}` exists for `{self_ty}`, but its trait bounds were not satisfied")
|
||||||
);
|
);
|
||||||
if !bounds.is_empty() {
|
if !bounds.is_empty() {
|
||||||
err.note(format!(
|
err.note(format!(
|
||||||
|
@ -710,7 +715,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
}
|
}
|
||||||
err.span_label(
|
err.span_label(
|
||||||
name.span,
|
name.span,
|
||||||
format!("associated {kind_str} cannot be referenced on `{self_ty}` due to unsatisfied trait bounds")
|
format!("associated {assoc_tag_str} cannot be referenced on `{self_ty}` due to unsatisfied trait bounds")
|
||||||
);
|
);
|
||||||
|
|
||||||
for (span, mut bounds) in bound_spans {
|
for (span, mut bounds) in bound_spans {
|
||||||
|
@ -761,7 +766,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
// `issue-22560.rs`.
|
// `issue-22560.rs`.
|
||||||
let mut dyn_compatibility_violations = Ok(());
|
let mut dyn_compatibility_violations = Ok(());
|
||||||
for (assoc_item, trait_ref) in &missing_assoc_types {
|
for (assoc_item, trait_ref) in &missing_assoc_types {
|
||||||
names.entry(trait_ref).or_default().push(assoc_item.name);
|
names.entry(trait_ref).or_default().push(assoc_item.name());
|
||||||
names_len += 1;
|
names_len += 1;
|
||||||
|
|
||||||
let violations =
|
let violations =
|
||||||
|
@ -812,7 +817,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
let assoc_item = tcx.associated_items(trait_def).find_by_ident_and_kind(
|
let assoc_item = tcx.associated_items(trait_def).find_by_ident_and_kind(
|
||||||
tcx,
|
tcx,
|
||||||
ident,
|
ident,
|
||||||
ty::AssocKind::Type,
|
ty::AssocTag::Type,
|
||||||
trait_def,
|
trait_def,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -852,16 +857,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
let mut names: UnordMap<_, usize> = Default::default();
|
let mut names: UnordMap<_, usize> = Default::default();
|
||||||
for (item, _) in &missing_assoc_types {
|
for (item, _) in &missing_assoc_types {
|
||||||
types_count += 1;
|
types_count += 1;
|
||||||
*names.entry(item.name).or_insert(0) += 1;
|
*names.entry(item.name()).or_insert(0) += 1;
|
||||||
}
|
}
|
||||||
let mut dupes = false;
|
let mut dupes = false;
|
||||||
let mut shadows = false;
|
let mut shadows = false;
|
||||||
for (item, trait_ref) in &missing_assoc_types {
|
for (item, trait_ref) in &missing_assoc_types {
|
||||||
let prefix = if names[&item.name] > 1 {
|
let name = item.name();
|
||||||
|
let prefix = if names[&name] > 1 {
|
||||||
let trait_def_id = trait_ref.def_id();
|
let trait_def_id = trait_ref.def_id();
|
||||||
dupes = true;
|
dupes = true;
|
||||||
format!("{}::", tcx.def_path_str(trait_def_id))
|
format!("{}::", tcx.def_path_str(trait_def_id))
|
||||||
} else if bound_names.get(&item.name).is_some_and(|x| *x != item) {
|
} else if bound_names.get(&name).is_some_and(|x| *x != item) {
|
||||||
let trait_def_id = trait_ref.def_id();
|
let trait_def_id = trait_ref.def_id();
|
||||||
shadows = true;
|
shadows = true;
|
||||||
format!("{}::", tcx.def_path_str(trait_def_id))
|
format!("{}::", tcx.def_path_str(trait_def_id))
|
||||||
|
@ -871,7 +877,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
|
|
||||||
let mut is_shadowed = false;
|
let mut is_shadowed = false;
|
||||||
|
|
||||||
if let Some(assoc_item) = bound_names.get(&item.name)
|
if let Some(assoc_item) = bound_names.get(&name)
|
||||||
&& *assoc_item != item
|
&& *assoc_item != item
|
||||||
{
|
{
|
||||||
is_shadowed = true;
|
is_shadowed = true;
|
||||||
|
@ -880,17 +886,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
if assoc_item.def_id.is_local() { ", consider renaming it" } else { "" };
|
if assoc_item.def_id.is_local() { ", consider renaming it" } else { "" };
|
||||||
err.span_label(
|
err.span_label(
|
||||||
tcx.def_span(assoc_item.def_id),
|
tcx.def_span(assoc_item.def_id),
|
||||||
format!("`{}{}` shadowed here{}", prefix, item.name, rename_message),
|
format!("`{}{}` shadowed here{}", prefix, name, rename_message),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let rename_message = if is_shadowed { ", consider renaming it" } else { "" };
|
let rename_message = if is_shadowed { ", consider renaming it" } else { "" };
|
||||||
|
|
||||||
if let Some(sp) = tcx.hir_span_if_local(item.def_id) {
|
if let Some(sp) = tcx.hir_span_if_local(item.def_id) {
|
||||||
err.span_label(
|
err.span_label(sp, format!("`{}{}` defined here{}", prefix, name, rename_message));
|
||||||
sp,
|
|
||||||
format!("`{}{}` defined here{}", prefix, item.name, rename_message),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if potential_assoc_types.len() == missing_assoc_types.len() {
|
if potential_assoc_types.len() == missing_assoc_types.len() {
|
||||||
|
@ -903,7 +906,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
{
|
{
|
||||||
let types: Vec<_> = missing_assoc_types
|
let types: Vec<_> = missing_assoc_types
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(item, _)| format!("{} = Type", item.name))
|
.map(|(item, _)| format!("{} = Type", item.name()))
|
||||||
.collect();
|
.collect();
|
||||||
let code = if let Some(snippet) = snippet.strip_suffix('>') {
|
let code = if let Some(snippet) = snippet.strip_suffix('>') {
|
||||||
// The user wrote `Trait<'a>` or similar and we don't have a type we can
|
// The user wrote `Trait<'a>` or similar and we don't have a type we can
|
||||||
|
@ -938,16 +941,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
let mut names: FxIndexMap<_, usize> = FxIndexMap::default();
|
let mut names: FxIndexMap<_, usize> = FxIndexMap::default();
|
||||||
for (item, _) in &missing_assoc_types {
|
for (item, _) in &missing_assoc_types {
|
||||||
types_count += 1;
|
types_count += 1;
|
||||||
*names.entry(item.name).or_insert(0) += 1;
|
*names.entry(item.name()).or_insert(0) += 1;
|
||||||
}
|
}
|
||||||
let mut label = vec![];
|
let mut label = vec![];
|
||||||
for (item, trait_ref) in &missing_assoc_types {
|
for (item, trait_ref) in &missing_assoc_types {
|
||||||
let postfix = if names[&item.name] > 1 {
|
let name = item.name();
|
||||||
|
let postfix = if names[&name] > 1 {
|
||||||
format!(" (from trait `{}`)", trait_ref.print_trait_sugared())
|
format!(" (from trait `{}`)", trait_ref.print_trait_sugared())
|
||||||
} else {
|
} else {
|
||||||
String::new()
|
String::new()
|
||||||
};
|
};
|
||||||
label.push(format!("`{}`{}", item.name, postfix));
|
label.push(format!("`{}`{}", name, postfix));
|
||||||
}
|
}
|
||||||
if !label.is_empty() {
|
if !label.is_empty() {
|
||||||
err.span_label(
|
err.span_label(
|
||||||
|
@ -1022,12 +1026,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
.map(|simple_ty| tcx.incoherent_impls(simple_ty))
|
.map(|simple_ty| tcx.incoherent_impls(simple_ty))
|
||||||
})
|
})
|
||||||
&& let name = Symbol::intern(&format!("{ident2}_{ident3}"))
|
&& let name = Symbol::intern(&format!("{ident2}_{ident3}"))
|
||||||
&& let Some(ty::AssocItem { kind: ty::AssocKind::Fn, .. }) = inherent_impls
|
&& let Some(item) = inherent_impls
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|inherent_impl| {
|
.flat_map(|inherent_impl| {
|
||||||
tcx.associated_items(inherent_impl).filter_by_name_unhygienic(name)
|
tcx.associated_items(inherent_impl).filter_by_name_unhygienic(name)
|
||||||
})
|
})
|
||||||
.next()
|
.next()
|
||||||
|
&& item.is_fn()
|
||||||
{
|
{
|
||||||
Err(struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated type")
|
Err(struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated type")
|
||||||
.with_span_suggestion_verbose(
|
.with_span_suggestion_verbose(
|
||||||
|
@ -1629,10 +1634,10 @@ fn generics_args_err_extend<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn assoc_kind_str(kind: ty::AssocKind) -> &'static str {
|
pub(crate) fn assoc_tag_str(assoc_tag: ty::AssocTag) -> &'static str {
|
||||||
match kind {
|
match assoc_tag {
|
||||||
ty::AssocKind::Fn => "function",
|
ty::AssocTag::Fn => "function",
|
||||||
ty::AssocKind::Const => "constant",
|
ty::AssocTag::Const => "constant",
|
||||||
ty::AssocKind::Type => "type",
|
ty::AssocTag::Type => "type",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -501,8 +501,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
let names: Vec<_> = tcx
|
let names: Vec<_> = tcx
|
||||||
.associated_items(trait_def_id)
|
.associated_items(trait_def_id)
|
||||||
.in_definition_order()
|
.in_definition_order()
|
||||||
.filter(|assoc| assoc.kind.namespace() == Namespace::ValueNS)
|
.filter(|assoc| assoc.namespace() == Namespace::ValueNS)
|
||||||
.map(|cand| cand.name)
|
.map(|cand| cand.name())
|
||||||
.collect();
|
.collect();
|
||||||
if let Some(typo) = find_best_match_for_name(&names, segment.ident.name, None) {
|
if let Some(typo) = find_best_match_for_name(&names, segment.ident.name, None) {
|
||||||
diag.span_suggestion_verbose(
|
diag.span_suggestion_verbose(
|
||||||
|
|
|
@ -38,8 +38,8 @@ use rustc_middle::middle::stability::AllowUnstable;
|
||||||
use rustc_middle::mir::interpret::LitToConstInput;
|
use rustc_middle::mir::interpret::LitToConstInput;
|
||||||
use rustc_middle::ty::print::PrintPolyTraitRefExt as _;
|
use rustc_middle::ty::print::PrintPolyTraitRefExt as _;
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, TyCtxt,
|
self, AssocTag, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty,
|
||||||
TypeVisitableExt, TypingMode, Upcast, fold_regions,
|
TyCtxt, TypeVisitableExt, TypingMode, Upcast, fold_regions,
|
||||||
};
|
};
|
||||||
use rustc_middle::{bug, span_bug};
|
use rustc_middle::{bug, span_bug};
|
||||||
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
|
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
|
||||||
|
@ -51,7 +51,7 @@ use rustc_trait_selection::traits::wf::object_region_bounds;
|
||||||
use rustc_trait_selection::traits::{self, ObligationCtxt};
|
use rustc_trait_selection::traits::{self, ObligationCtxt};
|
||||||
use tracing::{debug, instrument};
|
use tracing::{debug, instrument};
|
||||||
|
|
||||||
use self::errors::assoc_kind_str;
|
use self::errors::assoc_tag_str;
|
||||||
use crate::check::check_abi_fn_ptr;
|
use crate::check::check_abi_fn_ptr;
|
||||||
use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, NoVariantNamed};
|
use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, NoVariantNamed};
|
||||||
use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint};
|
use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint};
|
||||||
|
@ -168,7 +168,7 @@ pub trait HirTyLowerer<'tcx> {
|
||||||
item_def_id: DefId,
|
item_def_id: DefId,
|
||||||
item_segment: &hir::PathSegment<'tcx>,
|
item_segment: &hir::PathSegment<'tcx>,
|
||||||
poly_trait_ref: ty::PolyTraitRef<'tcx>,
|
poly_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||||
kind: ty::AssocKind,
|
assoc_tag: ty::AssocTag,
|
||||||
) -> Result<(DefId, GenericArgsRef<'tcx>), ErrorGuaranteed>;
|
) -> Result<(DefId, GenericArgsRef<'tcx>), ErrorGuaranteed>;
|
||||||
|
|
||||||
fn lower_fn_sig(
|
fn lower_fn_sig(
|
||||||
|
@ -251,10 +251,10 @@ enum LowerAssocMode {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LowerAssocMode {
|
impl LowerAssocMode {
|
||||||
fn kind(self) -> ty::AssocKind {
|
fn assoc_tag(self) -> ty::AssocTag {
|
||||||
match self {
|
match self {
|
||||||
LowerAssocMode::Type { .. } => ty::AssocKind::Type,
|
LowerAssocMode::Type { .. } => ty::AssocTag::Type,
|
||||||
LowerAssocMode::Const => ty::AssocKind::Const,
|
LowerAssocMode::Const => ty::AssocTag::Const,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,7 +268,8 @@ impl LowerAssocMode {
|
||||||
fn permit_variants(self) -> bool {
|
fn permit_variants(self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
LowerAssocMode::Type { permit_variants } => permit_variants,
|
LowerAssocMode::Type { permit_variants } => permit_variants,
|
||||||
// FIXME(mgca): Support paths like `Option::<T>::None` or `Option::<T>::Some` which resolve to const ctors/fn items respectively
|
// FIXME(mgca): Support paths like `Option::<T>::None` or `Option::<T>::Some` which
|
||||||
|
// resolve to const ctors/fn items respectively.
|
||||||
LowerAssocMode::Const => false,
|
LowerAssocMode::Const => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -932,12 +933,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
fn probe_trait_that_defines_assoc_item(
|
fn probe_trait_that_defines_assoc_item(
|
||||||
&self,
|
&self,
|
||||||
trait_def_id: DefId,
|
trait_def_id: DefId,
|
||||||
assoc_kind: ty::AssocKind,
|
assoc_tag: AssocTag,
|
||||||
assoc_ident: Ident,
|
assoc_ident: Ident,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
self.tcx()
|
self.tcx()
|
||||||
.associated_items(trait_def_id)
|
.associated_items(trait_def_id)
|
||||||
.find_by_ident_and_kind(self.tcx(), assoc_ident, assoc_kind, trait_def_id)
|
.find_by_ident_and_kind(self.tcx(), assoc_ident, assoc_tag, trait_def_id)
|
||||||
.is_some()
|
.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -975,7 +976,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
&self,
|
&self,
|
||||||
ty_param_def_id: LocalDefId,
|
ty_param_def_id: LocalDefId,
|
||||||
ty_param_span: Span,
|
ty_param_span: Span,
|
||||||
kind: ty::AssocKind,
|
assoc_tag: AssocTag,
|
||||||
assoc_ident: Ident,
|
assoc_ident: Ident,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> Result<ty::PolyTraitRef<'tcx>, ErrorGuaranteed> {
|
) -> Result<ty::PolyTraitRef<'tcx>, ErrorGuaranteed> {
|
||||||
|
@ -993,7 +994,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
traits::transitive_bounds_that_define_assoc_item(tcx, trait_refs, assoc_ident)
|
traits::transitive_bounds_that_define_assoc_item(tcx, trait_refs, assoc_ident)
|
||||||
},
|
},
|
||||||
AssocItemQSelf::TyParam(ty_param_def_id, ty_param_span),
|
AssocItemQSelf::TyParam(ty_param_def_id, ty_param_span),
|
||||||
kind,
|
assoc_tag,
|
||||||
assoc_ident,
|
assoc_ident,
|
||||||
span,
|
span,
|
||||||
None,
|
None,
|
||||||
|
@ -1010,7 +1011,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
&self,
|
&self,
|
||||||
all_candidates: impl Fn() -> I,
|
all_candidates: impl Fn() -> I,
|
||||||
qself: AssocItemQSelf,
|
qself: AssocItemQSelf,
|
||||||
assoc_kind: ty::AssocKind,
|
assoc_tag: AssocTag,
|
||||||
assoc_ident: Ident,
|
assoc_ident: Ident,
|
||||||
span: Span,
|
span: Span,
|
||||||
constraint: Option<&hir::AssocItemConstraint<'tcx>>,
|
constraint: Option<&hir::AssocItemConstraint<'tcx>>,
|
||||||
|
@ -1021,14 +1022,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
|
|
||||||
let mut matching_candidates = all_candidates().filter(|r| {
|
let mut matching_candidates = all_candidates().filter(|r| {
|
||||||
self.probe_trait_that_defines_assoc_item(r.def_id(), assoc_kind, assoc_ident)
|
self.probe_trait_that_defines_assoc_item(r.def_id(), assoc_tag, assoc_ident)
|
||||||
});
|
});
|
||||||
|
|
||||||
let Some(bound) = matching_candidates.next() else {
|
let Some(bound) = matching_candidates.next() else {
|
||||||
let reported = self.complain_about_assoc_item_not_found(
|
let reported = self.complain_about_assoc_item_not_found(
|
||||||
all_candidates,
|
all_candidates,
|
||||||
qself,
|
qself,
|
||||||
assoc_kind,
|
assoc_tag,
|
||||||
assoc_ident,
|
assoc_ident,
|
||||||
span,
|
span,
|
||||||
constraint,
|
constraint,
|
||||||
|
@ -1040,7 +1041,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
if let Some(bound2) = matching_candidates.next() {
|
if let Some(bound2) = matching_candidates.next() {
|
||||||
debug!(?bound2);
|
debug!(?bound2);
|
||||||
|
|
||||||
let assoc_kind_str = errors::assoc_kind_str(assoc_kind);
|
let assoc_kind_str = errors::assoc_tag_str(assoc_tag);
|
||||||
let qself_str = qself.to_string(tcx);
|
let qself_str = qself.to_string(tcx);
|
||||||
let mut err = self.dcx().create_err(crate::errors::AmbiguousAssocItem {
|
let mut err = self.dcx().create_err(crate::errors::AmbiguousAssocItem {
|
||||||
span,
|
span,
|
||||||
|
@ -1059,14 +1060,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// FIXME(#97583): Print associated item bindings properly (i.e., not as equality predicates!).
|
// FIXME(#97583): Print associated item bindings properly (i.e., not as equality
|
||||||
|
// predicates!).
|
||||||
// FIXME: Turn this into a structured, translateable & more actionable suggestion.
|
// FIXME: Turn this into a structured, translateable & more actionable suggestion.
|
||||||
let mut where_bounds = vec![];
|
let mut where_bounds = vec![];
|
||||||
for bound in [bound, bound2].into_iter().chain(matching_candidates) {
|
for bound in [bound, bound2].into_iter().chain(matching_candidates) {
|
||||||
let bound_id = bound.def_id();
|
let bound_id = bound.def_id();
|
||||||
let bound_span = tcx
|
let bound_span = tcx
|
||||||
.associated_items(bound_id)
|
.associated_items(bound_id)
|
||||||
.find_by_ident_and_kind(tcx, assoc_ident, assoc_kind, bound_id)
|
.find_by_ident_and_kind(tcx, assoc_ident, assoc_tag, bound_id)
|
||||||
.and_then(|item| tcx.hir_span_if_local(item.def_id));
|
.and_then(|item| tcx.hir_span_if_local(item.def_id));
|
||||||
|
|
||||||
if let Some(bound_span) = bound_span {
|
if let Some(bound_span) = bound_span {
|
||||||
|
@ -1265,7 +1267,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
qself_ty,
|
qself_ty,
|
||||||
hir_ref_id,
|
hir_ref_id,
|
||||||
span,
|
span,
|
||||||
mode.kind(),
|
mode.assoc_tag(),
|
||||||
)? {
|
)? {
|
||||||
return Ok(LoweredAssoc::Term(did, args));
|
return Ok(LoweredAssoc::Term(did, args));
|
||||||
}
|
}
|
||||||
|
@ -1296,7 +1298,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
AssocItemQSelf::SelfTyAlias,
|
AssocItemQSelf::SelfTyAlias,
|
||||||
mode.kind(),
|
mode.assoc_tag(),
|
||||||
assoc_ident,
|
assoc_ident,
|
||||||
span,
|
span,
|
||||||
None,
|
None,
|
||||||
|
@ -1308,12 +1310,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
) => self.probe_single_ty_param_bound_for_assoc_item(
|
) => self.probe_single_ty_param_bound_for_assoc_item(
|
||||||
param_did.expect_local(),
|
param_did.expect_local(),
|
||||||
qself.span,
|
qself.span,
|
||||||
mode.kind(),
|
mode.assoc_tag(),
|
||||||
assoc_ident,
|
assoc_ident,
|
||||||
span,
|
span,
|
||||||
)?,
|
)?,
|
||||||
_ => {
|
_ => {
|
||||||
let kind_str = assoc_kind_str(mode.kind());
|
let kind_str = assoc_tag_str(mode.assoc_tag());
|
||||||
let reported = if variant_resolution.is_some() {
|
let reported = if variant_resolution.is_some() {
|
||||||
// Variant in type position
|
// Variant in type position
|
||||||
let msg = format!("expected {kind_str}, found variant `{assoc_ident}`");
|
let msg = format!("expected {kind_str}, found variant `{assoc_ident}`");
|
||||||
|
@ -1420,7 +1422,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
&[qself_ty.to_string()],
|
&[qself_ty.to_string()],
|
||||||
&traits,
|
&traits,
|
||||||
assoc_ident.name,
|
assoc_ident.name,
|
||||||
mode.kind(),
|
mode.assoc_tag(),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
return Err(reported);
|
return Err(reported);
|
||||||
|
@ -1429,10 +1431,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
|
|
||||||
let trait_did = bound.def_id();
|
let trait_did = bound.def_id();
|
||||||
let assoc_item = self
|
let assoc_item = self
|
||||||
.probe_assoc_item(assoc_ident, mode.kind(), hir_ref_id, span, trait_did)
|
.probe_assoc_item(assoc_ident, mode.assoc_tag(), hir_ref_id, span, trait_did)
|
||||||
.expect("failed to find associated item");
|
.expect("failed to find associated item");
|
||||||
let (def_id, args) =
|
let (def_id, args) = self.lower_assoc_shared(
|
||||||
self.lower_assoc_shared(span, assoc_item.def_id, assoc_segment, bound, mode.kind())?;
|
span,
|
||||||
|
assoc_item.def_id,
|
||||||
|
assoc_segment,
|
||||||
|
bound,
|
||||||
|
mode.assoc_tag(),
|
||||||
|
)?;
|
||||||
let result = LoweredAssoc::Term(def_id, args);
|
let result = LoweredAssoc::Term(def_id, args);
|
||||||
|
|
||||||
if let Some(variant_def_id) = variant_resolution {
|
if let Some(variant_def_id) = variant_resolution {
|
||||||
|
@ -1469,20 +1476,21 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
self_ty: Ty<'tcx>,
|
self_ty: Ty<'tcx>,
|
||||||
block: HirId,
|
block: HirId,
|
||||||
span: Span,
|
span: Span,
|
||||||
kind: ty::AssocKind,
|
assoc_tag: ty::AssocTag,
|
||||||
) -> Result<Option<(DefId, GenericArgsRef<'tcx>)>, ErrorGuaranteed> {
|
) -> Result<Option<(DefId, GenericArgsRef<'tcx>)>, ErrorGuaranteed> {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
|
|
||||||
if !tcx.features().inherent_associated_types() {
|
if !tcx.features().inherent_associated_types() {
|
||||||
match kind {
|
match assoc_tag {
|
||||||
// Don't attempt to look up inherent associated types when the feature is not enabled.
|
// Don't attempt to look up inherent associated types when the feature is not
|
||||||
// Theoretically it'd be fine to do so since we feature-gate their definition site.
|
// enabled. Theoretically it'd be fine to do so since we feature-gate their
|
||||||
// However, due to current limitations of the implementation (caused by us performing
|
// definition site. However, due to current limitations of the implementation
|
||||||
// selection during HIR ty lowering instead of in the trait solver), IATs can lead to cycle
|
// (caused by us performing selection during HIR ty lowering instead of in the
|
||||||
// errors (#108491) which mask the feature-gate error, needlessly confusing users
|
// trait solver), IATs can lead to cycle errors (#108491) which mask the
|
||||||
// who use IATs by accident (#113265).
|
// feature-gate error, needlessly confusing users who use IATs by accident
|
||||||
ty::AssocKind::Type => return Ok(None),
|
// (#113265).
|
||||||
ty::AssocKind::Const => {
|
ty::AssocTag::Type => return Ok(None),
|
||||||
|
ty::AssocTag::Const => {
|
||||||
// We also gate the mgca codepath for type-level uses of inherent consts
|
// We also gate the mgca codepath for type-level uses of inherent consts
|
||||||
// with the inherent_associated_types feature gate since it relies on the
|
// with the inherent_associated_types feature gate since it relies on the
|
||||||
// same machinery and has similar rough edges.
|
// same machinery and has similar rough edges.
|
||||||
|
@ -1494,7 +1502,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
)
|
)
|
||||||
.emit());
|
.emit());
|
||||||
}
|
}
|
||||||
ty::AssocKind::Fn => unreachable!(),
|
ty::AssocTag::Fn => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1503,7 +1511,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
.inherent_impls(adt_did)
|
.inherent_impls(adt_did)
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|&impl_| {
|
.filter_map(|&impl_| {
|
||||||
let (item, scope) = self.probe_assoc_item_unchecked(name, kind, block, impl_)?;
|
let (item, scope) =
|
||||||
|
self.probe_assoc_item_unchecked(name, assoc_tag, block, impl_)?;
|
||||||
Some((impl_, (item.def_id, scope)))
|
Some((impl_, (item.def_id, scope)))
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -1542,7 +1551,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
self_ty,
|
self_ty,
|
||||||
|self_ty| {
|
|self_ty| {
|
||||||
self.select_inherent_assoc_candidates(
|
self.select_inherent_assoc_candidates(
|
||||||
infcx, name, span, self_ty, param_env, candidates, kind,
|
infcx, name, span, self_ty, param_env, candidates, assoc_tag,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
@ -1570,7 +1579,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
self_ty: Ty<'tcx>,
|
self_ty: Ty<'tcx>,
|
||||||
param_env: ParamEnv<'tcx>,
|
param_env: ParamEnv<'tcx>,
|
||||||
candidates: Vec<(DefId, (DefId, DefId))>,
|
candidates: Vec<(DefId, (DefId, DefId))>,
|
||||||
kind: ty::AssocKind,
|
assoc_tag: ty::AssocTag,
|
||||||
) -> Result<(DefId, (DefId, DefId)), ErrorGuaranteed> {
|
) -> Result<(DefId, (DefId, DefId)), ErrorGuaranteed> {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
let mut fulfillment_errors = Vec::new();
|
let mut fulfillment_errors = Vec::new();
|
||||||
|
@ -1621,7 +1630,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
candidates,
|
candidates,
|
||||||
fulfillment_errors,
|
fulfillment_errors,
|
||||||
span,
|
span,
|
||||||
kind,
|
assoc_tag,
|
||||||
)),
|
)),
|
||||||
|
|
||||||
&[applicable_candidate] => Ok(applicable_candidate),
|
&[applicable_candidate] => Ok(applicable_candidate),
|
||||||
|
@ -1640,12 +1649,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
fn probe_assoc_item(
|
fn probe_assoc_item(
|
||||||
&self,
|
&self,
|
||||||
ident: Ident,
|
ident: Ident,
|
||||||
kind: ty::AssocKind,
|
assoc_tag: ty::AssocTag,
|
||||||
block: HirId,
|
block: HirId,
|
||||||
span: Span,
|
span: Span,
|
||||||
scope: DefId,
|
scope: DefId,
|
||||||
) -> Option<ty::AssocItem> {
|
) -> Option<ty::AssocItem> {
|
||||||
let (item, scope) = self.probe_assoc_item_unchecked(ident, kind, block, scope)?;
|
let (item, scope) = self.probe_assoc_item_unchecked(ident, assoc_tag, block, scope)?;
|
||||||
self.check_assoc_item(item.def_id, ident, scope, block, span);
|
self.check_assoc_item(item.def_id, ident, scope, block, span);
|
||||||
Some(item)
|
Some(item)
|
||||||
}
|
}
|
||||||
|
@ -1657,7 +1666,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
fn probe_assoc_item_unchecked(
|
fn probe_assoc_item_unchecked(
|
||||||
&self,
|
&self,
|
||||||
ident: Ident,
|
ident: Ident,
|
||||||
kind: ty::AssocKind,
|
assoc_tag: ty::AssocTag,
|
||||||
block: HirId,
|
block: HirId,
|
||||||
scope: DefId,
|
scope: DefId,
|
||||||
) -> Option<(ty::AssocItem, /*scope*/ DefId)> {
|
) -> Option<(ty::AssocItem, /*scope*/ DefId)> {
|
||||||
|
@ -1670,7 +1679,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
let item = tcx
|
let item = tcx
|
||||||
.associated_items(scope)
|
.associated_items(scope)
|
||||||
.filter_by_name_unhygienic(ident.name)
|
.filter_by_name_unhygienic(ident.name)
|
||||||
.find(|i| i.kind == kind && i.ident(tcx).normalize_to_macros_2_0() == ident)?;
|
.find(|i| i.as_tag() == assoc_tag && i.ident(tcx).normalize_to_macros_2_0() == ident)?;
|
||||||
|
|
||||||
Some((*item, def_scope))
|
Some((*item, def_scope))
|
||||||
}
|
}
|
||||||
|
@ -1722,9 +1731,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
tcx.associated_items(*trait_def_id)
|
tcx.associated_items(*trait_def_id)
|
||||||
.in_definition_order()
|
.in_definition_order()
|
||||||
.any(|i| {
|
.any(|i| {
|
||||||
i.kind.namespace() == Namespace::TypeNS
|
i.namespace() == Namespace::TypeNS
|
||||||
&& i.ident(tcx).normalize_to_macros_2_0() == assoc_ident
|
&& i.ident(tcx).normalize_to_macros_2_0() == assoc_ident
|
||||||
&& matches!(i.kind, ty::AssocKind::Type)
|
&& i.is_type()
|
||||||
})
|
})
|
||||||
// Consider only accessible traits
|
// Consider only accessible traits
|
||||||
&& tcx.visibility(*trait_def_id)
|
&& tcx.visibility(*trait_def_id)
|
||||||
|
@ -1770,7 +1779,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
item_def_id,
|
item_def_id,
|
||||||
trait_segment,
|
trait_segment,
|
||||||
item_segment,
|
item_segment,
|
||||||
ty::AssocKind::Type,
|
ty::AssocTag::Type,
|
||||||
) {
|
) {
|
||||||
Ok((item_def_id, item_args)) => {
|
Ok((item_def_id, item_args)) => {
|
||||||
Ty::new_projection_from_args(self.tcx(), item_def_id, item_args)
|
Ty::new_projection_from_args(self.tcx(), item_def_id, item_args)
|
||||||
|
@ -1795,7 +1804,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
item_def_id,
|
item_def_id,
|
||||||
trait_segment,
|
trait_segment,
|
||||||
item_segment,
|
item_segment,
|
||||||
ty::AssocKind::Const,
|
ty::AssocTag::Const,
|
||||||
) {
|
) {
|
||||||
Ok((item_def_id, item_args)) => {
|
Ok((item_def_id, item_args)) => {
|
||||||
let uv = ty::UnevaluatedConst::new(item_def_id, item_args);
|
let uv = ty::UnevaluatedConst::new(item_def_id, item_args);
|
||||||
|
@ -1813,7 +1822,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
item_def_id: DefId,
|
item_def_id: DefId,
|
||||||
trait_segment: &hir::PathSegment<'tcx>,
|
trait_segment: &hir::PathSegment<'tcx>,
|
||||||
item_segment: &hir::PathSegment<'tcx>,
|
item_segment: &hir::PathSegment<'tcx>,
|
||||||
kind: ty::AssocKind,
|
assoc_tag: ty::AssocTag,
|
||||||
) -> Result<(DefId, GenericArgsRef<'tcx>), ErrorGuaranteed> {
|
) -> Result<(DefId, GenericArgsRef<'tcx>), ErrorGuaranteed> {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
|
|
||||||
|
@ -1821,7 +1830,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
debug!(?trait_def_id);
|
debug!(?trait_def_id);
|
||||||
|
|
||||||
let Some(self_ty) = opt_self_ty else {
|
let Some(self_ty) = opt_self_ty else {
|
||||||
return Err(self.error_missing_qpath_self_ty(trait_def_id, span, item_segment, kind));
|
return Err(self.error_missing_qpath_self_ty(
|
||||||
|
trait_def_id,
|
||||||
|
span,
|
||||||
|
item_segment,
|
||||||
|
assoc_tag,
|
||||||
|
));
|
||||||
};
|
};
|
||||||
debug!(?self_ty);
|
debug!(?self_ty);
|
||||||
|
|
||||||
|
@ -1840,7 +1854,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
trait_def_id: DefId,
|
trait_def_id: DefId,
|
||||||
span: Span,
|
span: Span,
|
||||||
item_segment: &hir::PathSegment<'tcx>,
|
item_segment: &hir::PathSegment<'tcx>,
|
||||||
kind: ty::AssocKind,
|
assoc_tag: ty::AssocTag,
|
||||||
) -> ErrorGuaranteed {
|
) -> ErrorGuaranteed {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
let path_str = tcx.def_path_str(trait_def_id);
|
let path_str = tcx.def_path_str(trait_def_id);
|
||||||
|
@ -1877,7 +1891,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
// FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that
|
// FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that
|
||||||
// references the trait. Relevant for the first case in
|
// references the trait. Relevant for the first case in
|
||||||
// `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs`
|
// `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs`
|
||||||
self.report_ambiguous_assoc(span, &type_names, &[path_str], item_segment.ident.name, kind)
|
self.report_ambiguous_assoc(
|
||||||
|
span,
|
||||||
|
&type_names,
|
||||||
|
&[path_str],
|
||||||
|
item_segment.ident.name,
|
||||||
|
assoc_tag,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prohibit_generic_args<'a>(
|
pub fn prohibit_generic_args<'a>(
|
||||||
|
@ -2862,7 +2882,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
let assoc = tcx.associated_items(trait_ref.def_id).find_by_ident_and_kind(
|
let assoc = tcx.associated_items(trait_ref.def_id).find_by_ident_and_kind(
|
||||||
tcx,
|
tcx,
|
||||||
*ident,
|
*ident,
|
||||||
ty::AssocKind::Fn,
|
ty::AssocTag::Fn,
|
||||||
trait_ref.def_id,
|
trait_ref.def_id,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
|
|
@ -112,14 +112,14 @@ pub(crate) fn enforce_impl_lifetime_params_are_constrained(
|
||||||
.flat_map(|def_id| {
|
.flat_map(|def_id| {
|
||||||
let item = tcx.associated_item(def_id);
|
let item = tcx.associated_item(def_id);
|
||||||
match item.kind {
|
match item.kind {
|
||||||
ty::AssocKind::Type => {
|
ty::AssocKind::Type { .. } => {
|
||||||
if item.defaultness(tcx).has_value() {
|
if item.defaultness(tcx).has_value() {
|
||||||
cgp::parameters_for(tcx, tcx.type_of(def_id).instantiate_identity(), true)
|
cgp::parameters_for(tcx, tcx.type_of(def_id).instantiate_identity(), true)
|
||||||
} else {
|
} else {
|
||||||
vec![]
|
vec![]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::AssocKind::Fn | ty::AssocKind::Const => vec![],
|
ty::AssocKind::Fn { .. } | ty::AssocKind::Const { .. } => vec![],
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
|
@ -1871,10 +1871,11 @@ impl<'a> State<'a> {
|
||||||
fn print_pat(&mut self, pat: &hir::Pat<'_>) {
|
fn print_pat(&mut self, pat: &hir::Pat<'_>) {
|
||||||
self.maybe_print_comment(pat.span.lo());
|
self.maybe_print_comment(pat.span.lo());
|
||||||
self.ann.pre(self, AnnNode::Pat(pat));
|
self.ann.pre(self, AnnNode::Pat(pat));
|
||||||
// Pat isn't normalized, but the beauty of it
|
// Pat isn't normalized, but the beauty of it is that it doesn't matter.
|
||||||
// is that it doesn't matter
|
|
||||||
match pat.kind {
|
match pat.kind {
|
||||||
PatKind::Missing => unreachable!(),
|
// Printing `_` isn't ideal for a missing pattern, but it's easy and good enough.
|
||||||
|
// E.g. `fn(u32)` gets printed as `fn(_: u32)`.
|
||||||
|
PatKind::Missing => self.word("_"),
|
||||||
PatKind::Wild => self.word("_"),
|
PatKind::Wild => self.word("_"),
|
||||||
PatKind::Never => self.word("!"),
|
PatKind::Never => self.word("!"),
|
||||||
PatKind::Binding(BindingMode(by_ref, mutbl), _, ident, sub) => {
|
PatKind::Binding(BindingMode(by_ref, mutbl), _, ident, sub) => {
|
||||||
|
@ -2164,7 +2165,9 @@ impl<'a> State<'a> {
|
||||||
s.end();
|
s.end();
|
||||||
});
|
});
|
||||||
if decl.c_variadic {
|
if decl.c_variadic {
|
||||||
|
if !decl.inputs.is_empty() {
|
||||||
self.word(", ");
|
self.word(", ");
|
||||||
|
}
|
||||||
print_arg(self, None);
|
print_arg(self, None);
|
||||||
self.word("...");
|
self.word("...");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1089,14 +1089,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
/// This function checks whether the method is not static and does not accept other parameters than `self`.
|
/// This function checks whether the method is not static and does not accept other parameters than `self`.
|
||||||
fn has_only_self_parameter(&self, method: &AssocItem) -> bool {
|
fn has_only_self_parameter(&self, method: &AssocItem) -> bool {
|
||||||
match method.kind {
|
method.is_method()
|
||||||
ty::AssocKind::Fn => {
|
&& self.tcx.fn_sig(method.def_id).skip_binder().inputs().skip_binder().len() == 1
|
||||||
method.fn_has_self_parameter
|
|
||||||
&& self.tcx.fn_sig(method.def_id).skip_binder().inputs().skip_binder().len()
|
|
||||||
== 1
|
|
||||||
}
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If the given `HirId` corresponds to a block with a trailing expression, return that expression
|
/// If the given `HirId` corresponds to a block with a trailing expression, return that expression
|
||||||
|
|
|
@ -2588,9 +2588,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flat_map(|i| self.tcx.associated_items(i).in_definition_order())
|
.flat_map(|i| self.tcx.associated_items(i).in_definition_order())
|
||||||
// Only assoc fn with no receivers.
|
// Only assoc fn with no receivers.
|
||||||
.filter(|item| {
|
.filter(|item| item.is_fn() && !item.is_method())
|
||||||
matches!(item.kind, ty::AssocKind::Fn) && !item.fn_has_self_parameter
|
|
||||||
})
|
|
||||||
.filter_map(|item| {
|
.filter_map(|item| {
|
||||||
// Only assoc fns that return `Self`
|
// Only assoc fns that return `Self`
|
||||||
let fn_sig = self.tcx.fn_sig(item.def_id).skip_binder();
|
let fn_sig = self.tcx.fn_sig(item.def_id).skip_binder();
|
||||||
|
@ -2603,8 +2601,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let input_len = fn_sig.inputs().skip_binder().len();
|
let input_len = fn_sig.inputs().skip_binder().len();
|
||||||
let order = !item.name.as_str().starts_with("new");
|
let name = item.name();
|
||||||
Some((order, item.name, input_len))
|
let order = !name.as_str().starts_with("new");
|
||||||
|
Some((order, name, input_len))
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
items.sort_by_key(|(order, _, _)| *order);
|
items.sort_by_key(|(order, _, _)| *order);
|
||||||
|
|
|
@ -616,7 +616,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
if let Some((DefKind::AssocFn, def_id)) =
|
if let Some((DefKind::AssocFn, def_id)) =
|
||||||
self.typeck_results.borrow().type_dependent_def(call_expr.hir_id)
|
self.typeck_results.borrow().type_dependent_def(call_expr.hir_id)
|
||||||
&& let Some(assoc) = tcx.opt_associated_item(def_id)
|
&& let Some(assoc) = tcx.opt_associated_item(def_id)
|
||||||
&& assoc.fn_has_self_parameter
|
&& assoc.is_method()
|
||||||
{
|
{
|
||||||
Some(*receiver)
|
Some(*receiver)
|
||||||
} else {
|
} else {
|
||||||
|
@ -642,8 +642,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
TraitsInScope,
|
TraitsInScope,
|
||||||
|mut ctxt| ctxt.probe_for_similar_candidate(),
|
|mut ctxt| ctxt.probe_for_similar_candidate(),
|
||||||
)
|
)
|
||||||
&& let ty::AssocKind::Fn = assoc.kind
|
&& assoc.is_method()
|
||||||
&& assoc.fn_has_self_parameter
|
|
||||||
{
|
{
|
||||||
let args = self.infcx.fresh_args_for_item(call_name.span, assoc.def_id);
|
let args = self.infcx.fresh_args_for_item(call_name.span, assoc.def_id);
|
||||||
let fn_sig = tcx.fn_sig(assoc.def_id).instantiate(tcx, args);
|
let fn_sig = tcx.fn_sig(assoc.def_id).instantiate(tcx, args);
|
||||||
|
@ -684,10 +683,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
.all(|(expected, found)| self.may_coerce(*expected, *found))
|
.all(|(expected, found)| self.may_coerce(*expected, *found))
|
||||||
&& fn_sig.inputs()[1..].len() == input_types.len()
|
&& fn_sig.inputs()[1..].len() == input_types.len()
|
||||||
{
|
{
|
||||||
|
let assoc_name = assoc.name();
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
call_name.span,
|
call_name.span,
|
||||||
format!("you might have meant to use `{}`", assoc.name),
|
format!("you might have meant to use `{}`", assoc_name),
|
||||||
assoc.name,
|
assoc_name,
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
|
@ -707,7 +707,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
tcx.def_span(assoc.def_id),
|
tcx.def_span(assoc.def_id),
|
||||||
format!(
|
format!(
|
||||||
"there's is a method with similar name `{}`, but the arguments don't match",
|
"there's is a method with similar name `{}`, but the arguments don't match",
|
||||||
assoc.name,
|
assoc.name(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
|
@ -719,7 +719,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
format!(
|
format!(
|
||||||
"there's is a method with similar name `{}`, but their argument count \
|
"there's is a method with similar name `{}`, but their argument count \
|
||||||
doesn't match",
|
doesn't match",
|
||||||
assoc.name,
|
assoc.name(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -314,7 +314,7 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
|
||||||
item_def_id: DefId,
|
item_def_id: DefId,
|
||||||
item_segment: &rustc_hir::PathSegment<'tcx>,
|
item_segment: &rustc_hir::PathSegment<'tcx>,
|
||||||
poly_trait_ref: ty::PolyTraitRef<'tcx>,
|
poly_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||||
_kind: ty::AssocKind,
|
_assoc_tag: ty::AssocTag,
|
||||||
) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> {
|
) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> {
|
||||||
let trait_ref = self.instantiate_binder_with_fresh_vars(
|
let trait_ref = self.instantiate_binder_with_fresh_vars(
|
||||||
span,
|
span,
|
||||||
|
|
|
@ -381,9 +381,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
let mut suggestions = methods
|
let mut suggestions = methods
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|conversion_method| {
|
.filter_map(|conversion_method| {
|
||||||
|
let conversion_method_name = conversion_method.name();
|
||||||
let receiver_method_ident = expr.method_ident();
|
let receiver_method_ident = expr.method_ident();
|
||||||
if let Some(method_ident) = receiver_method_ident
|
if let Some(method_ident) = receiver_method_ident
|
||||||
&& method_ident.name == conversion_method.name
|
&& method_ident.name == conversion_method_name
|
||||||
{
|
{
|
||||||
return None; // do not suggest code that is already there (#53348)
|
return None; // do not suggest code that is already there (#53348)
|
||||||
}
|
}
|
||||||
|
@ -391,20 +392,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
let method_call_list = [sym::to_vec, sym::to_string];
|
let method_call_list = [sym::to_vec, sym::to_string];
|
||||||
let mut sugg = if let ExprKind::MethodCall(receiver_method, ..) = expr.kind
|
let mut sugg = if let ExprKind::MethodCall(receiver_method, ..) = expr.kind
|
||||||
&& receiver_method.ident.name == sym::clone
|
&& receiver_method.ident.name == sym::clone
|
||||||
&& method_call_list.contains(&conversion_method.name)
|
&& method_call_list.contains(&conversion_method_name)
|
||||||
// If receiver is `.clone()` and found type has one of those methods,
|
// If receiver is `.clone()` and found type has one of those methods,
|
||||||
// we guess that the user wants to convert from a slice type (`&[]` or `&str`)
|
// we guess that the user wants to convert from a slice type (`&[]` or `&str`)
|
||||||
// to an owned type (`Vec` or `String`). These conversions clone internally,
|
// to an owned type (`Vec` or `String`). These conversions clone internally,
|
||||||
// so we remove the user's `clone` call.
|
// so we remove the user's `clone` call.
|
||||||
{
|
{
|
||||||
vec![(receiver_method.ident.span, conversion_method.name.to_string())]
|
vec![(receiver_method.ident.span, conversion_method_name.to_string())]
|
||||||
} else if expr.precedence() < ExprPrecedence::Unambiguous {
|
} else if expr.precedence() < ExprPrecedence::Unambiguous {
|
||||||
vec![
|
vec![
|
||||||
(expr.span.shrink_to_lo(), "(".to_string()),
|
(expr.span.shrink_to_lo(), "(".to_string()),
|
||||||
(expr.span.shrink_to_hi(), format!(").{}()", conversion_method.name)),
|
(expr.span.shrink_to_hi(), format!(").{}()", conversion_method_name)),
|
||||||
]
|
]
|
||||||
} else {
|
} else {
|
||||||
vec![(expr.span.shrink_to_hi(), format!(".{}()", conversion_method.name))]
|
vec![(expr.span.shrink_to_hi(), format!(".{}()", conversion_method_name))]
|
||||||
};
|
};
|
||||||
let struct_pat_shorthand_field =
|
let struct_pat_shorthand_field =
|
||||||
self.tcx.hir_maybe_get_struct_pattern_shorthand_field(expr);
|
self.tcx.hir_maybe_get_struct_pattern_shorthand_field(expr);
|
||||||
|
|
|
@ -265,7 +265,7 @@ fn infer_type_if_missing<'tcx>(fcx: &FnCtxt<'_, 'tcx>, node: Node<'tcx>) -> Opti
|
||||||
let expected_type = if let Some(&hir::Ty { kind: hir::TyKind::Infer(()), span, .. }) = node.ty()
|
let expected_type = if let Some(&hir::Ty { kind: hir::TyKind::Infer(()), span, .. }) = node.ty()
|
||||||
{
|
{
|
||||||
if let Some(item) = tcx.opt_associated_item(def_id.into())
|
if let Some(item) = tcx.opt_associated_item(def_id.into())
|
||||||
&& let ty::AssocKind::Const = item.kind
|
&& let ty::AssocKind::Const { .. } = item.kind
|
||||||
&& let ty::AssocItemContainer::Impl = item.container
|
&& let ty::AssocItemContainer::Impl = item.container
|
||||||
&& let Some(trait_item_def_id) = item.trait_item_def_id
|
&& let Some(trait_item_def_id) = item.trait_item_def_id
|
||||||
{
|
{
|
||||||
|
|
|
@ -379,7 +379,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
};
|
};
|
||||||
|
|
||||||
let def_id = method_item.def_id;
|
let def_id = method_item.def_id;
|
||||||
if method_item.kind != ty::AssocKind::Fn {
|
if !method_item.is_fn() {
|
||||||
span_bug!(tcx.def_span(def_id), "expected `{m_name}` to be an associated function");
|
span_bug!(tcx.def_span(def_id), "expected `{m_name}` to be an associated function");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -529,7 +529,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let def_kind = pick.item.kind.as_def_kind();
|
let def_kind = pick.item.as_def_kind();
|
||||||
tcx.check_stability(pick.item.def_id, Some(expr_id), span, Some(method_name.span));
|
tcx.check_stability(pick.item.def_id, Some(expr_id), span, Some(method_name.span));
|
||||||
Ok((def_kind, pick.item.def_id))
|
Ok((def_kind, pick.item.def_id))
|
||||||
}
|
}
|
||||||
|
|
|
@ -992,7 +992,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||||
|
|
||||||
fn matches_return_type(&self, method: ty::AssocItem, expected: Ty<'tcx>) -> bool {
|
fn matches_return_type(&self, method: ty::AssocItem, expected: Ty<'tcx>) -> bool {
|
||||||
match method.kind {
|
match method.kind {
|
||||||
ty::AssocKind::Fn => self.probe(|_| {
|
ty::AssocKind::Fn { .. } => self.probe(|_| {
|
||||||
let args = self.fresh_args_for_item(self.span, method.def_id);
|
let args = self.fresh_args_for_item(self.span, method.def_id);
|
||||||
let fty = self.tcx.fn_sig(method.def_id).instantiate(self.tcx, args);
|
let fty = self.tcx.fn_sig(method.def_id).instantiate(self.tcx, args);
|
||||||
let fty = self.instantiate_binder_with_fresh_vars(self.span, infer::FnCall, fty);
|
let fty = self.instantiate_binder_with_fresh_vars(self.span, infer::FnCall, fty);
|
||||||
|
@ -1583,7 +1583,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
) {
|
) {
|
||||||
self.private_candidate.set(Some((pick.item.kind.as_def_kind(), pick.item.def_id)));
|
self.private_candidate.set(Some((pick.item.as_def_kind(), pick.item.def_id)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
|
@ -1671,16 +1671,7 @@ impl<'tcx> Pick<'tcx> {
|
||||||
/// Do not use for type checking.
|
/// Do not use for type checking.
|
||||||
pub(crate) fn differs_from(&self, other: &Self) -> bool {
|
pub(crate) fn differs_from(&self, other: &Self) -> bool {
|
||||||
let Self {
|
let Self {
|
||||||
item:
|
item: AssocItem { def_id, kind: _, container: _, trait_item_def_id: _ },
|
||||||
AssocItem {
|
|
||||||
def_id,
|
|
||||||
name: _,
|
|
||||||
kind: _,
|
|
||||||
container: _,
|
|
||||||
trait_item_def_id: _,
|
|
||||||
fn_has_self_parameter: _,
|
|
||||||
opt_rpitit_info: _,
|
|
||||||
},
|
|
||||||
kind: _,
|
kind: _,
|
||||||
import_ids: _,
|
import_ids: _,
|
||||||
autoderefs: _,
|
autoderefs: _,
|
||||||
|
@ -1703,7 +1694,7 @@ impl<'tcx> Pick<'tcx> {
|
||||||
if self.unstable_candidates.is_empty() {
|
if self.unstable_candidates.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let def_kind = self.item.kind.as_def_kind();
|
let def_kind = self.item.as_def_kind();
|
||||||
tcx.node_span_lint(lint::builtin::UNSTABLE_NAME_COLLISIONS, scope_expr_id, span, |lint| {
|
tcx.node_span_lint(lint::builtin::UNSTABLE_NAME_COLLISIONS, scope_expr_id, span, |lint| {
|
||||||
lint.primary_message(format!(
|
lint.primary_message(format!(
|
||||||
"{} {} with this name may be added to the standard library in the future",
|
"{} {} with this name may be added to the standard library in the future",
|
||||||
|
@ -1712,7 +1703,7 @@ impl<'tcx> Pick<'tcx> {
|
||||||
));
|
));
|
||||||
|
|
||||||
match (self.item.kind, self.item.container) {
|
match (self.item.kind, self.item.container) {
|
||||||
(ty::AssocKind::Fn, _) => {
|
(ty::AssocKind::Fn { .. }, _) => {
|
||||||
// FIXME: This should be a `span_suggestion` instead of `help`
|
// FIXME: This should be a `span_suggestion` instead of `help`
|
||||||
// However `self.span` only
|
// However `self.span` only
|
||||||
// highlights the method name, so we can't use it. Also consider reusing
|
// highlights the method name, so we can't use it. Also consider reusing
|
||||||
|
@ -1723,17 +1714,12 @@ impl<'tcx> Pick<'tcx> {
|
||||||
tcx.def_path_str(self.item.def_id),
|
tcx.def_path_str(self.item.def_id),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
(ty::AssocKind::Const, ty::AssocItemContainer::Trait) => {
|
(ty::AssocKind::Const { name }, ty::AssocItemContainer::Trait) => {
|
||||||
let def_id = self.item.container_id(tcx);
|
let def_id = self.item.container_id(tcx);
|
||||||
lint.span_suggestion(
|
lint.span_suggestion(
|
||||||
span,
|
span,
|
||||||
"use the fully qualified path to the associated const",
|
"use the fully qualified path to the associated const",
|
||||||
format!(
|
format!("<{} as {}>::{}", self.self_ty, tcx.def_path_str(def_id), name),
|
||||||
"<{} as {}>::{}",
|
|
||||||
self.self_ty,
|
|
||||||
tcx.def_path_str(def_id),
|
|
||||||
self.item.name
|
|
||||||
),
|
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2222,7 +2208,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||||
let best_name = {
|
let best_name = {
|
||||||
let names = applicable_close_candidates
|
let names = applicable_close_candidates
|
||||||
.iter()
|
.iter()
|
||||||
.map(|cand| cand.name)
|
.map(|cand| cand.name())
|
||||||
.collect::<Vec<Symbol>>();
|
.collect::<Vec<Symbol>>();
|
||||||
find_best_match_for_name_with_substrings(
|
find_best_match_for_name_with_substrings(
|
||||||
&names,
|
&names,
|
||||||
|
@ -2234,10 +2220,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||||
applicable_close_candidates
|
applicable_close_candidates
|
||||||
.iter()
|
.iter()
|
||||||
.find(|cand| self.matches_by_doc_alias(cand.def_id))
|
.find(|cand| self.matches_by_doc_alias(cand.def_id))
|
||||||
.map(|cand| cand.name)
|
.map(|cand| cand.name())
|
||||||
});
|
});
|
||||||
Ok(best_name.and_then(|best_name| {
|
Ok(best_name.and_then(|best_name| {
|
||||||
applicable_close_candidates.into_iter().find(|method| method.name == best_name)
|
applicable_close_candidates
|
||||||
|
.into_iter()
|
||||||
|
.find(|method| method.name() == best_name)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -2252,10 +2240,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||||
// In Path mode (i.e., resolving a value like `T::next`), consider any
|
// In Path mode (i.e., resolving a value like `T::next`), consider any
|
||||||
// associated value (i.e., methods, constants) but not types.
|
// associated value (i.e., methods, constants) but not types.
|
||||||
match self.mode {
|
match self.mode {
|
||||||
Mode::MethodCall => item.fn_has_self_parameter,
|
Mode::MethodCall => item.is_method(),
|
||||||
Mode::Path => match item.kind {
|
Mode::Path => match item.kind {
|
||||||
ty::AssocKind::Type => false,
|
ty::AssocKind::Type { .. } => false,
|
||||||
ty::AssocKind::Fn | ty::AssocKind::Const => true,
|
ty::AssocKind::Fn { .. } | ty::AssocKind::Const { .. } => true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
// FIXME -- check for types that deref to `Self`,
|
// FIXME -- check for types that deref to `Self`,
|
||||||
|
@ -2277,7 +2265,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||||
impl_ty: Ty<'tcx>,
|
impl_ty: Ty<'tcx>,
|
||||||
args: GenericArgsRef<'tcx>,
|
args: GenericArgsRef<'tcx>,
|
||||||
) -> (Ty<'tcx>, Option<Ty<'tcx>>) {
|
) -> (Ty<'tcx>, Option<Ty<'tcx>>) {
|
||||||
if item.kind == ty::AssocKind::Fn && self.mode == Mode::MethodCall {
|
if item.is_fn() && self.mode == Mode::MethodCall {
|
||||||
let sig = self.xform_method_sig(item.def_id, args);
|
let sig = self.xform_method_sig(item.def_id, args);
|
||||||
(sig.inputs()[0], Some(sig.output()))
|
(sig.inputs()[0], Some(sig.output()))
|
||||||
} else {
|
} else {
|
||||||
|
@ -2328,8 +2316,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||||
/// Determine if the given associated item type is relevant in the current context.
|
/// Determine if the given associated item type is relevant in the current context.
|
||||||
fn is_relevant_kind_for_mode(&self, kind: ty::AssocKind) -> bool {
|
fn is_relevant_kind_for_mode(&self, kind: ty::AssocKind) -> bool {
|
||||||
match (self.mode, kind) {
|
match (self.mode, kind) {
|
||||||
(Mode::MethodCall, ty::AssocKind::Fn) => true,
|
(Mode::MethodCall, ty::AssocKind::Fn { .. }) => true,
|
||||||
(Mode::Path, ty::AssocKind::Const | ty::AssocKind::Fn) => true,
|
(Mode::Path, ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. }) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2411,7 +2399,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
match edit_distance_with_substrings(
|
match edit_distance_with_substrings(
|
||||||
name.as_str(),
|
name.as_str(),
|
||||||
x.name.as_str(),
|
x.name().as_str(),
|
||||||
max_dist,
|
max_dist,
|
||||||
) {
|
) {
|
||||||
Some(d) => d > 0,
|
Some(d) => d > 0,
|
||||||
|
|
|
@ -713,7 +713,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
&& let Some(candidate) = tcx.associated_items(impl_def_id).find_by_ident_and_kind(
|
&& let Some(candidate) = tcx.associated_items(impl_def_id).find_by_ident_and_kind(
|
||||||
self.tcx,
|
self.tcx,
|
||||||
item_ident,
|
item_ident,
|
||||||
ty::AssocKind::Type,
|
ty::AssocTag::Type,
|
||||||
impl_def_id,
|
impl_def_id,
|
||||||
)
|
)
|
||||||
&& let Some(adt_def) = tcx.type_of(candidate.def_id).skip_binder().ty_adt_def()
|
&& let Some(adt_def) = tcx.type_of(candidate.def_id).skip_binder().ty_adt_def()
|
||||||
|
@ -1442,7 +1442,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
if let Some(assoc) = self.associated_value(*def_id, item_ident) {
|
if let Some(assoc) = self.associated_value(*def_id, item_ident) {
|
||||||
// Check for both mode is the same so we avoid suggesting
|
// Check for both mode is the same so we avoid suggesting
|
||||||
// incorrect associated item.
|
// incorrect associated item.
|
||||||
match (mode, assoc.fn_has_self_parameter, source) {
|
match (mode, assoc.is_method(), source) {
|
||||||
(Mode::MethodCall, true, SelfSource::MethodCall(_)) => {
|
(Mode::MethodCall, true, SelfSource::MethodCall(_)) => {
|
||||||
// We check that the suggest type is actually
|
// We check that the suggest type is actually
|
||||||
// different from the received one
|
// different from the received one
|
||||||
|
@ -1722,7 +1722,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
// that had unsatisfied trait bounds
|
// that had unsatisfied trait bounds
|
||||||
if unsatisfied_predicates.is_empty()
|
if unsatisfied_predicates.is_empty()
|
||||||
// ...or if we already suggested that name because of `rustc_confusable` annotation.
|
// ...or if we already suggested that name because of `rustc_confusable` annotation.
|
||||||
&& Some(similar_candidate.name) != confusable_suggested
|
&& Some(similar_candidate.name()) != confusable_suggested
|
||||||
{
|
{
|
||||||
self.find_likely_intended_associated_item(
|
self.find_likely_intended_associated_item(
|
||||||
&mut err,
|
&mut err,
|
||||||
|
@ -1819,12 +1819,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
) {
|
) {
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
let def_kind = similar_candidate.kind.as_def_kind();
|
let def_kind = similar_candidate.as_def_kind();
|
||||||
let an = self.tcx.def_kind_descr_article(def_kind, similar_candidate.def_id);
|
let an = self.tcx.def_kind_descr_article(def_kind, similar_candidate.def_id);
|
||||||
|
let similar_candidate_name = similar_candidate.name();
|
||||||
let msg = format!(
|
let msg = format!(
|
||||||
"there is {an} {} `{}` with a similar name",
|
"there is {an} {} `{}` with a similar name",
|
||||||
self.tcx.def_kind_descr(def_kind, similar_candidate.def_id),
|
self.tcx.def_kind_descr(def_kind, similar_candidate.def_id),
|
||||||
similar_candidate.name,
|
similar_candidate_name,
|
||||||
);
|
);
|
||||||
// Methods are defined within the context of a struct and their first parameter
|
// Methods are defined within the context of a struct and their first parameter
|
||||||
// is always `self`, which represents the instance of the struct the method is
|
// is always `self`, which represents the instance of the struct the method is
|
||||||
|
@ -1834,7 +1835,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
let ty_args = self.infcx.fresh_args_for_item(span, similar_candidate.def_id);
|
let ty_args = self.infcx.fresh_args_for_item(span, similar_candidate.def_id);
|
||||||
let fn_sig = tcx.fn_sig(similar_candidate.def_id).instantiate(tcx, ty_args);
|
let fn_sig = tcx.fn_sig(similar_candidate.def_id).instantiate(tcx, ty_args);
|
||||||
let fn_sig = self.instantiate_binder_with_fresh_vars(span, infer::FnCall, fn_sig);
|
let fn_sig = self.instantiate_binder_with_fresh_vars(span, infer::FnCall, fn_sig);
|
||||||
if similar_candidate.fn_has_self_parameter {
|
if similar_candidate.is_method() {
|
||||||
if let Some(args) = args
|
if let Some(args) = args
|
||||||
&& fn_sig.inputs()[1..].len() == args.len()
|
&& fn_sig.inputs()[1..].len() == args.len()
|
||||||
{
|
{
|
||||||
|
@ -1843,7 +1844,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
span,
|
span,
|
||||||
msg,
|
msg,
|
||||||
similar_candidate.name,
|
similar_candidate_name,
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1865,7 +1866,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
span,
|
span,
|
||||||
msg,
|
msg,
|
||||||
similar_candidate.name,
|
similar_candidate_name,
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1878,7 +1879,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
span,
|
span,
|
||||||
msg,
|
msg,
|
||||||
similar_candidate.name,
|
similar_candidate_name,
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1902,7 +1903,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
{
|
{
|
||||||
if let Some(candidates) = find_attr!(self.tcx.get_all_attrs(inherent_method.def_id), AttributeKind::Confusables{symbols, ..} => symbols)
|
if let Some(candidates) = find_attr!(self.tcx.get_all_attrs(inherent_method.def_id), AttributeKind::Confusables{symbols, ..} => symbols)
|
||||||
&& candidates.contains(&item_name.name)
|
&& candidates.contains(&item_name.name)
|
||||||
&& let ty::AssocKind::Fn = inherent_method.kind
|
&& inherent_method.is_fn()
|
||||||
{
|
{
|
||||||
let args =
|
let args =
|
||||||
ty::GenericArgs::identity_for_item(self.tcx, inherent_method.def_id)
|
ty::GenericArgs::identity_for_item(self.tcx, inherent_method.def_id)
|
||||||
|
@ -1918,6 +1919,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
infer::FnCall,
|
infer::FnCall,
|
||||||
fn_sig,
|
fn_sig,
|
||||||
);
|
);
|
||||||
|
let name = inherent_method.name();
|
||||||
if let Some(ref args) = call_args
|
if let Some(ref args) = call_args
|
||||||
&& fn_sig.inputs()[1..]
|
&& fn_sig.inputs()[1..]
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -1927,20 +1929,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
{
|
{
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
item_name.span,
|
item_name.span,
|
||||||
format!("you might have meant to use `{}`", inherent_method.name),
|
format!("you might have meant to use `{}`", name),
|
||||||
inherent_method.name,
|
name,
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
return Some(inherent_method.name);
|
return Some(name);
|
||||||
} else if let None = call_args {
|
} else if let None = call_args {
|
||||||
err.span_note(
|
err.span_note(
|
||||||
self.tcx.def_span(inherent_method.def_id),
|
self.tcx.def_span(inherent_method.def_id),
|
||||||
format!(
|
format!("you might have meant to use method `{}`", name),
|
||||||
"you might have meant to use method `{}`",
|
|
||||||
inherent_method.name,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
return Some(inherent_method.name);
|
return Some(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2116,8 +2115,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
// Only assoc fn with no receivers and only if
|
// Only assoc fn with no receivers and only if
|
||||||
// they are resolvable
|
// they are resolvable
|
||||||
.filter(|item| {
|
.filter(|item| {
|
||||||
matches!(item.kind, ty::AssocKind::Fn)
|
matches!(item.kind, ty::AssocKind::Fn { has_self: false, .. })
|
||||||
&& !item.fn_has_self_parameter
|
|
||||||
&& self
|
&& self
|
||||||
.probe_for_name(
|
.probe_for_name(
|
||||||
Mode::Path,
|
Mode::Path,
|
||||||
|
@ -2261,7 +2259,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
};
|
};
|
||||||
|
|
||||||
let assoc = self.associated_value(assoc_did, item_name)?;
|
let assoc = self.associated_value(assoc_did, item_name)?;
|
||||||
if assoc.kind != ty::AssocKind::Fn {
|
if !assoc.is_fn() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3208,7 +3206,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
// If this method receives `&self`, then the provided
|
// If this method receives `&self`, then the provided
|
||||||
// argument _should_ coerce, so it's valid to suggest
|
// argument _should_ coerce, so it's valid to suggest
|
||||||
// just changing the path.
|
// just changing the path.
|
||||||
&& pick.item.fn_has_self_parameter
|
&& pick.item.is_method()
|
||||||
&& let Some(self_ty) =
|
&& let Some(self_ty) =
|
||||||
self.tcx.fn_sig(pick.item.def_id).instantiate_identity().inputs().skip_binder().get(0)
|
self.tcx.fn_sig(pick.item.def_id).instantiate_identity().inputs().skip_binder().get(0)
|
||||||
&& self_ty.is_ref()
|
&& self_ty.is_ref()
|
||||||
|
@ -3560,7 +3558,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
|| (("Pin::new" == *pre)
|
|| (("Pin::new" == *pre)
|
||||||
&& ((sym::as_ref == item_name.name) || !unpin))
|
&& ((sym::as_ref == item_name.name) || !unpin))
|
||||||
|| inputs_len.is_some_and(|inputs_len| {
|
|| inputs_len.is_some_and(|inputs_len| {
|
||||||
pick.item.kind == ty::AssocKind::Fn
|
pick.item.is_fn()
|
||||||
&& self
|
&& self
|
||||||
.tcx
|
.tcx
|
||||||
.fn_sig(pick.item.def_id)
|
.fn_sig(pick.item.def_id)
|
||||||
|
@ -3618,7 +3616,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
&& pick.autoderefs == 0
|
&& pick.autoderefs == 0
|
||||||
// Check that the method of the same name that was found on the new `Pin<T>`
|
// Check that the method of the same name that was found on the new `Pin<T>`
|
||||||
// receiver has the same number of arguments that appear in the user's code.
|
// receiver has the same number of arguments that appear in the user's code.
|
||||||
&& inputs_len.is_some_and(|inputs_len| pick.item.kind == ty::AssocKind::Fn && self.tcx.fn_sig(pick.item.def_id).skip_binder().skip_binder().inputs().len() == inputs_len)
|
&& inputs_len.is_some_and(|inputs_len| pick.item.is_fn() && self.tcx.fn_sig(pick.item.def_id).skip_binder().skip_binder().inputs().len() == inputs_len)
|
||||||
{
|
{
|
||||||
let indent = self
|
let indent = self
|
||||||
.tcx
|
.tcx
|
||||||
|
@ -3756,7 +3754,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
&& self
|
&& self
|
||||||
.associated_value(info.def_id, item_name)
|
.associated_value(info.def_id, item_name)
|
||||||
.filter(|item| {
|
.filter(|item| {
|
||||||
if let ty::AssocKind::Fn = item.kind {
|
if item.is_fn() {
|
||||||
let id = item
|
let id = item
|
||||||
.def_id
|
.def_id
|
||||||
.as_local()
|
.as_local()
|
||||||
|
@ -4279,17 +4277,17 @@ fn print_disambiguation_help<'tcx>(
|
||||||
item: ty::AssocItem,
|
item: ty::AssocItem,
|
||||||
) -> Option<String> {
|
) -> Option<String> {
|
||||||
let trait_impl_type = trait_ref.self_ty().peel_refs();
|
let trait_impl_type = trait_ref.self_ty().peel_refs();
|
||||||
let trait_ref = if item.fn_has_self_parameter {
|
let trait_ref = if item.is_method() {
|
||||||
trait_ref.print_only_trait_name().to_string()
|
trait_ref.print_only_trait_name().to_string()
|
||||||
} else {
|
} else {
|
||||||
format!("<{} as {}>", trait_ref.args[0], trait_ref.print_only_trait_name())
|
format!("<{} as {}>", trait_ref.args[0], trait_ref.print_only_trait_name())
|
||||||
};
|
};
|
||||||
Some(
|
Some(
|
||||||
if matches!(item.kind, ty::AssocKind::Fn)
|
if item.is_fn()
|
||||||
&& let SelfSource::MethodCall(receiver) = source
|
&& let SelfSource::MethodCall(receiver) = source
|
||||||
&& let Some(args) = args
|
&& let Some(args) = args
|
||||||
{
|
{
|
||||||
let def_kind_descr = tcx.def_kind_descr(item.kind.as_def_kind(), item.def_id);
|
let def_kind_descr = tcx.def_kind_descr(item.as_def_kind(), item.def_id);
|
||||||
let item_name = item.ident(tcx);
|
let item_name = item.ident(tcx);
|
||||||
let first_input =
|
let first_input =
|
||||||
tcx.fn_sig(item.def_id).instantiate_identity().skip_binder().inputs().get(0);
|
tcx.fn_sig(item.def_id).instantiate_identity().skip_binder().inputs().get(0);
|
||||||
|
@ -4304,7 +4302,7 @@ fn print_disambiguation_help<'tcx>(
|
||||||
let args = if let Some(first_arg_type) = first_arg_type
|
let args = if let Some(first_arg_type) = first_arg_type
|
||||||
&& (first_arg_type == tcx.types.self_param
|
&& (first_arg_type == tcx.types.self_param
|
||||||
|| first_arg_type == trait_impl_type
|
|| first_arg_type == trait_impl_type
|
||||||
|| item.fn_has_self_parameter)
|
|| item.is_method())
|
||||||
{
|
{
|
||||||
Some(receiver)
|
Some(receiver)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -372,7 +372,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
.associated_item_def_ids(def_id)
|
.associated_item_def_ids(def_id)
|
||||||
.iter()
|
.iter()
|
||||||
.find(|item_def_id| {
|
.find(|item_def_id| {
|
||||||
self.tcx.associated_item(*item_def_id).name == sym::Output
|
self.tcx.associated_item(*item_def_id).name() == sym::Output
|
||||||
})
|
})
|
||||||
.cloned()
|
.cloned()
|
||||||
});
|
});
|
||||||
|
|
|
@ -855,11 +855,11 @@ impl<'tcx> LateContext<'tcx> {
|
||||||
&self,
|
&self,
|
||||||
self_ty: Ty<'tcx>,
|
self_ty: Ty<'tcx>,
|
||||||
trait_id: DefId,
|
trait_id: DefId,
|
||||||
name: &str,
|
name: Symbol,
|
||||||
) -> Option<Ty<'tcx>> {
|
) -> Option<Ty<'tcx>> {
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
tcx.associated_items(trait_id)
|
tcx.associated_items(trait_id)
|
||||||
.find_by_ident_and_kind(tcx, Ident::from_str(name), ty::AssocKind::Type, trait_id)
|
.find_by_ident_and_kind(tcx, Ident::with_dummy_span(name), ty::AssocTag::Type, trait_id)
|
||||||
.and_then(|assoc| {
|
.and_then(|assoc| {
|
||||||
let proj = Ty::new_projection(tcx, assoc.def_id, [self_ty]);
|
let proj = Ty::new_projection(tcx, assoc.def_id, [self_ty]);
|
||||||
tcx.try_normalize_erasing_regions(self.typing_env(), proj).ok()
|
tcx.try_normalize_erasing_regions(self.typing_env(), proj).ok()
|
||||||
|
|
|
@ -69,7 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait {
|
||||||
&& let ty::Dynamic(data, _, ty::Dyn) = self_ty.kind()
|
&& let ty::Dynamic(data, _, ty::Dyn) = self_ty.kind()
|
||||||
&& let Some(self_principal) = data.principal()
|
&& let Some(self_principal) = data.principal()
|
||||||
// `<T as Deref>::Target` is `dyn target_principal`
|
// `<T as Deref>::Target` is `dyn target_principal`
|
||||||
&& let Some(target) = cx.get_associated_type(self_ty, did, "Target")
|
&& let Some(target) = cx.get_associated_type(self_ty, did, sym::Target)
|
||||||
&& let ty::Dynamic(data, _, ty::Dyn) = target.kind()
|
&& let ty::Dynamic(data, _, ty::Dyn) = target.kind()
|
||||||
&& let Some(target_principal) = data.principal()
|
&& let Some(target_principal) = data.principal()
|
||||||
// `target_principal` is a supertrait of `t_principal`
|
// `target_principal` is a supertrait of `t_principal`
|
||||||
|
|
|
@ -1332,29 +1332,30 @@ impl<'a> CrateMetadataRef<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_associated_item(self, id: DefIndex, sess: &'a Session) -> ty::AssocItem {
|
fn get_associated_item(self, id: DefIndex, sess: &'a Session) -> ty::AssocItem {
|
||||||
let name = if self.root.tables.opt_rpitit_info.get(self, id).is_some() {
|
let kind = match self.def_kind(id) {
|
||||||
kw::Empty
|
DefKind::AssocConst => ty::AssocKind::Const { name: self.item_name(id) },
|
||||||
|
DefKind::AssocFn => ty::AssocKind::Fn {
|
||||||
|
name: self.item_name(id),
|
||||||
|
has_self: self.get_fn_has_self_parameter(id, sess),
|
||||||
|
},
|
||||||
|
DefKind::AssocTy => {
|
||||||
|
let data = if let Some(rpitit_info) = self.root.tables.opt_rpitit_info.get(self, id)
|
||||||
|
{
|
||||||
|
ty::AssocTypeData::Rpitit(rpitit_info.decode(self))
|
||||||
} else {
|
} else {
|
||||||
self.item_name(id)
|
ty::AssocTypeData::Normal(self.item_name(id))
|
||||||
};
|
};
|
||||||
let (kind, has_self) = match self.def_kind(id) {
|
ty::AssocKind::Type { data }
|
||||||
DefKind::AssocConst => (ty::AssocKind::Const, false),
|
}
|
||||||
DefKind::AssocFn => (ty::AssocKind::Fn, self.get_fn_has_self_parameter(id, sess)),
|
|
||||||
DefKind::AssocTy => (ty::AssocKind::Type, false),
|
|
||||||
_ => bug!("cannot get associated-item of `{:?}`", self.def_key(id)),
|
_ => bug!("cannot get associated-item of `{:?}`", self.def_key(id)),
|
||||||
};
|
};
|
||||||
let container = self.root.tables.assoc_container.get(self, id).unwrap();
|
let container = self.root.tables.assoc_container.get(self, id).unwrap();
|
||||||
let opt_rpitit_info =
|
|
||||||
self.root.tables.opt_rpitit_info.get(self, id).map(|d| d.decode(self));
|
|
||||||
|
|
||||||
ty::AssocItem {
|
ty::AssocItem {
|
||||||
name,
|
|
||||||
kind,
|
kind,
|
||||||
def_id: self.local_def_id(id),
|
def_id: self.local_def_id(id),
|
||||||
trait_item_def_id: self.get_trait_item_def_id(id),
|
trait_item_def_id: self.get_trait_item_def_id(id),
|
||||||
container,
|
container,
|
||||||
fn_has_self_parameter: has_self,
|
|
||||||
opt_rpitit_info,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1338,7 +1338,7 @@ fn should_encode_const(def_kind: DefKind) -> bool {
|
||||||
fn should_encode_fn_impl_trait_in_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
|
fn should_encode_fn_impl_trait_in_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
|
||||||
if let Some(assoc_item) = tcx.opt_associated_item(def_id)
|
if let Some(assoc_item) = tcx.opt_associated_item(def_id)
|
||||||
&& assoc_item.container == ty::AssocItemContainer::Trait
|
&& assoc_item.container == ty::AssocItemContainer::Trait
|
||||||
&& assoc_item.kind == ty::AssocKind::Fn
|
&& assoc_item.is_fn()
|
||||||
{
|
{
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
|
@ -1691,7 +1691,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||||
|
|
||||||
match item.container {
|
match item.container {
|
||||||
AssocItemContainer::Trait => {
|
AssocItemContainer::Trait => {
|
||||||
if let ty::AssocKind::Type = item.kind {
|
if item.is_type() {
|
||||||
self.encode_explicit_item_bounds(def_id);
|
self.encode_explicit_item_bounds(def_id);
|
||||||
self.encode_explicit_item_self_bounds(def_id);
|
self.encode_explicit_item_self_bounds(def_id);
|
||||||
if tcx.is_conditionally_const(def_id) {
|
if tcx.is_conditionally_const(def_id) {
|
||||||
|
@ -1706,7 +1706,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(rpitit_info) = item.opt_rpitit_info {
|
if let ty::AssocKind::Type { data: ty::AssocTypeData::Rpitit(rpitit_info) } = item.kind {
|
||||||
record!(self.tables.opt_rpitit_info[def_id] <- rpitit_info);
|
record!(self.tables.opt_rpitit_info[def_id] <- rpitit_info);
|
||||||
if matches!(rpitit_info, ty::ImplTraitInTraitData::Trait { .. }) {
|
if matches!(rpitit_info, ty::ImplTraitInTraitData::Trait { .. }) {
|
||||||
record_array!(
|
record_array!(
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
//! This module used to contain a type called `Map`. That type has since been
|
||||||
|
//! eliminated, and all its methods are now on `TyCtxt`. But the module name
|
||||||
|
//! stays as `map` because there isn't an obviously better name for it.
|
||||||
|
|
||||||
use rustc_abi::ExternAbi;
|
use rustc_abi::ExternAbi;
|
||||||
use rustc_ast::visit::{VisitorResult, walk_list};
|
use rustc_ast::visit::{VisitorResult, walk_list};
|
||||||
use rustc_data_structures::fingerprint::Fingerprint;
|
use rustc_data_structures::fingerprint::Fingerprint;
|
||||||
|
@ -18,16 +22,6 @@ use crate::middle::debugger_visualizer::DebuggerVisualizerFile;
|
||||||
use crate::query::LocalCrate;
|
use crate::query::LocalCrate;
|
||||||
use crate::ty::TyCtxt;
|
use crate::ty::TyCtxt;
|
||||||
|
|
||||||
// FIXME: the structure was necessary in the past but now it
|
|
||||||
// only serves as "namespace" for HIR-related methods, and can be
|
|
||||||
// removed if all the methods are reasonably renamed and moved to tcx
|
|
||||||
// (https://github.com/rust-lang/rust/pull/118256#issuecomment-1826442834).
|
|
||||||
#[allow(unused)] // FIXME: temporary
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct Map<'hir> {
|
|
||||||
pub(super) tcx: TyCtxt<'hir>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An iterator that walks up the ancestor tree of a given `HirId`.
|
/// An iterator that walks up the ancestor tree of a given `HirId`.
|
||||||
/// Constructed using `tcx.hir_parent_iter(hir_id)`.
|
/// Constructed using `tcx.hir_parent_iter(hir_id)`.
|
||||||
struct ParentHirIterator<'tcx> {
|
struct ParentHirIterator<'tcx> {
|
||||||
|
@ -335,7 +329,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
|
|
||||||
/// Returns an iterator of the `DefId`s for all body-owners in this
|
/// Returns an iterator of the `DefId`s for all body-owners in this
|
||||||
/// crate. If you would prefer to iterate over the bodies
|
/// crate. If you would prefer to iterate over the bodies
|
||||||
/// themselves, you can do `self.hir().krate().body_ids.iter()`.
|
/// themselves, you can do `self.hir_crate(()).body_ids.iter()`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn hir_body_owners(self) -> impl Iterator<Item = LocalDefId> {
|
pub fn hir_body_owners(self) -> impl Iterator<Item = LocalDefId> {
|
||||||
self.hir_crate_items(()).body_owners.iter().copied()
|
self.hir_crate_items(()).body_owners.iter().copied()
|
||||||
|
|
|
@ -116,11 +116,6 @@ impl ModuleItems {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> TyCtxt<'tcx> {
|
impl<'tcx> TyCtxt<'tcx> {
|
||||||
#[inline(always)]
|
|
||||||
pub fn hir(self) -> map::Map<'tcx> {
|
|
||||||
map::Map { tcx: self }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parent_module(self, id: HirId) -> LocalModDefId {
|
pub fn parent_module(self, id: HirId) -> LocalModDefId {
|
||||||
if !id.is_owner() && self.def_kind(id.owner) == DefKind::Mod {
|
if !id.is_owner() && self.def_kind(id.owner) == DefKind::Mod {
|
||||||
LocalModDefId::new_unchecked(id.owner.def_id)
|
LocalModDefId::new_unchecked(id.owner.def_id)
|
||||||
|
|
|
@ -1636,8 +1636,8 @@ pub fn find_self_call<'tcx>(
|
||||||
&body[block].terminator
|
&body[block].terminator
|
||||||
&& let Operand::Constant(box ConstOperand { const_, .. }) = func
|
&& let Operand::Constant(box ConstOperand { const_, .. }) = func
|
||||||
&& let ty::FnDef(def_id, fn_args) = *const_.ty().kind()
|
&& let ty::FnDef(def_id, fn_args) = *const_.ty().kind()
|
||||||
&& let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) =
|
&& let Some(item) = tcx.opt_associated_item(def_id)
|
||||||
tcx.opt_associated_item(def_id)
|
&& item.is_method()
|
||||||
&& let [Spanned { node: Operand::Move(self_place) | Operand::Copy(self_place), .. }, ..] =
|
&& let [Spanned { node: Operand::Move(self_place) | Operand::Copy(self_place), .. }, ..] =
|
||||||
**args
|
**args
|
||||||
{
|
{
|
||||||
|
|
|
@ -161,11 +161,11 @@ rustc_queries! {
|
||||||
|
|
||||||
/// Represents crate as a whole (as distinct from the top-level crate module).
|
/// Represents crate as a whole (as distinct from the top-level crate module).
|
||||||
///
|
///
|
||||||
/// If you call `hir_crate` (e.g., indirectly by calling `tcx.hir_crate()`),
|
/// If you call `tcx.hir_crate(())` we will have to assume that any change
|
||||||
/// we will have to assume that any change means that you need to be recompiled.
|
/// means that you need to be recompiled. This is because the `hir_crate`
|
||||||
/// This is because the `hir_crate` query gives you access to all other items.
|
/// query gives you access to all other items. To avoid this fate, do not
|
||||||
/// To avoid this fate, do not call `tcx.hir_crate()`; instead,
|
/// call `tcx.hir_crate(())`; instead, prefer wrappers like
|
||||||
/// prefer wrappers like [`TyCtxt::hir_visit_all_item_likes_in_crate`].
|
/// [`TyCtxt::hir_visit_all_item_likes_in_crate`].
|
||||||
query hir_crate(key: ()) -> &'tcx Crate<'tcx> {
|
query hir_crate(key: ()) -> &'tcx Crate<'tcx> {
|
||||||
arena_cache
|
arena_cache
|
||||||
eval_always
|
eval_always
|
||||||
|
@ -197,7 +197,7 @@ rustc_queries! {
|
||||||
|
|
||||||
/// Gives access to the HIR node's parent for the HIR owner `key`.
|
/// Gives access to the HIR node's parent for the HIR owner `key`.
|
||||||
///
|
///
|
||||||
/// This can be conveniently accessed by methods on `tcx.hir()`.
|
/// This can be conveniently accessed by `tcx.hir_*` methods.
|
||||||
/// Avoid calling this query directly.
|
/// Avoid calling this query directly.
|
||||||
query hir_owner_parent(key: hir::OwnerId) -> hir::HirId {
|
query hir_owner_parent(key: hir::OwnerId) -> hir::HirId {
|
||||||
desc { |tcx| "getting HIR parent of `{}`", tcx.def_path_str(key) }
|
desc { |tcx| "getting HIR parent of `{}`", tcx.def_path_str(key) }
|
||||||
|
@ -205,7 +205,7 @@ rustc_queries! {
|
||||||
|
|
||||||
/// Gives access to the HIR nodes and bodies inside `key` if it's a HIR owner.
|
/// Gives access to the HIR nodes and bodies inside `key` if it's a HIR owner.
|
||||||
///
|
///
|
||||||
/// This can be conveniently accessed by methods on `tcx.hir()`.
|
/// This can be conveniently accessed by `tcx.hir_*` methods.
|
||||||
/// Avoid calling this query directly.
|
/// Avoid calling this query directly.
|
||||||
query opt_hir_owner_nodes(key: LocalDefId) -> Option<&'tcx hir::OwnerNodes<'tcx>> {
|
query opt_hir_owner_nodes(key: LocalDefId) -> Option<&'tcx hir::OwnerNodes<'tcx>> {
|
||||||
desc { |tcx| "getting HIR owner items in `{}`", tcx.def_path_str(key) }
|
desc { |tcx| "getting HIR owner items in `{}`", tcx.def_path_str(key) }
|
||||||
|
@ -214,7 +214,7 @@ rustc_queries! {
|
||||||
|
|
||||||
/// Gives access to the HIR attributes inside the HIR owner `key`.
|
/// Gives access to the HIR attributes inside the HIR owner `key`.
|
||||||
///
|
///
|
||||||
/// This can be conveniently accessed by methods on `tcx.hir()`.
|
/// This can be conveniently accessed by `tcx.hir_*` methods.
|
||||||
/// Avoid calling this query directly.
|
/// Avoid calling this query directly.
|
||||||
query hir_attr_map(key: hir::OwnerId) -> &'tcx hir::AttributeMap<'tcx> {
|
query hir_attr_map(key: hir::OwnerId) -> &'tcx hir::AttributeMap<'tcx> {
|
||||||
desc { |tcx| "getting HIR owner attributes in `{}`", tcx.def_path_str(key) }
|
desc { |tcx| "getting HIR owner attributes in `{}`", tcx.def_path_str(key) }
|
||||||
|
|
|
@ -5,7 +5,7 @@ use rustc_hir::lang_items::LangItem;
|
||||||
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
|
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
|
||||||
use crate::ty::{self, Ty, TyCtxt};
|
use crate::ty::{Ty, TyCtxt};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
|
||||||
pub enum PointerCoercion {
|
pub enum PointerCoercion {
|
||||||
|
@ -133,7 +133,7 @@ impl OverloadedDeref {
|
||||||
};
|
};
|
||||||
tcx.associated_items(trait_def_id)
|
tcx.associated_items(trait_def_id)
|
||||||
.in_definition_order()
|
.in_definition_order()
|
||||||
.find(|m| m.kind == ty::AssocKind::Fn)
|
.find(|item| item.is_fn())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.def_id
|
.def_id
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,27 +18,33 @@ pub enum AssocItemContainer {
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, HashStable, Eq, Hash, Encodable, Decodable)]
|
#[derive(Copy, Clone, Debug, PartialEq, HashStable, Eq, Hash, Encodable, Decodable)]
|
||||||
pub struct AssocItem {
|
pub struct AssocItem {
|
||||||
pub def_id: DefId,
|
pub def_id: DefId,
|
||||||
pub name: Symbol,
|
|
||||||
pub kind: AssocKind,
|
pub kind: AssocKind,
|
||||||
pub container: AssocItemContainer,
|
pub container: AssocItemContainer,
|
||||||
|
|
||||||
/// If this is an item in an impl of a trait then this is the `DefId` of
|
/// If this is an item in an impl of a trait then this is the `DefId` of
|
||||||
/// the associated item on the trait that this implements.
|
/// the associated item on the trait that this implements.
|
||||||
pub trait_item_def_id: Option<DefId>,
|
pub trait_item_def_id: Option<DefId>,
|
||||||
|
|
||||||
/// Whether this is a method with an explicit self
|
|
||||||
/// as its first parameter, allowing method calls.
|
|
||||||
pub fn_has_self_parameter: bool,
|
|
||||||
|
|
||||||
/// `Some` if the associated item (an associated type) comes from the
|
|
||||||
/// return-position `impl Trait` in trait desugaring. The `ImplTraitInTraitData`
|
|
||||||
/// provides additional information about its source.
|
|
||||||
pub opt_rpitit_info: Option<ty::ImplTraitInTraitData>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AssocItem {
|
impl AssocItem {
|
||||||
|
// Gets the identifier, if it has one.
|
||||||
|
pub fn opt_name(&self) -> Option<Symbol> {
|
||||||
|
match self.kind {
|
||||||
|
ty::AssocKind::Type { data: AssocTypeData::Normal(name) } => Some(name),
|
||||||
|
ty::AssocKind::Type { data: AssocTypeData::Rpitit(_) } => None,
|
||||||
|
ty::AssocKind::Const { name } => Some(name),
|
||||||
|
ty::AssocKind::Fn { name, .. } => Some(name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets the identifier name. Aborts if it lacks one, i.e. is an RPITIT
|
||||||
|
// associated type.
|
||||||
|
pub fn name(&self) -> Symbol {
|
||||||
|
self.opt_name().expect("name of non-Rpitit assoc item")
|
||||||
|
}
|
||||||
|
|
||||||
pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident {
|
pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident {
|
||||||
Ident::new(self.name, tcx.def_ident_span(self.def_id).unwrap())
|
Ident::new(self.name(), tcx.def_ident_span(self.def_id).unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the defaultness of the associated item.
|
/// Gets the defaultness of the associated item.
|
||||||
|
@ -78,35 +84,65 @@ impl AssocItem {
|
||||||
|
|
||||||
pub fn signature(&self, tcx: TyCtxt<'_>) -> String {
|
pub fn signature(&self, tcx: TyCtxt<'_>) -> String {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
ty::AssocKind::Fn => {
|
ty::AssocKind::Fn { .. } => {
|
||||||
// We skip the binder here because the binder would deanonymize all
|
// We skip the binder here because the binder would deanonymize all
|
||||||
// late-bound regions, and we don't want method signatures to show up
|
// late-bound regions, and we don't want method signatures to show up
|
||||||
// `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound
|
// `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound
|
||||||
// regions just fine, showing `fn(&MyType)`.
|
// regions just fine, showing `fn(&MyType)`.
|
||||||
tcx.fn_sig(self.def_id).instantiate_identity().skip_binder().to_string()
|
tcx.fn_sig(self.def_id).instantiate_identity().skip_binder().to_string()
|
||||||
}
|
}
|
||||||
ty::AssocKind::Type => format!("type {};", self.name),
|
ty::AssocKind::Type { .. } => format!("type {};", self.name()),
|
||||||
ty::AssocKind::Const => {
|
ty::AssocKind::Const { name } => {
|
||||||
format!(
|
format!("const {}: {:?};", name, tcx.type_of(self.def_id).instantiate_identity())
|
||||||
"const {}: {:?};",
|
|
||||||
self.name,
|
|
||||||
tcx.type_of(self.def_id).instantiate_identity()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn descr(&self) -> &'static str {
|
pub fn descr(&self) -> &'static str {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
ty::AssocKind::Const => "associated const",
|
ty::AssocKind::Const { .. } => "associated const",
|
||||||
ty::AssocKind::Fn if self.fn_has_self_parameter => "method",
|
ty::AssocKind::Fn { has_self: true, .. } => "method",
|
||||||
ty::AssocKind::Fn => "associated function",
|
ty::AssocKind::Fn { has_self: false, .. } => "associated function",
|
||||||
ty::AssocKind::Type => "associated type",
|
ty::AssocKind::Type { .. } => "associated type",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn namespace(&self) -> Namespace {
|
||||||
|
match self.kind {
|
||||||
|
ty::AssocKind::Type { .. } => Namespace::TypeNS,
|
||||||
|
ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => Namespace::ValueNS,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_def_kind(&self) -> DefKind {
|
||||||
|
match self.kind {
|
||||||
|
AssocKind::Const { .. } => DefKind::AssocConst,
|
||||||
|
AssocKind::Fn { .. } => DefKind::AssocFn,
|
||||||
|
AssocKind::Type { .. } => DefKind::AssocTy,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn is_type(&self) -> bool {
|
||||||
|
matches!(self.kind, ty::AssocKind::Type { .. })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_fn(&self) -> bool {
|
||||||
|
matches!(self.kind, ty::AssocKind::Fn { .. })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_method(&self) -> bool {
|
||||||
|
matches!(self.kind, ty::AssocKind::Fn { has_self: true, .. })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_tag(&self) -> AssocTag {
|
||||||
|
match self.kind {
|
||||||
|
AssocKind::Const { .. } => AssocTag::Const,
|
||||||
|
AssocKind::Fn { .. } => AssocTag::Fn,
|
||||||
|
AssocKind::Type { .. } => AssocTag::Type,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_impl_trait_in_trait(&self) -> bool {
|
pub fn is_impl_trait_in_trait(&self) -> bool {
|
||||||
self.opt_rpitit_info.is_some()
|
matches!(self.kind, AssocKind::Type { data: AssocTypeData::Rpitit(_) })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if:
|
/// Returns true if:
|
||||||
|
@ -114,7 +150,7 @@ impl AssocItem {
|
||||||
/// - If it is in a trait impl, the item from the original trait has this attribute, or
|
/// - If it is in a trait impl, the item from the original trait has this attribute, or
|
||||||
/// - It is an inherent assoc const.
|
/// - It is an inherent assoc const.
|
||||||
pub fn is_type_const_capable(&self, tcx: TyCtxt<'_>) -> bool {
|
pub fn is_type_const_capable(&self, tcx: TyCtxt<'_>) -> bool {
|
||||||
if self.kind != ty::AssocKind::Const {
|
if !matches!(self.kind, ty::AssocKind::Const { .. }) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,26 +164,35 @@ impl AssocItem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash, Encodable, Decodable)]
|
||||||
|
pub enum AssocTypeData {
|
||||||
|
Normal(Symbol),
|
||||||
|
/// The associated type comes from an RPITIT. It has no name, and the
|
||||||
|
/// `ImplTraitInTraitData` provides additional information about its
|
||||||
|
/// source.
|
||||||
|
Rpitit(ty::ImplTraitInTraitData),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash, Encodable, Decodable)]
|
#[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash, Encodable, Decodable)]
|
||||||
pub enum AssocKind {
|
pub enum AssocKind {
|
||||||
Const,
|
Const { name: Symbol },
|
||||||
Fn,
|
Fn { name: Symbol, has_self: bool },
|
||||||
Type,
|
Type { data: AssocTypeData },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AssocKind {
|
impl AssocKind {
|
||||||
pub fn namespace(&self) -> Namespace {
|
pub fn namespace(&self) -> Namespace {
|
||||||
match *self {
|
match *self {
|
||||||
ty::AssocKind::Type => Namespace::TypeNS,
|
ty::AssocKind::Type { .. } => Namespace::TypeNS,
|
||||||
ty::AssocKind::Const | ty::AssocKind::Fn => Namespace::ValueNS,
|
ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => Namespace::ValueNS,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_def_kind(&self) -> DefKind {
|
pub fn as_def_kind(&self) -> DefKind {
|
||||||
match self {
|
match self {
|
||||||
AssocKind::Const => DefKind::AssocConst,
|
AssocKind::Const { .. } => DefKind::AssocConst,
|
||||||
AssocKind::Fn => DefKind::AssocFn,
|
AssocKind::Fn { .. } => DefKind::AssocFn,
|
||||||
AssocKind::Type => DefKind::AssocTy,
|
AssocKind::Type { .. } => DefKind::AssocTy,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -155,15 +200,22 @@ impl AssocKind {
|
||||||
impl std::fmt::Display for AssocKind {
|
impl std::fmt::Display for AssocKind {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
// FIXME: fails to distinguish between "associated function" and
|
AssocKind::Fn { has_self: true, .. } => write!(f, "method"),
|
||||||
// "method" because `has_self` isn't known here.
|
AssocKind::Fn { has_self: false, .. } => write!(f, "associated function"),
|
||||||
AssocKind::Fn => write!(f, "method"),
|
AssocKind::Const { .. } => write!(f, "associated const"),
|
||||||
AssocKind::Const => write!(f, "associated const"),
|
AssocKind::Type { .. } => write!(f, "associated type"),
|
||||||
AssocKind::Type => write!(f, "associated type"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Like `AssocKind`, but just the tag, no fields. Used in various kinds of matching.
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub enum AssocTag {
|
||||||
|
Const,
|
||||||
|
Fn,
|
||||||
|
Type,
|
||||||
|
}
|
||||||
|
|
||||||
/// A list of `ty::AssocItem`s in definition order that allows for efficient lookup by name.
|
/// A list of `ty::AssocItem`s in definition order that allows for efficient lookup by name.
|
||||||
///
|
///
|
||||||
/// When doing lookup by name, we try to postpone hygienic comparison for as long as possible since
|
/// When doing lookup by name, we try to postpone hygienic comparison for as long as possible since
|
||||||
|
@ -171,17 +223,17 @@ impl std::fmt::Display for AssocKind {
|
||||||
/// done only on items with the same name.
|
/// done only on items with the same name.
|
||||||
#[derive(Debug, Clone, PartialEq, HashStable)]
|
#[derive(Debug, Clone, PartialEq, HashStable)]
|
||||||
pub struct AssocItems {
|
pub struct AssocItems {
|
||||||
items: SortedIndexMultiMap<u32, Symbol, ty::AssocItem>,
|
items: SortedIndexMultiMap<u32, Option<Symbol>, ty::AssocItem>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AssocItems {
|
impl AssocItems {
|
||||||
/// Constructs an `AssociatedItems` map from a series of `ty::AssocItem`s in definition order.
|
/// Constructs an `AssociatedItems` map from a series of `ty::AssocItem`s in definition order.
|
||||||
pub fn new(items_in_def_order: impl IntoIterator<Item = ty::AssocItem>) -> Self {
|
pub fn new(items_in_def_order: impl IntoIterator<Item = ty::AssocItem>) -> Self {
|
||||||
let items = items_in_def_order.into_iter().map(|item| (item.name, item)).collect();
|
let items = items_in_def_order.into_iter().map(|item| (item.opt_name(), item)).collect();
|
||||||
AssocItems { items }
|
AssocItems { items }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a slice of associated items in the order they were defined.
|
/// Returns an iterator over associated items in the order they were defined.
|
||||||
///
|
///
|
||||||
/// New code should avoid relying on definition order. If you need a particular associated item
|
/// New code should avoid relying on definition order. If you need a particular associated item
|
||||||
/// for a known trait, make that trait a lang item instead of indexing this array.
|
/// for a known trait, make that trait a lang item instead of indexing this array.
|
||||||
|
@ -198,7 +250,8 @@ impl AssocItems {
|
||||||
&self,
|
&self,
|
||||||
name: Symbol,
|
name: Symbol,
|
||||||
) -> impl '_ + Iterator<Item = &ty::AssocItem> {
|
) -> impl '_ + Iterator<Item = &ty::AssocItem> {
|
||||||
self.items.get_by_key(name)
|
assert!(!name.is_empty());
|
||||||
|
self.items.get_by_key(Some(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the associated item with the given identifier and `AssocKind`, if one exists.
|
/// Returns the associated item with the given identifier and `AssocKind`, if one exists.
|
||||||
|
@ -207,27 +260,14 @@ impl AssocItems {
|
||||||
&self,
|
&self,
|
||||||
tcx: TyCtxt<'_>,
|
tcx: TyCtxt<'_>,
|
||||||
ident: Ident,
|
ident: Ident,
|
||||||
kind: AssocKind,
|
assoc_tag: AssocTag,
|
||||||
parent_def_id: DefId,
|
parent_def_id: DefId,
|
||||||
) -> Option<&ty::AssocItem> {
|
) -> Option<&ty::AssocItem> {
|
||||||
self.filter_by_name_unhygienic(ident.name)
|
self.filter_by_name_unhygienic(ident.name)
|
||||||
.filter(|item| item.kind == kind)
|
.filter(|item| item.as_tag() == assoc_tag)
|
||||||
.find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id))
|
.find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the associated item with the given identifier and any of `AssocKind`, if one
|
|
||||||
/// exists. The identifier is matched hygienically.
|
|
||||||
pub fn find_by_ident_and_kinds(
|
|
||||||
&self,
|
|
||||||
tcx: TyCtxt<'_>,
|
|
||||||
ident: Ident,
|
|
||||||
// Sorted in order of what kinds to look at
|
|
||||||
kinds: &[AssocKind],
|
|
||||||
parent_def_id: DefId,
|
|
||||||
) -> Option<&ty::AssocItem> {
|
|
||||||
kinds.iter().find_map(|kind| self.find_by_ident_and_kind(tcx, ident, *kind, parent_def_id))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the associated item with the given identifier in the given `Namespace`, if one
|
/// Returns the associated item with the given identifier in the given `Namespace`, if one
|
||||||
/// exists. The identifier is matched hygienically.
|
/// exists. The identifier is matched hygienically.
|
||||||
pub fn find_by_ident_and_namespace(
|
pub fn find_by_ident_and_namespace(
|
||||||
|
@ -238,7 +278,7 @@ impl AssocItems {
|
||||||
parent_def_id: DefId,
|
parent_def_id: DefId,
|
||||||
) -> Option<&ty::AssocItem> {
|
) -> Option<&ty::AssocItem> {
|
||||||
self.filter_by_name_unhygienic(ident.name)
|
self.filter_by_name_unhygienic(ident.name)
|
||||||
.filter(|item| item.kind.namespace() == ns)
|
.filter(|item| item.namespace() == ns)
|
||||||
.find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id))
|
.find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -464,7 +464,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
||||||
fn associated_type_def_ids(self, def_id: DefId) -> impl IntoIterator<Item = DefId> {
|
fn associated_type_def_ids(self, def_id: DefId) -> impl IntoIterator<Item = DefId> {
|
||||||
self.associated_items(def_id)
|
self.associated_items(def_id)
|
||||||
.in_definition_order()
|
.in_definition_order()
|
||||||
.filter(|assoc_item| matches!(assoc_item.kind, ty::AssocKind::Type))
|
.filter(|assoc_item| assoc_item.is_type())
|
||||||
.map(|assoc_item| assoc_item.def_id)
|
.map(|assoc_item| assoc_item.def_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2147,7 +2147,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
return vec![];
|
return vec![];
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut v = TraitObjectVisitor(vec![], self.hir());
|
let mut v = TraitObjectVisitor(vec![]);
|
||||||
v.visit_ty_unambig(hir_output);
|
v.visit_ty_unambig(hir_output);
|
||||||
v.0
|
v.0
|
||||||
}
|
}
|
||||||
|
@ -2160,7 +2160,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
scope_def_id: LocalDefId,
|
scope_def_id: LocalDefId,
|
||||||
) -> Option<(Vec<&'tcx hir::Ty<'tcx>>, Span, Option<Span>)> {
|
) -> Option<(Vec<&'tcx hir::Ty<'tcx>>, Span, Option<Span>)> {
|
||||||
let hir_id = self.local_def_id_to_hir_id(scope_def_id);
|
let hir_id = self.local_def_id_to_hir_id(scope_def_id);
|
||||||
let mut v = TraitObjectVisitor(vec![], self.hir());
|
let mut v = TraitObjectVisitor(vec![]);
|
||||||
// when the return type is a type alias
|
// when the return type is a type alias
|
||||||
if let Some(hir::FnDecl { output: hir::FnRetTy::Return(hir_output), .. }) = self.hir_fn_decl_by_hir_id(hir_id)
|
if let Some(hir::FnDecl { output: hir::FnRetTy::Return(hir_output), .. }) = self.hir_fn_decl_by_hir_id(hir_id)
|
||||||
&& let hir::TyKind::Path(hir::QPath::Resolved(
|
&& let hir::TyKind::Path(hir::QPath::Resolved(
|
||||||
|
|
|
@ -571,7 +571,7 @@ pub fn suggest_constraining_type_params<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Collect al types that have an implicit `'static` obligation that we could suggest `'_` for.
|
/// Collect al types that have an implicit `'static` obligation that we could suggest `'_` for.
|
||||||
pub struct TraitObjectVisitor<'tcx>(pub Vec<&'tcx hir::Ty<'tcx>>, pub crate::hir::map::Map<'tcx>);
|
pub(crate) struct TraitObjectVisitor<'tcx>(pub(crate) Vec<&'tcx hir::Ty<'tcx>>);
|
||||||
|
|
||||||
impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> {
|
impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> {
|
||||||
fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) {
|
fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) {
|
||||||
|
@ -592,18 +592,6 @@ impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Collect al types that have an implicit `'static` obligation that we could suggest `'_` for.
|
|
||||||
pub struct StaticLifetimeVisitor<'tcx>(pub Vec<Span>, pub crate::hir::map::Map<'tcx>);
|
|
||||||
|
|
||||||
impl<'v> hir::intravisit::Visitor<'v> for StaticLifetimeVisitor<'v> {
|
|
||||||
fn visit_lifetime(&mut self, lt: &'v hir::Lifetime) {
|
|
||||||
if let hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static = lt.res
|
|
||||||
{
|
|
||||||
self.0.push(lt.ident.span);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct IsSuggestableVisitor<'tcx> {
|
pub struct IsSuggestableVisitor<'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
infer_suggestable: bool,
|
infer_suggestable: bool,
|
||||||
|
|
|
@ -746,7 +746,7 @@ impl<'tcx> Instance<'tcx> {
|
||||||
let call_once = tcx
|
let call_once = tcx
|
||||||
.associated_items(fn_once)
|
.associated_items(fn_once)
|
||||||
.in_definition_order()
|
.in_definition_order()
|
||||||
.find(|it| it.kind == ty::AssocKind::Fn)
|
.find(|it| it.is_fn())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.def_id;
|
.def_id;
|
||||||
let track_caller =
|
let track_caller =
|
||||||
|
|
|
@ -1462,7 +1462,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
pub fn provided_trait_methods(self, id: DefId) -> impl 'tcx + Iterator<Item = &'tcx AssocItem> {
|
pub fn provided_trait_methods(self, id: DefId) -> impl 'tcx + Iterator<Item = &'tcx AssocItem> {
|
||||||
self.associated_items(id)
|
self.associated_items(id)
|
||||||
.in_definition_order()
|
.in_definition_order()
|
||||||
.filter(move |item| item.kind == AssocKind::Fn && item.defaultness(self).has_value())
|
.filter(move |item| item.is_fn() && item.defaultness(self).has_value())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn repr_options_of_def(self, did: LocalDefId) -> ReprOptions {
|
pub fn repr_options_of_def(self, did: LocalDefId) -> ReprOptions {
|
||||||
|
@ -1608,8 +1608,11 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
/// return-position `impl Trait` from a trait, then provide the source info
|
/// return-position `impl Trait` from a trait, then provide the source info
|
||||||
/// about where that RPITIT came from.
|
/// about where that RPITIT came from.
|
||||||
pub fn opt_rpitit_info(self, def_id: DefId) -> Option<ImplTraitInTraitData> {
|
pub fn opt_rpitit_info(self, def_id: DefId) -> Option<ImplTraitInTraitData> {
|
||||||
if let DefKind::AssocTy = self.def_kind(def_id) {
|
if let DefKind::AssocTy = self.def_kind(def_id)
|
||||||
self.associated_item(def_id).opt_rpitit_info
|
&& let AssocKind::Type { data: AssocTypeData::Rpitit(rpitit_info) } =
|
||||||
|
self.associated_item(def_id).kind
|
||||||
|
{
|
||||||
|
Some(rpitit_info)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
|
@ -1214,7 +1214,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
|
||||||
&& assoc
|
&& assoc
|
||||||
.trait_container(tcx)
|
.trait_container(tcx)
|
||||||
.is_some_and(|def_id| tcx.is_lang_item(def_id, LangItem::Coroutine))
|
.is_some_and(|def_id| tcx.is_lang_item(def_id, LangItem::Coroutine))
|
||||||
&& assoc.name == rustc_span::sym::Return
|
&& assoc.opt_name() == Some(rustc_span::sym::Return)
|
||||||
{
|
{
|
||||||
if let ty::Coroutine(_, args) = args.type_at(0).kind() {
|
if let ty::Coroutine(_, args) = args.type_at(0).kind() {
|
||||||
let return_ty = args.as_coroutine().return_ty();
|
let return_ty = args.as_coroutine().return_ty();
|
||||||
|
@ -1237,7 +1237,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
|
||||||
p!(", ");
|
p!(", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
p!(write("{} = ", tcx.associated_item(assoc_item_def_id).name));
|
p!(write("{} = ", tcx.associated_item(assoc_item_def_id).name()));
|
||||||
|
|
||||||
match term.unpack() {
|
match term.unpack() {
|
||||||
TermKind::Ty(ty) => p!(print(ty)),
|
TermKind::Ty(ty) => p!(print(ty)),
|
||||||
|
@ -3291,7 +3291,7 @@ define_print! {
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::ExistentialProjection<'tcx> {
|
ty::ExistentialProjection<'tcx> {
|
||||||
let name = cx.tcx().associated_item(self.def_id).name;
|
let name = cx.tcx().associated_item(self.def_id).name();
|
||||||
// The args don't contain the self ty (as it has been erased) but the corresp.
|
// The args don't contain the self ty (as it has been erased) but the corresp.
|
||||||
// generics do as the trait always has a self ty param. We need to offset.
|
// generics do as the trait always has a self ty param. We need to offset.
|
||||||
let args = &self.args[cx.tcx().generics_of(self.def_id).parent_count - 1..];
|
let args = &self.args[cx.tcx().generics_of(self.def_id).parent_count - 1..];
|
||||||
|
|
|
@ -735,7 +735,7 @@ impl<'tcx> Ty<'tcx> {
|
||||||
.map(|principal| {
|
.map(|principal| {
|
||||||
tcx.associated_items(principal.def_id())
|
tcx.associated_items(principal.def_id())
|
||||||
.in_definition_order()
|
.in_definition_order()
|
||||||
.filter(|item| item.kind == ty::AssocKind::Type)
|
.filter(|item| item.is_type())
|
||||||
.filter(|item| !item.is_impl_trait_in_trait())
|
.filter(|item| !item.is_impl_trait_in_trait())
|
||||||
.filter(|item| !tcx.generics_require_sized_self(item.def_id))
|
.filter(|item| !tcx.generics_require_sized_self(item.def_id))
|
||||||
.count()
|
.count()
|
||||||
|
|
|
@ -819,7 +819,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
/// Get an English description for the item's kind.
|
/// Get an English description for the item's kind.
|
||||||
pub fn def_kind_descr(self, def_kind: DefKind, def_id: DefId) -> &'static str {
|
pub fn def_kind_descr(self, def_kind: DefKind, def_id: DefId) -> &'static str {
|
||||||
match def_kind {
|
match def_kind {
|
||||||
DefKind::AssocFn if self.associated_item(def_id).fn_has_self_parameter => "method",
|
DefKind::AssocFn if self.associated_item(def_id).is_method() => "method",
|
||||||
DefKind::Closure if let Some(coroutine_kind) = self.coroutine_kind(def_id) => {
|
DefKind::Closure if let Some(coroutine_kind) = self.coroutine_kind(def_id) => {
|
||||||
match coroutine_kind {
|
match coroutine_kind {
|
||||||
hir::CoroutineKind::Desugared(
|
hir::CoroutineKind::Desugared(
|
||||||
|
@ -873,7 +873,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
/// Gets an English article for the [`TyCtxt::def_kind_descr`].
|
/// Gets an English article for the [`TyCtxt::def_kind_descr`].
|
||||||
pub fn def_kind_descr_article(self, def_kind: DefKind, def_id: DefId) -> &'static str {
|
pub fn def_kind_descr_article(self, def_kind: DefKind, def_id: DefId) -> &'static str {
|
||||||
match def_kind {
|
match def_kind {
|
||||||
DefKind::AssocFn if self.associated_item(def_id).fn_has_self_parameter => "a",
|
DefKind::AssocFn if self.associated_item(def_id).is_method() => "a",
|
||||||
DefKind::Closure if let Some(coroutine_kind) = self.coroutine_kind(def_id) => {
|
DefKind::Closure if let Some(coroutine_kind) = self.coroutine_kind(def_id) => {
|
||||||
match coroutine_kind {
|
match coroutine_kind {
|
||||||
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, ..) => "an",
|
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, ..) => "an",
|
||||||
|
|
|
@ -140,8 +140,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
let success_block = target_block(TestBranch::Success);
|
let success_block = target_block(TestBranch::Success);
|
||||||
let fail_block = target_block(TestBranch::Failure);
|
let fail_block = target_block(TestBranch::Failure);
|
||||||
|
|
||||||
let expect_ty = value.ty();
|
let mut expect_ty = value.ty();
|
||||||
let expect = self.literal_operand(test.span, value);
|
let mut expect = self.literal_operand(test.span, value);
|
||||||
|
|
||||||
let mut place = place;
|
let mut place = place;
|
||||||
let mut block = block;
|
let mut block = block;
|
||||||
|
@ -174,6 +174,31 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
place = ref_str;
|
place = ref_str;
|
||||||
ty = ref_str_ty;
|
ty = ref_str_ty;
|
||||||
}
|
}
|
||||||
|
&ty::Pat(base, _) => {
|
||||||
|
assert_eq!(ty, value.ty());
|
||||||
|
assert!(base.is_trivially_pure_clone_copy());
|
||||||
|
|
||||||
|
let transmuted_place = self.temp(base, test.span);
|
||||||
|
self.cfg.push_assign(
|
||||||
|
block,
|
||||||
|
self.source_info(scrutinee_span),
|
||||||
|
transmuted_place,
|
||||||
|
Rvalue::Cast(CastKind::Transmute, Operand::Copy(place), base),
|
||||||
|
);
|
||||||
|
|
||||||
|
let transmuted_expect = self.temp(base, test.span);
|
||||||
|
self.cfg.push_assign(
|
||||||
|
block,
|
||||||
|
self.source_info(test.span),
|
||||||
|
transmuted_expect,
|
||||||
|
Rvalue::Cast(CastKind::Transmute, expect, base),
|
||||||
|
);
|
||||||
|
|
||||||
|
place = transmuted_place;
|
||||||
|
expect = Operand::Copy(transmuted_expect);
|
||||||
|
ty = base;
|
||||||
|
expect_ty = base;
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -715,7 +740,7 @@ fn trait_method<'tcx>(
|
||||||
let item = tcx
|
let item = tcx
|
||||||
.associated_items(trait_def_id)
|
.associated_items(trait_def_id)
|
||||||
.filter_by_name_unhygienic(method_name)
|
.filter_by_name_unhygienic(method_name)
|
||||||
.find(|item| item.kind == ty::AssocKind::Fn)
|
.find(|item| item.is_fn())
|
||||||
.expect("trait method not found");
|
.expect("trait method not found");
|
||||||
|
|
||||||
let method_ty = Ty::new_fn_def(tcx, item.def_id, args);
|
let method_ty = Ty::new_fn_def(tcx, item.def_id, args);
|
||||||
|
|
|
@ -42,7 +42,7 @@ impl<'a, 'tcx> UndefinedTransmutesChecker<'a, 'tcx> {
|
||||||
if self.tcx.is_const_fn(def_id)
|
if self.tcx.is_const_fn(def_id)
|
||||||
|| matches!(
|
|| matches!(
|
||||||
self.tcx.opt_associated_item(def_id),
|
self.tcx.opt_associated_item(def_id),
|
||||||
Some(AssocItem { kind: AssocKind::Const, .. })
|
Some(AssocItem { kind: AssocKind::Const { .. }, .. })
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
let fn_sig = function.ty(self.body, self.tcx).fn_sig(self.tcx).skip_binder();
|
let fn_sig = function.ty(self.body, self.tcx).fn_sig(self.tcx).skip_binder();
|
||||||
|
|
|
@ -66,7 +66,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body<
|
||||||
let call_mut = tcx
|
let call_mut = tcx
|
||||||
.associated_items(fn_mut)
|
.associated_items(fn_mut)
|
||||||
.in_definition_order()
|
.in_definition_order()
|
||||||
.find(|it| it.kind == ty::AssocKind::Fn)
|
.find(|it| it.is_fn())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.def_id;
|
.def_id;
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ use rustc_data_structures::fx::FxIndexSet;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_middle::mir::visit::Visitor as MirVisitor;
|
use rustc_middle::mir::visit::Visitor as MirVisitor;
|
||||||
use rustc_middle::mir::{self, Location, traversal};
|
use rustc_middle::mir::{self, Location, traversal};
|
||||||
use rustc_middle::ty::{self, AssocKind, Instance, Ty, TyCtxt, TypeFoldable};
|
use rustc_middle::ty::{self, AssocTag, Instance, Ty, TyCtxt, TypeFoldable};
|
||||||
use rustc_session::Limit;
|
use rustc_session::Limit;
|
||||||
use rustc_session::lint::builtin::LARGE_ASSIGNMENTS;
|
use rustc_session::lint::builtin::LARGE_ASSIGNMENTS;
|
||||||
use rustc_span::source_map::Spanned;
|
use rustc_span::source_map::Spanned;
|
||||||
|
@ -194,7 +194,7 @@ fn assoc_fn_of_type<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, fn_ident: Ident) ->
|
||||||
if let Some(new) = tcx.associated_items(impl_def_id).find_by_ident_and_kind(
|
if let Some(new) = tcx.associated_items(impl_def_id).find_by_ident_and_kind(
|
||||||
tcx,
|
tcx,
|
||||||
fn_ident,
|
fn_ident,
|
||||||
AssocKind::Fn,
|
AssocTag::Fn,
|
||||||
def_id,
|
def_id,
|
||||||
) {
|
) {
|
||||||
return Some(new.def_id);
|
return Some(new.def_id);
|
||||||
|
|
|
@ -792,37 +792,46 @@ where
|
||||||
};
|
};
|
||||||
|
|
||||||
match proven_via {
|
match proven_via {
|
||||||
|
TraitGoalProvenVia::ParamEnv | TraitGoalProvenVia::AliasBound => {
|
||||||
|
let mut considered_candidates = Vec::new();
|
||||||
|
considered_candidates.extend(
|
||||||
|
candidates
|
||||||
|
.iter()
|
||||||
|
.filter(|c| matches!(c.source, CandidateSource::ParamEnv(_)))
|
||||||
|
.map(|c| c.result),
|
||||||
|
);
|
||||||
|
|
||||||
// Even when a trait bound has been proven using a where-bound, we
|
// Even when a trait bound has been proven using a where-bound, we
|
||||||
// still need to consider alias-bounds for normalization, see
|
// still need to consider alias-bounds for normalization, see
|
||||||
// tests/ui/next-solver/alias-bound-shadowed-by-env.rs.
|
// tests/ui/next-solver/alias-bound-shadowed-by-env.rs.
|
||||||
//
|
//
|
||||||
|
// We still need to prefer where-bounds over alias-bounds however.
|
||||||
|
// See tests/ui/winnowing/norm-where-bound-gt-alias-bound.rs.
|
||||||
|
//
|
||||||
// FIXME(const_trait_impl): should this behavior also be used by
|
// FIXME(const_trait_impl): should this behavior also be used by
|
||||||
// constness checking. Doing so is *at least theoretically* breaking,
|
// constness checking. Doing so is *at least theoretically* breaking,
|
||||||
// see github.com/rust-lang/rust/issues/133044#issuecomment-2500709754
|
// see github.com/rust-lang/rust/issues/133044#issuecomment-2500709754
|
||||||
TraitGoalProvenVia::ParamEnv | TraitGoalProvenVia::AliasBound => {
|
if considered_candidates.is_empty() {
|
||||||
let mut candidates_from_env_and_bounds: Vec<_> = candidates
|
considered_candidates.extend(
|
||||||
|
candidates
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|c| {
|
.filter(|c| matches!(c.source, CandidateSource::AliasBound))
|
||||||
matches!(
|
.map(|c| c.result),
|
||||||
c.source,
|
);
|
||||||
CandidateSource::AliasBound | CandidateSource::ParamEnv(_)
|
}
|
||||||
)
|
|
||||||
})
|
|
||||||
.map(|c| c.result)
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
// If the trait goal has been proven by using the environment, we want to treat
|
// If the trait goal has been proven by using the environment, we want to treat
|
||||||
// aliases as rigid if there are no applicable projection bounds in the environment.
|
// aliases as rigid if there are no applicable projection bounds in the environment.
|
||||||
if candidates_from_env_and_bounds.is_empty() {
|
if considered_candidates.is_empty() {
|
||||||
if let Ok(response) = inject_normalize_to_rigid_candidate(self) {
|
if let Ok(response) = inject_normalize_to_rigid_candidate(self) {
|
||||||
candidates_from_env_and_bounds.push(response);
|
considered_candidates.push(response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(response) = self.try_merge_responses(&candidates_from_env_and_bounds) {
|
if let Some(response) = self.try_merge_responses(&considered_candidates) {
|
||||||
Ok(response)
|
Ok(response)
|
||||||
} else {
|
} else {
|
||||||
self.flounder(&candidates_from_env_and_bounds)
|
self.flounder(&considered_candidates)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TraitGoalProvenVia::Misc => {
|
TraitGoalProvenVia::Misc => {
|
||||||
|
|
|
@ -164,6 +164,7 @@ where
|
||||||
ecx: &mut EvalCtxt<'_, D>,
|
ecx: &mut EvalCtxt<'_, D>,
|
||||||
goal: Goal<I, Self>,
|
goal: Goal<I, Self>,
|
||||||
) -> Result<Candidate<I>, NoSolution> {
|
) -> Result<Candidate<I>, NoSolution> {
|
||||||
|
let cx = ecx.cx();
|
||||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
}
|
}
|
||||||
|
@ -174,20 +175,37 @@ where
|
||||||
|
|
||||||
// Only consider auto impls of unsafe traits when there are no unsafe
|
// Only consider auto impls of unsafe traits when there are no unsafe
|
||||||
// fields.
|
// fields.
|
||||||
if ecx.cx().trait_is_unsafe(goal.predicate.def_id())
|
if cx.trait_is_unsafe(goal.predicate.def_id())
|
||||||
&& goal.predicate.self_ty().has_unsafe_fields()
|
&& goal.predicate.self_ty().has_unsafe_fields()
|
||||||
{
|
{
|
||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We only look into opaque types during analysis for opaque types
|
// We leak the implemented auto traits of opaques outside of their defining scope.
|
||||||
// outside of their defining scope. Doing so for opaques in the
|
// This depends on `typeck` of the defining scope of that opaque, which may result in
|
||||||
// defining scope may require calling `typeck` on the same item we're
|
// fatal query cycles.
|
||||||
// currently type checking, which will result in a fatal cycle that
|
//
|
||||||
// ideally we want to avoid, since we can make progress on this goal
|
// We only get to this point if we're outside of the defining scope as we'd otherwise
|
||||||
// via an alias bound or a locally-inferred hidden type instead.
|
// be able to normalize the opaque type. We may also cycle in case `typeck` of a defining
|
||||||
|
// scope relies on the current context, e.g. either because it also leaks auto trait
|
||||||
|
// bounds of opaques defined in the current context or by evaluating the current item.
|
||||||
|
//
|
||||||
|
// To avoid this we don't try to leak auto trait bounds if they can also be proven via
|
||||||
|
// item bounds of the opaque. These bounds are always applicable as auto traits must not
|
||||||
|
// have any generic parameters. They would also get preferred over the impl candidate
|
||||||
|
// when merging candidates anyways.
|
||||||
|
//
|
||||||
|
// See tests/ui/impl-trait/auto-trait-leakage/avoid-query-cycle-via-item-bound.rs.
|
||||||
if let ty::Alias(ty::Opaque, opaque_ty) = goal.predicate.self_ty().kind() {
|
if let ty::Alias(ty::Opaque, opaque_ty) = goal.predicate.self_ty().kind() {
|
||||||
debug_assert!(ecx.opaque_type_is_rigid(opaque_ty.def_id));
|
debug_assert!(ecx.opaque_type_is_rigid(opaque_ty.def_id));
|
||||||
|
for item_bound in cx.item_self_bounds(opaque_ty.def_id).skip_binder() {
|
||||||
|
if item_bound
|
||||||
|
.as_trait_clause()
|
||||||
|
.is_some_and(|b| b.def_id() == goal.predicate.def_id())
|
||||||
|
{
|
||||||
|
return Err(NoSolution);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ecx.probe_and_evaluate_goal_for_constituent_tys(
|
ecx.probe_and_evaluate_goal_for_constituent_tys(
|
||||||
|
@ -1238,10 +1256,11 @@ where
|
||||||
D: SolverDelegate<Interner = I>,
|
D: SolverDelegate<Interner = I>,
|
||||||
I: Interner,
|
I: Interner,
|
||||||
{
|
{
|
||||||
|
#[instrument(level = "debug", skip(self, goal), ret)]
|
||||||
pub(super) fn merge_trait_candidates(
|
pub(super) fn merge_trait_candidates(
|
||||||
&mut self,
|
&mut self,
|
||||||
goal: Goal<I, TraitPredicate<I>>,
|
goal: Goal<I, TraitPredicate<I>>,
|
||||||
candidates: Vec<Candidate<I>>,
|
mut candidates: Vec<Candidate<I>>,
|
||||||
) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> {
|
) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> {
|
||||||
if let TypingMode::Coherence = self.typing_mode() {
|
if let TypingMode::Coherence = self.typing_mode() {
|
||||||
let all_candidates: Vec<_> = candidates.into_iter().map(|c| c.result).collect();
|
let all_candidates: Vec<_> = candidates.into_iter().map(|c| c.result).collect();
|
||||||
|
@ -1323,13 +1342,16 @@ where
|
||||||
|
|
||||||
// If there are *only* global where bounds, then make sure to return that this
|
// If there are *only* global where bounds, then make sure to return that this
|
||||||
// is still reported as being proven-via the param-env so that rigid projections
|
// is still reported as being proven-via the param-env so that rigid projections
|
||||||
// operate correctly.
|
// operate correctly. Otherwise, drop all global where-bounds before merging the
|
||||||
|
// remaining candidates.
|
||||||
let proven_via =
|
let proven_via =
|
||||||
if candidates.iter().all(|c| matches!(c.source, CandidateSource::ParamEnv(_))) {
|
if candidates.iter().all(|c| matches!(c.source, CandidateSource::ParamEnv(_))) {
|
||||||
TraitGoalProvenVia::ParamEnv
|
TraitGoalProvenVia::ParamEnv
|
||||||
} else {
|
} else {
|
||||||
|
candidates.retain(|c| !matches!(c.source, CandidateSource::ParamEnv(_)));
|
||||||
TraitGoalProvenVia::Misc
|
TraitGoalProvenVia::Misc
|
||||||
};
|
};
|
||||||
|
|
||||||
let all_candidates: Vec<_> = candidates.into_iter().map(|c| c.result).collect();
|
let all_candidates: Vec<_> = candidates.into_iter().map(|c| c.result).collect();
|
||||||
if let Some(response) = self.try_merge_responses(&all_candidates) {
|
if let Some(response) = self.try_merge_responses(&all_candidates) {
|
||||||
Ok((response, Some(proven_via)))
|
Ok((response, Some(proven_via)))
|
||||||
|
|
|
@ -1994,7 +1994,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|i| self.r.tcx.associated_items(i).in_definition_order())
|
.flat_map(|i| self.r.tcx.associated_items(i).in_definition_order())
|
||||||
// Only assoc fn with no receivers.
|
// Only assoc fn with no receivers.
|
||||||
.filter(|item| matches!(item.kind, ty::AssocKind::Fn) && !item.fn_has_self_parameter)
|
.filter(|item| item.is_fn() && !item.is_method())
|
||||||
.filter_map(|item| {
|
.filter_map(|item| {
|
||||||
// Only assoc fns that return `Self`
|
// Only assoc fns that return `Self`
|
||||||
let fn_sig = self.r.tcx.fn_sig(item.def_id).skip_binder();
|
let fn_sig = self.r.tcx.fn_sig(item.def_id).skip_binder();
|
||||||
|
@ -2007,8 +2007,9 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
||||||
if def.did() != def_id {
|
if def.did() != def_id {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let order = !item.name.as_str().starts_with("new");
|
let name = item.name();
|
||||||
Some((order, item.name, input_len))
|
let order = !name.as_str().starts_with("new");
|
||||||
|
Some((order, name, input_len))
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
items.sort_by_key(|(order, _, _)| *order);
|
items.sort_by_key(|(order, _, _)| *order);
|
||||||
|
|
|
@ -240,7 +240,7 @@ fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tc
|
||||||
.flat_map(|super_poly_trait_ref| {
|
.flat_map(|super_poly_trait_ref| {
|
||||||
tcx.associated_items(super_poly_trait_ref.def_id())
|
tcx.associated_items(super_poly_trait_ref.def_id())
|
||||||
.in_definition_order()
|
.in_definition_order()
|
||||||
.filter(|item| item.kind == ty::AssocKind::Type)
|
.filter(|item| item.is_type())
|
||||||
.filter(|item| !tcx.generics_require_sized_self(item.def_id))
|
.filter(|item| !tcx.generics_require_sized_self(item.def_id))
|
||||||
.map(move |assoc_ty| {
|
.map(move |assoc_ty| {
|
||||||
super_poly_trait_ref.map_bound(|super_trait_ref| {
|
super_poly_trait_ref.map_bound(|super_trait_ref| {
|
||||||
|
@ -446,7 +446,7 @@ pub(crate) fn transform_instance<'tcx>(
|
||||||
let call = tcx
|
let call = tcx
|
||||||
.associated_items(trait_id)
|
.associated_items(trait_id)
|
||||||
.in_definition_order()
|
.in_definition_order()
|
||||||
.find(|it| it.kind == ty::AssocKind::Fn)
|
.find(|it| it.is_fn())
|
||||||
.expect("No call-family function on closure-like Fn trait?")
|
.expect("No call-family function on closure-like Fn trait?")
|
||||||
.def_id;
|
.def_id;
|
||||||
|
|
||||||
|
|
|
@ -894,12 +894,21 @@ impl<'tcx> Stable<'tcx> for rustc_session::cstore::ForeignModule {
|
||||||
impl<'tcx> Stable<'tcx> for ty::AssocKind {
|
impl<'tcx> Stable<'tcx> for ty::AssocKind {
|
||||||
type T = stable_mir::ty::AssocKind;
|
type T = stable_mir::ty::AssocKind;
|
||||||
|
|
||||||
fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
|
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
|
||||||
use stable_mir::ty::AssocKind;
|
use stable_mir::ty::{AssocKind, AssocTypeData};
|
||||||
match self {
|
match *self {
|
||||||
ty::AssocKind::Const => AssocKind::Const,
|
ty::AssocKind::Const { name } => AssocKind::Const { name: name.to_string() },
|
||||||
ty::AssocKind::Fn => AssocKind::Fn,
|
ty::AssocKind::Fn { name, has_self } => {
|
||||||
ty::AssocKind::Type => AssocKind::Type,
|
AssocKind::Fn { name: name.to_string(), has_self }
|
||||||
|
}
|
||||||
|
ty::AssocKind::Type { data } => AssocKind::Type {
|
||||||
|
data: match data {
|
||||||
|
ty::AssocTypeData::Normal(name) => AssocTypeData::Normal(name.to_string()),
|
||||||
|
ty::AssocTypeData::Rpitit(rpitit) => {
|
||||||
|
AssocTypeData::Rpitit(rpitit.stable(tables))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -922,12 +931,9 @@ impl<'tcx> Stable<'tcx> for ty::AssocItem {
|
||||||
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
|
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
|
||||||
stable_mir::ty::AssocItem {
|
stable_mir::ty::AssocItem {
|
||||||
def_id: tables.assoc_def(self.def_id),
|
def_id: tables.assoc_def(self.def_id),
|
||||||
name: self.name.to_string(),
|
|
||||||
kind: self.kind.stable(tables),
|
kind: self.kind.stable(tables),
|
||||||
container: self.container.stable(tables),
|
container: self.container.stable(tables),
|
||||||
trait_item_def_id: self.trait_item_def_id.map(|did| tables.assoc_def(did)),
|
trait_item_def_id: self.trait_item_def_id.map(|did| tables.assoc_def(did)),
|
||||||
fn_has_self_parameter: self.fn_has_self_parameter,
|
|
||||||
opt_rpitit_info: self.opt_rpitit_info.map(|rpitit| rpitit.stable(tables)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,9 +22,10 @@ impl Display for Ty {
|
||||||
impl Display for AssocKind {
|
impl Display for AssocKind {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
AssocKind::Fn => write!(f, "method"),
|
AssocKind::Fn { has_self: true, .. } => write!(f, "method"),
|
||||||
AssocKind::Const => write!(f, "associated const"),
|
AssocKind::Fn { has_self: false, .. } => write!(f, "associated function"),
|
||||||
AssocKind::Type => write!(f, "associated type"),
|
AssocKind::Const { .. } => write!(f, "associated const"),
|
||||||
|
AssocKind::Type { .. } => write!(f, "associated type"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1578,29 +1578,28 @@ crate_def! {
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
||||||
pub struct AssocItem {
|
pub struct AssocItem {
|
||||||
pub def_id: AssocDef,
|
pub def_id: AssocDef,
|
||||||
pub name: Symbol,
|
|
||||||
pub kind: AssocKind,
|
pub kind: AssocKind,
|
||||||
pub container: AssocItemContainer,
|
pub container: AssocItemContainer,
|
||||||
|
|
||||||
/// If this is an item in an impl of a trait then this is the `DefId` of
|
/// If this is an item in an impl of a trait then this is the `DefId` of
|
||||||
/// the associated item on the trait that this implements.
|
/// the associated item on the trait that this implements.
|
||||||
pub trait_item_def_id: Option<AssocDef>,
|
pub trait_item_def_id: Option<AssocDef>,
|
||||||
|
}
|
||||||
|
|
||||||
/// Whether this is a method with an explicit self
|
#[derive(Clone, PartialEq, Debug, Eq, Serialize)]
|
||||||
/// as its first parameter, allowing method calls.
|
pub enum AssocTypeData {
|
||||||
pub fn_has_self_parameter: bool,
|
Normal(Symbol),
|
||||||
|
/// The associated type comes from an RPITIT. It has no name, and the
|
||||||
/// `Some` if the associated item (an associated type) comes from the
|
/// `ImplTraitInTraitData` provides additional information about its
|
||||||
/// return-position `impl Trait` in trait desugaring. The `ImplTraitInTraitData`
|
/// source.
|
||||||
/// provides additional information about its source.
|
Rpitit(ImplTraitInTraitData),
|
||||||
pub opt_rpitit_info: Option<ImplTraitInTraitData>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
||||||
pub enum AssocKind {
|
pub enum AssocKind {
|
||||||
Const,
|
Const { name: Symbol },
|
||||||
Fn,
|
Fn { name: Symbol, has_self: bool },
|
||||||
Type,
|
Type { data: AssocTypeData },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
||||||
|
@ -1617,6 +1616,6 @@ pub enum ImplTraitInTraitData {
|
||||||
|
|
||||||
impl AssocItem {
|
impl AssocItem {
|
||||||
pub fn is_impl_trait_in_trait(&self) -> bool {
|
pub fn is_impl_trait_in_trait(&self) -> bool {
|
||||||
self.opt_rpitit_info.is_some()
|
matches!(self.kind, AssocKind::Type { data: AssocTypeData::Rpitit(_) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -615,7 +615,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
|
||||||
cx.print_def_path(trait_ref.def_id, trait_ref.args)?;
|
cx.print_def_path(trait_ref.def_id, trait_ref.args)?;
|
||||||
}
|
}
|
||||||
ty::ExistentialPredicate::Projection(projection) => {
|
ty::ExistentialPredicate::Projection(projection) => {
|
||||||
let name = cx.tcx.associated_item(projection.def_id).name;
|
let name = cx.tcx.associated_item(projection.def_id).name();
|
||||||
cx.push("p");
|
cx.push("p");
|
||||||
cx.push_ident(name.as_str());
|
cx.push_ident(name.as_str());
|
||||||
match projection.term.unpack() {
|
match projection.term.unpack() {
|
||||||
|
|
|
@ -2334,13 +2334,13 @@ impl<'tcx> ObligationCause<'tcx> {
|
||||||
subdiags: Vec<TypeErrorAdditionalDiags>,
|
subdiags: Vec<TypeErrorAdditionalDiags>,
|
||||||
) -> ObligationCauseFailureCode {
|
) -> ObligationCauseFailureCode {
|
||||||
match self.code() {
|
match self.code() {
|
||||||
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn, .. } => {
|
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn { .. }, .. } => {
|
||||||
ObligationCauseFailureCode::MethodCompat { span, subdiags }
|
ObligationCauseFailureCode::MethodCompat { span, subdiags }
|
||||||
}
|
}
|
||||||
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type, .. } => {
|
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type { .. }, .. } => {
|
||||||
ObligationCauseFailureCode::TypeCompat { span, subdiags }
|
ObligationCauseFailureCode::TypeCompat { span, subdiags }
|
||||||
}
|
}
|
||||||
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const, .. } => {
|
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const { .. }, .. } => {
|
||||||
ObligationCauseFailureCode::ConstCompat { span, subdiags }
|
ObligationCauseFailureCode::ConstCompat { span, subdiags }
|
||||||
}
|
}
|
||||||
ObligationCauseCode::BlockTailExpression(.., hir::MatchSource::TryDesugar(_)) => {
|
ObligationCauseCode::BlockTailExpression(.., hir::MatchSource::TryDesugar(_)) => {
|
||||||
|
@ -2398,13 +2398,13 @@ impl<'tcx> ObligationCause<'tcx> {
|
||||||
|
|
||||||
fn as_requirement_str(&self) -> &'static str {
|
fn as_requirement_str(&self) -> &'static str {
|
||||||
match self.code() {
|
match self.code() {
|
||||||
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn, .. } => {
|
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn { .. }, .. } => {
|
||||||
"method type is compatible with trait"
|
"method type is compatible with trait"
|
||||||
}
|
}
|
||||||
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type, .. } => {
|
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type { .. }, .. } => {
|
||||||
"associated type is compatible with trait"
|
"associated type is compatible with trait"
|
||||||
}
|
}
|
||||||
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const, .. } => {
|
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const { .. }, .. } => {
|
||||||
"const is compatible with trait"
|
"const is compatible with trait"
|
||||||
}
|
}
|
||||||
ObligationCauseCode::MainFunctionType => "`main` function has the correct type",
|
ObligationCauseCode::MainFunctionType => "`main` function has the correct type",
|
||||||
|
@ -2422,9 +2422,13 @@ pub struct ObligationCauseAsDiagArg<'tcx>(pub ObligationCause<'tcx>);
|
||||||
impl IntoDiagArg for ObligationCauseAsDiagArg<'_> {
|
impl IntoDiagArg for ObligationCauseAsDiagArg<'_> {
|
||||||
fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {
|
fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {
|
||||||
let kind = match self.0.code() {
|
let kind = match self.0.code() {
|
||||||
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn, .. } => "method_compat",
|
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn { .. }, .. } => {
|
||||||
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type, .. } => "type_compat",
|
"method_compat"
|
||||||
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const, .. } => {
|
}
|
||||||
|
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type { .. }, .. } => {
|
||||||
|
"type_compat"
|
||||||
|
}
|
||||||
|
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const { .. }, .. } => {
|
||||||
"const_compat"
|
"const_compat"
|
||||||
}
|
}
|
||||||
ObligationCauseCode::MainFunctionType => "fn_main_correct_type",
|
ObligationCauseCode::MainFunctionType => "fn_main_correct_type",
|
||||||
|
|
|
@ -98,7 +98,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
||||||
let assoc_item = self.tcx().associated_item(trait_item_def_id);
|
let assoc_item = self.tcx().associated_item(trait_item_def_id);
|
||||||
let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] };
|
let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] };
|
||||||
match assoc_item.kind {
|
match assoc_item.kind {
|
||||||
ty::AssocKind::Fn => {
|
ty::AssocKind::Fn { .. } => {
|
||||||
if let Some(hir_id) =
|
if let Some(hir_id) =
|
||||||
assoc_item.def_id.as_local().map(|id| self.tcx().local_def_id_to_hir_id(id))
|
assoc_item.def_id.as_local().map(|id| self.tcx().local_def_id_to_hir_id(id))
|
||||||
{
|
{
|
||||||
|
|
|
@ -158,6 +158,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
||||||
&& self
|
&& self
|
||||||
.tcx()
|
.tcx()
|
||||||
.opt_associated_item(scope_def_id.to_def_id())
|
.opt_associated_item(scope_def_id.to_def_id())
|
||||||
.is_some_and(|i| i.fn_has_self_parameter)
|
.is_some_and(|i| i.is_method())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -782,8 +782,8 @@ fn foo(&self) -> Self::T { String::new() }
|
||||||
let methods: Vec<(Span, String)> = items
|
let methods: Vec<(Span, String)> = items
|
||||||
.in_definition_order()
|
.in_definition_order()
|
||||||
.filter(|item| {
|
.filter(|item| {
|
||||||
ty::AssocKind::Fn == item.kind
|
item.is_fn()
|
||||||
&& Some(item.name) != current_method_ident
|
&& Some(item.name()) != current_method_ident
|
||||||
&& !tcx.is_doc_hidden(item.def_id)
|
&& !tcx.is_doc_hidden(item.def_id)
|
||||||
})
|
})
|
||||||
.filter_map(|item| {
|
.filter_map(|item| {
|
||||||
|
|
|
@ -1017,7 +1017,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||||
infer::BoundRegion(_, br, infer::AssocTypeProjection(def_id)) => format!(
|
infer::BoundRegion(_, br, infer::AssocTypeProjection(def_id)) => format!(
|
||||||
" for lifetime parameter {}in trait containing associated type `{}`",
|
" for lifetime parameter {}in trait containing associated type `{}`",
|
||||||
br_string(br),
|
br_string(br),
|
||||||
self.tcx.associated_item(def_id).name
|
self.tcx.associated_item(def_id).name()
|
||||||
),
|
),
|
||||||
infer::RegionParameterDefinition(_, name) => {
|
infer::RegionParameterDefinition(_, name) => {
|
||||||
format!(" for lifetime parameter `{name}`")
|
format!(" for lifetime parameter `{name}`")
|
||||||
|
|
|
@ -348,11 +348,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||||
&& let None = self.tainted_by_errors()
|
&& let None = self.tainted_by_errors()
|
||||||
{
|
{
|
||||||
let (verb, noun) = match self.tcx.associated_item(item_id).kind {
|
let (verb, noun) = match self.tcx.associated_item(item_id).kind {
|
||||||
ty::AssocKind::Const => ("refer to the", "constant"),
|
ty::AssocKind::Const { .. } => ("refer to the", "constant"),
|
||||||
ty::AssocKind::Fn => ("call", "function"),
|
ty::AssocKind::Fn { .. } => ("call", "function"),
|
||||||
// This is already covered by E0223, but this following single match
|
// This is already covered by E0223, but this following single match
|
||||||
// arm doesn't hurt here.
|
// arm doesn't hurt here.
|
||||||
ty::AssocKind::Type => ("refer to the", "type"),
|
ty::AssocKind::Type { .. } => ("refer to the", "type"),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Replace the more general E0283 with a more specific error
|
// Replace the more general E0283 with a more specific error
|
||||||
|
|
|
@ -2112,16 +2112,20 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||||
trait_ref: DefId,
|
trait_ref: DefId,
|
||||||
) {
|
) {
|
||||||
if let Some(assoc_item) = self.tcx.opt_associated_item(item_def_id) {
|
if let Some(assoc_item) = self.tcx.opt_associated_item(item_def_id) {
|
||||||
if let ty::AssocKind::Const | ty::AssocKind::Type = assoc_item.kind {
|
if let ty::AssocKind::Const { .. } | ty::AssocKind::Type { .. } = assoc_item.kind {
|
||||||
err.note(format!(
|
err.note(format!(
|
||||||
"{}s cannot be accessed directly on a `trait`, they can only be \
|
"{}s cannot be accessed directly on a `trait`, they can only be \
|
||||||
accessed through a specific `impl`",
|
accessed through a specific `impl`",
|
||||||
self.tcx.def_kind_descr(assoc_item.kind.as_def_kind(), item_def_id)
|
self.tcx.def_kind_descr(assoc_item.as_def_kind(), item_def_id)
|
||||||
));
|
));
|
||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
span,
|
span,
|
||||||
"use the fully qualified path to an implementation",
|
"use the fully qualified path to an implementation",
|
||||||
format!("<Type as {}>::{}", self.tcx.def_path_str(trait_ref), assoc_item.name),
|
format!(
|
||||||
|
"<Type as {}>::{}",
|
||||||
|
self.tcx.def_path_str(trait_ref),
|
||||||
|
assoc_item.name()
|
||||||
|
),
|
||||||
Applicability::HasPlaceholders,
|
Applicability::HasPlaceholders,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -5411,7 +5415,7 @@ fn point_at_assoc_type_restriction<G: EmissionGuarantee>(
|
||||||
tcx.associated_items(data.impl_or_alias_def_id).find_by_ident_and_kind(
|
tcx.associated_items(data.impl_or_alias_def_id).find_by_ident_and_kind(
|
||||||
tcx,
|
tcx,
|
||||||
Ident::with_dummy_span(name),
|
Ident::with_dummy_span(name),
|
||||||
ty::AssocKind::Type,
|
ty::AssocTag::Type,
|
||||||
data.impl_or_alias_def_id,
|
data.impl_or_alias_def_id,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
|
|
@ -188,7 +188,7 @@ fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span
|
||||||
tcx.associated_items(trait_def_id)
|
tcx.associated_items(trait_def_id)
|
||||||
.in_definition_order()
|
.in_definition_order()
|
||||||
// We're only looking at associated type bounds
|
// We're only looking at associated type bounds
|
||||||
.filter(|item| item.kind == ty::AssocKind::Type)
|
.filter(|item| item.is_type())
|
||||||
// Ignore GATs with `Self: Sized`
|
// Ignore GATs with `Self: Sized`
|
||||||
.filter(|item| !tcx.generics_require_sized_self(item.def_id))
|
.filter(|item| !tcx.generics_require_sized_self(item.def_id))
|
||||||
.flat_map(|item| tcx.explicit_item_bounds(item.def_id).iter_identity_copied())
|
.flat_map(|item| tcx.explicit_item_bounds(item.def_id).iter_identity_copied())
|
||||||
|
@ -298,10 +298,11 @@ pub fn dyn_compatibility_violations_for_assoc_item(
|
||||||
match item.kind {
|
match item.kind {
|
||||||
// Associated consts are never dyn-compatible, as they can't have `where` bounds yet at all,
|
// Associated consts are never dyn-compatible, as they can't have `where` bounds yet at all,
|
||||||
// and associated const bounds in trait objects aren't a thing yet either.
|
// and associated const bounds in trait objects aren't a thing yet either.
|
||||||
ty::AssocKind::Const => {
|
ty::AssocKind::Const { name } => {
|
||||||
vec![DynCompatibilityViolation::AssocConst(item.name, item.ident(tcx).span)]
|
vec![DynCompatibilityViolation::AssocConst(name, item.ident(tcx).span)]
|
||||||
}
|
}
|
||||||
ty::AssocKind::Fn => virtual_call_violations_for_method(tcx, trait_def_id, item)
|
ty::AssocKind::Fn { name, .. } => {
|
||||||
|
virtual_call_violations_for_method(tcx, trait_def_id, item)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|v| {
|
.map(|v| {
|
||||||
let node = tcx.hir_get_if_local(item.def_id);
|
let node = tcx.hir_get_if_local(item.def_id);
|
||||||
|
@ -316,13 +317,14 @@ pub fn dyn_compatibility_violations_for_assoc_item(
|
||||||
_ => item.ident(tcx).span,
|
_ => item.ident(tcx).span,
|
||||||
};
|
};
|
||||||
|
|
||||||
DynCompatibilityViolation::Method(item.name, v, span)
|
DynCompatibilityViolation::Method(name, v, span)
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect()
|
||||||
|
}
|
||||||
// Associated types can only be dyn-compatible if they have `Self: Sized` bounds.
|
// Associated types can only be dyn-compatible if they have `Self: Sized` bounds.
|
||||||
ty::AssocKind::Type => {
|
ty::AssocKind::Type { .. } => {
|
||||||
if !tcx.generics_of(item.def_id).is_own_empty() && !item.is_impl_trait_in_trait() {
|
if !tcx.generics_of(item.def_id).is_own_empty() && !item.is_impl_trait_in_trait() {
|
||||||
vec![DynCompatibilityViolation::GAT(item.name, item.ident(tcx).span)]
|
vec![DynCompatibilityViolation::GAT(item.name(), item.ident(tcx).span)]
|
||||||
} else {
|
} else {
|
||||||
// We will permit associated types if they are explicitly mentioned in the trait object.
|
// We will permit associated types if they are explicitly mentioned in the trait object.
|
||||||
// We can't check this here, as here we only check if it is guaranteed to not be possible.
|
// We can't check this here, as here we only check if it is guaranteed to not be possible.
|
||||||
|
@ -344,7 +346,7 @@ fn virtual_call_violations_for_method<'tcx>(
|
||||||
let sig = tcx.fn_sig(method.def_id).instantiate_identity();
|
let sig = tcx.fn_sig(method.def_id).instantiate_identity();
|
||||||
|
|
||||||
// The method's first parameter must be named `self`
|
// The method's first parameter must be named `self`
|
||||||
if !method.fn_has_self_parameter {
|
if !method.is_method() {
|
||||||
let sugg = if let Some(hir::Node::TraitItem(hir::TraitItem {
|
let sugg = if let Some(hir::Node::TraitItem(hir::TraitItem {
|
||||||
generics,
|
generics,
|
||||||
kind: hir::TraitItemKind::Fn(sig, _),
|
kind: hir::TraitItemKind::Fn(sig, _),
|
||||||
|
|
|
@ -1393,7 +1393,7 @@ fn confirm_future_candidate<'cx, 'tcx>(
|
||||||
coroutine_sig,
|
coroutine_sig,
|
||||||
);
|
);
|
||||||
|
|
||||||
debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Output);
|
debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name(), sym::Output);
|
||||||
|
|
||||||
let predicate = ty::ProjectionPredicate {
|
let predicate = ty::ProjectionPredicate {
|
||||||
projection_term: ty::AliasTerm::new_from_args(
|
projection_term: ty::AliasTerm::new_from_args(
|
||||||
|
@ -1439,7 +1439,7 @@ fn confirm_iterator_candidate<'cx, 'tcx>(
|
||||||
gen_sig,
|
gen_sig,
|
||||||
);
|
);
|
||||||
|
|
||||||
debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Item);
|
debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name(), sym::Item);
|
||||||
|
|
||||||
let predicate = ty::ProjectionPredicate {
|
let predicate = ty::ProjectionPredicate {
|
||||||
projection_term: ty::AliasTerm::new_from_args(
|
projection_term: ty::AliasTerm::new_from_args(
|
||||||
|
@ -1485,7 +1485,7 @@ fn confirm_async_iterator_candidate<'cx, 'tcx>(
|
||||||
gen_sig,
|
gen_sig,
|
||||||
);
|
);
|
||||||
|
|
||||||
debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Item);
|
debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name(), sym::Item);
|
||||||
|
|
||||||
let ty::Adt(_poll_adt, args) = *yield_ty.kind() else {
|
let ty::Adt(_poll_adt, args) = *yield_ty.kind() else {
|
||||||
bug!();
|
bug!();
|
||||||
|
@ -2005,7 +2005,8 @@ fn confirm_impl_candidate<'cx, 'tcx>(
|
||||||
if !assoc_ty.item.defaultness(tcx).has_value() {
|
if !assoc_ty.item.defaultness(tcx).has_value() {
|
||||||
debug!(
|
debug!(
|
||||||
"confirm_impl_candidate: no associated type {:?} for {:?}",
|
"confirm_impl_candidate: no associated type {:?} for {:?}",
|
||||||
assoc_ty.item.name, obligation.predicate
|
assoc_ty.item.name(),
|
||||||
|
obligation.predicate
|
||||||
);
|
);
|
||||||
if tcx.impl_self_is_guaranteed_unsized(impl_def_id) {
|
if tcx.impl_self_is_guaranteed_unsized(impl_def_id) {
|
||||||
// We treat this projection as rigid here, which is represented via
|
// We treat this projection as rigid here, which is represented via
|
||||||
|
|
|
@ -594,9 +594,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
// Associated types that require `Self: Sized` do not show up in the built-in
|
// Associated types that require `Self: Sized` do not show up in the built-in
|
||||||
// implementation of `Trait for dyn Trait`, and can be dropped here.
|
// implementation of `Trait for dyn Trait`, and can be dropped here.
|
||||||
.filter(|item| !tcx.generics_require_sized_self(item.def_id))
|
.filter(|item| !tcx.generics_require_sized_self(item.def_id))
|
||||||
.filter_map(
|
.filter_map(|item| if item.is_type() { Some(item.def_id) } else { None })
|
||||||
|item| if item.kind == ty::AssocKind::Type { Some(item.def_id) } else { None },
|
|
||||||
)
|
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
for assoc_type in assoc_types {
|
for assoc_type in assoc_types {
|
||||||
|
|
|
@ -197,10 +197,8 @@ fn own_existential_vtable_entries_iter(
|
||||||
tcx: TyCtxt<'_>,
|
tcx: TyCtxt<'_>,
|
||||||
trait_def_id: DefId,
|
trait_def_id: DefId,
|
||||||
) -> impl Iterator<Item = DefId> {
|
) -> impl Iterator<Item = DefId> {
|
||||||
let trait_methods = tcx
|
let trait_methods =
|
||||||
.associated_items(trait_def_id)
|
tcx.associated_items(trait_def_id).in_definition_order().filter(|item| item.is_fn());
|
||||||
.in_definition_order()
|
|
||||||
.filter(|item| item.kind == ty::AssocKind::Fn);
|
|
||||||
|
|
||||||
// Now list each method's DefId (for within its trait).
|
// Now list each method's DefId (for within its trait).
|
||||||
let own_entries = trait_methods.filter_map(move |&trait_method| {
|
let own_entries = trait_methods.filter_map(move |&trait_method| {
|
||||||
|
|
|
@ -6,7 +6,6 @@ use rustc_hir::{self as hir, AmbigArg};
|
||||||
use rustc_middle::query::Providers;
|
use rustc_middle::query::Providers;
|
||||||
use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt};
|
use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt};
|
||||||
use rustc_middle::{bug, span_bug};
|
use rustc_middle::{bug, span_bug};
|
||||||
use rustc_span::kw;
|
|
||||||
|
|
||||||
pub(crate) fn provide(providers: &mut Providers) {
|
pub(crate) fn provide(providers: &mut Providers) {
|
||||||
*providers = Providers {
|
*providers = Providers {
|
||||||
|
@ -129,39 +128,35 @@ fn associated_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AssocItem {
|
||||||
|
|
||||||
fn associated_item_from_trait_item_ref(trait_item_ref: &hir::TraitItemRef) -> ty::AssocItem {
|
fn associated_item_from_trait_item_ref(trait_item_ref: &hir::TraitItemRef) -> ty::AssocItem {
|
||||||
let owner_id = trait_item_ref.id.owner_id;
|
let owner_id = trait_item_ref.id.owner_id;
|
||||||
let (kind, has_self) = match trait_item_ref.kind {
|
let name = trait_item_ref.ident.name;
|
||||||
hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
|
let kind = match trait_item_ref.kind {
|
||||||
hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
|
hir::AssocItemKind::Const => ty::AssocKind::Const { name },
|
||||||
hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
|
hir::AssocItemKind::Fn { has_self } => ty::AssocKind::Fn { name, has_self },
|
||||||
|
hir::AssocItemKind::Type => ty::AssocKind::Type { data: ty::AssocTypeData::Normal(name) },
|
||||||
};
|
};
|
||||||
|
|
||||||
ty::AssocItem {
|
ty::AssocItem {
|
||||||
name: trait_item_ref.ident.name,
|
|
||||||
kind,
|
kind,
|
||||||
def_id: owner_id.to_def_id(),
|
def_id: owner_id.to_def_id(),
|
||||||
trait_item_def_id: Some(owner_id.to_def_id()),
|
trait_item_def_id: Some(owner_id.to_def_id()),
|
||||||
container: ty::AssocItemContainer::Trait,
|
container: ty::AssocItemContainer::Trait,
|
||||||
fn_has_self_parameter: has_self,
|
|
||||||
opt_rpitit_info: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::AssocItem {
|
fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::AssocItem {
|
||||||
let def_id = impl_item_ref.id.owner_id;
|
let def_id = impl_item_ref.id.owner_id;
|
||||||
let (kind, has_self) = match impl_item_ref.kind {
|
let name = impl_item_ref.ident.name;
|
||||||
hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
|
let kind = match impl_item_ref.kind {
|
||||||
hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
|
hir::AssocItemKind::Const => ty::AssocKind::Const { name },
|
||||||
hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
|
hir::AssocItemKind::Fn { has_self } => ty::AssocKind::Fn { name, has_self },
|
||||||
|
hir::AssocItemKind::Type => ty::AssocKind::Type { data: ty::AssocTypeData::Normal(name) },
|
||||||
};
|
};
|
||||||
|
|
||||||
ty::AssocItem {
|
ty::AssocItem {
|
||||||
name: impl_item_ref.ident.name,
|
|
||||||
kind,
|
kind,
|
||||||
def_id: def_id.to_def_id(),
|
def_id: def_id.to_def_id(),
|
||||||
trait_item_def_id: impl_item_ref.trait_item_def_id,
|
trait_item_def_id: impl_item_ref.trait_item_def_id,
|
||||||
container: ty::AssocItemContainer::Impl,
|
container: ty::AssocItemContainer::Impl,
|
||||||
fn_has_self_parameter: has_self,
|
|
||||||
opt_rpitit_info: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -264,16 +259,15 @@ fn associated_type_for_impl_trait_in_trait(
|
||||||
trait_assoc_ty.def_ident_span(Some(span));
|
trait_assoc_ty.def_ident_span(Some(span));
|
||||||
|
|
||||||
trait_assoc_ty.associated_item(ty::AssocItem {
|
trait_assoc_ty.associated_item(ty::AssocItem {
|
||||||
name: kw::Empty,
|
kind: ty::AssocKind::Type {
|
||||||
kind: ty::AssocKind::Type,
|
data: ty::AssocTypeData::Rpitit(ImplTraitInTraitData::Trait {
|
||||||
def_id,
|
|
||||||
trait_item_def_id: None,
|
|
||||||
container: ty::AssocItemContainer::Trait,
|
|
||||||
fn_has_self_parameter: false,
|
|
||||||
opt_rpitit_info: Some(ImplTraitInTraitData::Trait {
|
|
||||||
fn_def_id: fn_def_id.to_def_id(),
|
fn_def_id: fn_def_id.to_def_id(),
|
||||||
opaque_def_id: opaque_ty_def_id.to_def_id(),
|
opaque_def_id: opaque_ty_def_id.to_def_id(),
|
||||||
}),
|
}),
|
||||||
|
},
|
||||||
|
def_id,
|
||||||
|
trait_item_def_id: None,
|
||||||
|
container: ty::AssocItemContainer::Trait,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Copy visility of the containing function.
|
// Copy visility of the containing function.
|
||||||
|
@ -317,13 +311,14 @@ fn associated_type_for_impl_trait_in_impl(
|
||||||
impl_assoc_ty.def_ident_span(Some(span));
|
impl_assoc_ty.def_ident_span(Some(span));
|
||||||
|
|
||||||
impl_assoc_ty.associated_item(ty::AssocItem {
|
impl_assoc_ty.associated_item(ty::AssocItem {
|
||||||
name: kw::Empty,
|
kind: ty::AssocKind::Type {
|
||||||
kind: ty::AssocKind::Type,
|
data: ty::AssocTypeData::Rpitit(ImplTraitInTraitData::Impl {
|
||||||
|
fn_def_id: impl_fn_def_id.to_def_id(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
def_id,
|
def_id,
|
||||||
trait_item_def_id: Some(trait_assoc_def_id),
|
trait_item_def_id: Some(trait_assoc_def_id),
|
||||||
container: ty::AssocItemContainer::Impl,
|
container: ty::AssocItemContainer::Impl,
|
||||||
fn_has_self_parameter: false,
|
|
||||||
opt_rpitit_info: Some(ImplTraitInTraitData::Impl { fn_def_id: impl_fn_def_id.to_def_id() }),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Copy visility of the containing function.
|
// Copy visility of the containing function.
|
||||||
|
|
|
@ -2,19 +2,23 @@
|
||||||
|
|
||||||
pub use crate::macros::builtin::{contracts_ensures as ensures, contracts_requires as requires};
|
pub use crate::macros::builtin::{contracts_ensures as ensures, contracts_requires as requires};
|
||||||
|
|
||||||
/// Emitted by rustc as a desugaring of `#[ensures(PRED)] fn foo() -> R { ... [return R;] ... }`
|
/// This is an identity function used as part of the desugaring of the `#[ensures]` attribute.
|
||||||
/// into: `fn foo() { let _check = build_check_ensures(|ret| PRED) ... [return _check(R);] ... }`
|
///
|
||||||
/// (including the implicit return of the tail expression, if any).
|
/// This is an existing hack to allow users to omit the type of the return value in their ensures
|
||||||
|
/// attribute.
|
||||||
|
///
|
||||||
|
/// Ideally, rustc should be able to generate the type annotation.
|
||||||
|
/// The existing lowering logic makes it rather hard to add the explicit type annotation,
|
||||||
|
/// while the function call is fairly straight forward.
|
||||||
#[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)]
|
#[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)]
|
||||||
|
// Similar to `contract_check_requires`, we need to use the user-facing
|
||||||
|
// `contracts` feature rather than the perma-unstable `contracts_internals`.
|
||||||
|
// Const-checking doesn't honor allow_internal_unstable logic used by contract expansion.
|
||||||
|
#[rustc_const_unstable(feature = "contracts", issue = "128044")]
|
||||||
#[lang = "contract_build_check_ensures"]
|
#[lang = "contract_build_check_ensures"]
|
||||||
#[track_caller]
|
pub const fn build_check_ensures<Ret, C>(cond: C) -> C
|
||||||
pub fn build_check_ensures<Ret, C>(cond: C) -> impl (Fn(Ret) -> Ret) + Copy
|
|
||||||
where
|
where
|
||||||
C: for<'a> Fn(&'a Ret) -> bool + Copy + 'static,
|
C: Fn(&Ret) -> bool + Copy + 'static,
|
||||||
{
|
{
|
||||||
#[track_caller]
|
cond
|
||||||
move |ret| {
|
|
||||||
crate::intrinsics::contract_check_ensures(&ret, cond);
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3402,20 +3402,62 @@ pub const fn contract_checks() -> bool {
|
||||||
///
|
///
|
||||||
/// By default, if `contract_checks` is enabled, this will panic with no unwind if the condition
|
/// By default, if `contract_checks` is enabled, this will panic with no unwind if the condition
|
||||||
/// returns false.
|
/// returns false.
|
||||||
#[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)]
|
///
|
||||||
|
/// Note that this function is a no-op during constant evaluation.
|
||||||
|
#[unstable(feature = "contracts_internals", issue = "128044")]
|
||||||
|
// Calls to this function get inserted by an AST expansion pass, which uses the equivalent of
|
||||||
|
// `#[allow_internal_unstable]` to allow using `contracts_internals` functions. Const-checking
|
||||||
|
// doesn't honor `#[allow_internal_unstable]`, so for the const feature gate we use the user-facing
|
||||||
|
// `contracts` feature rather than the perma-unstable `contracts_internals`
|
||||||
|
#[rustc_const_unstable(feature = "contracts", issue = "128044")]
|
||||||
#[lang = "contract_check_requires"]
|
#[lang = "contract_check_requires"]
|
||||||
#[rustc_intrinsic]
|
#[rustc_intrinsic]
|
||||||
pub fn contract_check_requires<C: Fn() -> bool>(cond: C) {
|
pub const fn contract_check_requires<C: Fn() -> bool + Copy>(cond: C) {
|
||||||
|
const_eval_select!(
|
||||||
|
@capture[C: Fn() -> bool + Copy] { cond: C } :
|
||||||
|
if const {
|
||||||
|
// Do nothing
|
||||||
|
} else {
|
||||||
if contract_checks() && !cond() {
|
if contract_checks() && !cond() {
|
||||||
// Emit no unwind panic in case this was a safety requirement.
|
// Emit no unwind panic in case this was a safety requirement.
|
||||||
crate::panicking::panic_nounwind("failed requires check");
|
crate::panicking::panic_nounwind("failed requires check");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// Check if the post-condition `cond` has been met.
|
/// Check if the post-condition `cond` has been met.
|
||||||
///
|
///
|
||||||
/// By default, if `contract_checks` is enabled, this will panic with no unwind if the condition
|
/// By default, if `contract_checks` is enabled, this will panic with no unwind if the condition
|
||||||
/// returns false.
|
/// returns false.
|
||||||
|
///
|
||||||
|
/// Note that this function is a no-op during constant evaluation.
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
#[unstable(feature = "contracts_internals", issue = "128044")]
|
||||||
|
// Similar to `contract_check_requires`, we need to use the user-facing
|
||||||
|
// `contracts` feature rather than the perma-unstable `contracts_internals`.
|
||||||
|
// Const-checking doesn't honor allow_internal_unstable logic used by contract expansion.
|
||||||
|
#[rustc_const_unstable(feature = "contracts", issue = "128044")]
|
||||||
|
#[lang = "contract_check_ensures"]
|
||||||
|
#[rustc_intrinsic]
|
||||||
|
pub const fn contract_check_ensures<C: Fn(&Ret) -> bool + Copy, Ret>(cond: C, ret: Ret) -> Ret {
|
||||||
|
const_eval_select!(
|
||||||
|
@capture[C: Fn(&Ret) -> bool + Copy, Ret] { cond: C, ret: Ret } -> Ret :
|
||||||
|
if const {
|
||||||
|
// Do nothing
|
||||||
|
ret
|
||||||
|
} else {
|
||||||
|
if contract_checks() && !cond(&ret) {
|
||||||
|
// Emit no unwind panic in case this was a safety requirement.
|
||||||
|
crate::panicking::panic_nounwind("failed ensures check");
|
||||||
|
}
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This is the old version of contract_check_ensures kept here for bootstrap only.
|
||||||
|
#[cfg(bootstrap)]
|
||||||
#[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)]
|
#[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)]
|
||||||
#[rustc_intrinsic]
|
#[rustc_intrinsic]
|
||||||
pub fn contract_check_ensures<'a, Ret, C: Fn(&'a Ret) -> bool>(ret: &'a Ret, cond: C) {
|
pub fn contract_check_ensures<'a, Ret, C: Fn(&'a Ret) -> bool>(ret: &'a Ret, cond: C) {
|
||||||
|
|
|
@ -101,7 +101,6 @@
|
||||||
#![feature(bstr)]
|
#![feature(bstr)]
|
||||||
#![feature(bstr_internals)]
|
#![feature(bstr_internals)]
|
||||||
#![feature(cfg_match)]
|
#![feature(cfg_match)]
|
||||||
#![feature(closure_track_caller)]
|
|
||||||
#![feature(const_carrying_mul_add)]
|
#![feature(const_carrying_mul_add)]
|
||||||
#![feature(const_eval_select)]
|
#![feature(const_eval_select)]
|
||||||
#![feature(core_intrinsics)]
|
#![feature(core_intrinsics)]
|
||||||
|
|
|
@ -111,12 +111,6 @@ impl Clone for TokenStream {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for SourceFile {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
self.clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Span {
|
impl Span {
|
||||||
pub(crate) fn def_site() -> Span {
|
pub(crate) fn def_site() -> Span {
|
||||||
Bridge::with(|bridge| bridge.globals.def_site)
|
Bridge::with(|bridge| bridge.globals.def_site)
|
||||||
|
|
|
@ -81,16 +81,8 @@ macro_rules! with_api {
|
||||||
$self: $S::TokenStream
|
$self: $S::TokenStream
|
||||||
) -> Vec<TokenTree<$S::TokenStream, $S::Span, $S::Symbol>>;
|
) -> Vec<TokenTree<$S::TokenStream, $S::Span, $S::Symbol>>;
|
||||||
},
|
},
|
||||||
SourceFile {
|
|
||||||
fn drop($self: $S::SourceFile);
|
|
||||||
fn clone($self: &$S::SourceFile) -> $S::SourceFile;
|
|
||||||
fn eq($self: &$S::SourceFile, other: &$S::SourceFile) -> bool;
|
|
||||||
fn path($self: &$S::SourceFile) -> String;
|
|
||||||
fn is_real($self: &$S::SourceFile) -> bool;
|
|
||||||
},
|
|
||||||
Span {
|
Span {
|
||||||
fn debug($self: $S::Span) -> String;
|
fn debug($self: $S::Span) -> String;
|
||||||
fn source_file($self: $S::Span) -> $S::SourceFile;
|
|
||||||
fn parent($self: $S::Span) -> Option<$S::Span>;
|
fn parent($self: $S::Span) -> Option<$S::Span>;
|
||||||
fn source($self: $S::Span) -> $S::Span;
|
fn source($self: $S::Span) -> $S::Span;
|
||||||
fn byte_range($self: $S::Span) -> Range<usize>;
|
fn byte_range($self: $S::Span) -> Range<usize>;
|
||||||
|
@ -98,6 +90,8 @@ macro_rules! with_api {
|
||||||
fn end($self: $S::Span) -> $S::Span;
|
fn end($self: $S::Span) -> $S::Span;
|
||||||
fn line($self: $S::Span) -> usize;
|
fn line($self: $S::Span) -> usize;
|
||||||
fn column($self: $S::Span) -> usize;
|
fn column($self: $S::Span) -> usize;
|
||||||
|
fn file($self: $S::Span) -> String;
|
||||||
|
fn local_file($self: $S::Span) -> Option<String>;
|
||||||
fn join($self: $S::Span, other: $S::Span) -> Option<$S::Span>;
|
fn join($self: $S::Span, other: $S::Span) -> Option<$S::Span>;
|
||||||
fn subspan($self: $S::Span, start: Bound<usize>, end: Bound<usize>) -> Option<$S::Span>;
|
fn subspan($self: $S::Span, start: Bound<usize>, end: Bound<usize>) -> Option<$S::Span>;
|
||||||
fn resolved_at($self: $S::Span, at: $S::Span) -> $S::Span;
|
fn resolved_at($self: $S::Span, at: $S::Span) -> $S::Span;
|
||||||
|
@ -120,7 +114,6 @@ macro_rules! with_api_handle_types {
|
||||||
'owned:
|
'owned:
|
||||||
FreeFunctions,
|
FreeFunctions,
|
||||||
TokenStream,
|
TokenStream,
|
||||||
SourceFile,
|
|
||||||
|
|
||||||
'interned:
|
'interned:
|
||||||
Span,
|
Span,
|
||||||
|
|
|
@ -82,7 +82,6 @@ with_api_handle_types!(define_server_handles);
|
||||||
pub trait Types {
|
pub trait Types {
|
||||||
type FreeFunctions: 'static;
|
type FreeFunctions: 'static;
|
||||||
type TokenStream: 'static + Clone;
|
type TokenStream: 'static + Clone;
|
||||||
type SourceFile: 'static + Clone;
|
|
||||||
type Span: 'static + Copy + Eq + Hash;
|
type Span: 'static + Copy + Eq + Hash;
|
||||||
type Symbol: 'static;
|
type Symbol: 'static;
|
||||||
}
|
}
|
||||||
|
|
|
@ -491,12 +491,6 @@ impl Span {
|
||||||
Span(bridge::client::Span::mixed_site())
|
Span(bridge::client::Span::mixed_site())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The original source file into which this span points.
|
|
||||||
#[unstable(feature = "proc_macro_span", issue = "54725")]
|
|
||||||
pub fn source_file(&self) -> SourceFile {
|
|
||||||
SourceFile(self.0.source_file())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The `Span` for the tokens in the previous macro expansion from which
|
/// The `Span` for the tokens in the previous macro expansion from which
|
||||||
/// `self` was generated from, if any.
|
/// `self` was generated from, if any.
|
||||||
#[unstable(feature = "proc_macro_span", issue = "54725")]
|
#[unstable(feature = "proc_macro_span", issue = "54725")]
|
||||||
|
@ -546,6 +540,25 @@ impl Span {
|
||||||
self.0.column()
|
self.0.column()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The path to the source file in which this span occurs, for display purposes.
|
||||||
|
///
|
||||||
|
/// This might not correspond to a valid file system path.
|
||||||
|
/// It might be remapped, or might be an artificial path such as `"<macro expansion>"`.
|
||||||
|
#[unstable(feature = "proc_macro_span", issue = "54725")]
|
||||||
|
pub fn file(&self) -> String {
|
||||||
|
self.0.file()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The path to the source file in which this span occurs on disk.
|
||||||
|
///
|
||||||
|
/// This is the actual path on disk. It is unaffected by path remapping.
|
||||||
|
///
|
||||||
|
/// This path should not be embedded in the output of the macro; prefer `file()` instead.
|
||||||
|
#[unstable(feature = "proc_macro_span", issue = "54725")]
|
||||||
|
pub fn local_file(&self) -> Option<PathBuf> {
|
||||||
|
self.0.local_file().map(|s| PathBuf::from(s))
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a new span encompassing `self` and `other`.
|
/// Creates a new span encompassing `self` and `other`.
|
||||||
///
|
///
|
||||||
/// Returns `None` if `self` and `other` are from different files.
|
/// Returns `None` if `self` and `other` are from different files.
|
||||||
|
@ -614,58 +627,6 @@ impl fmt::Debug for Span {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The source file of a given `Span`.
|
|
||||||
#[unstable(feature = "proc_macro_span", issue = "54725")]
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct SourceFile(bridge::client::SourceFile);
|
|
||||||
|
|
||||||
impl SourceFile {
|
|
||||||
/// Gets the path to this source file.
|
|
||||||
///
|
|
||||||
/// ### Note
|
|
||||||
/// If the code span associated with this `SourceFile` was generated by an external macro, this
|
|
||||||
/// macro, this might not be an actual path on the filesystem. Use [`is_real`] to check.
|
|
||||||
///
|
|
||||||
/// Also note that even if `is_real` returns `true`, if `--remap-path-prefix` was passed on
|
|
||||||
/// the command line, the path as given might not actually be valid.
|
|
||||||
///
|
|
||||||
/// [`is_real`]: Self::is_real
|
|
||||||
#[unstable(feature = "proc_macro_span", issue = "54725")]
|
|
||||||
pub fn path(&self) -> PathBuf {
|
|
||||||
PathBuf::from(self.0.path())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns `true` if this source file is a real source file, and not generated by an external
|
|
||||||
/// macro's expansion.
|
|
||||||
#[unstable(feature = "proc_macro_span", issue = "54725")]
|
|
||||||
pub fn is_real(&self) -> bool {
|
|
||||||
// This is a hack until intercrate spans are implemented and we can have real source files
|
|
||||||
// for spans generated in external macros.
|
|
||||||
// https://github.com/rust-lang/rust/pull/43604#issuecomment-333334368
|
|
||||||
self.0.is_real()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[unstable(feature = "proc_macro_span", issue = "54725")]
|
|
||||||
impl fmt::Debug for SourceFile {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
f.debug_struct("SourceFile")
|
|
||||||
.field("path", &self.path())
|
|
||||||
.field("is_real", &self.is_real())
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[unstable(feature = "proc_macro_span", issue = "54725")]
|
|
||||||
impl PartialEq for SourceFile {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.0.eq(&other.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[unstable(feature = "proc_macro_span", issue = "54725")]
|
|
||||||
impl Eq for SourceFile {}
|
|
||||||
|
|
||||||
/// A single token or a delimited sequence of token trees (e.g., `[1, (), ..]`).
|
/// A single token or a delimited sequence of token trees (e.g., `[1, (), ..]`).
|
||||||
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
|
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
|
|
@ -1286,6 +1286,40 @@ pub struct Output {
|
||||||
pub stderr: Vec<u8>,
|
pub stderr: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Output {
|
||||||
|
/// Returns an error if a nonzero exit status was received.
|
||||||
|
///
|
||||||
|
/// If the [`Command`] exited successfully,
|
||||||
|
/// `self` is returned.
|
||||||
|
///
|
||||||
|
/// This is equivalent to calling [`exit_ok`](ExitStatus::exit_ok)
|
||||||
|
/// on [`Output.status`](Output::status).
|
||||||
|
///
|
||||||
|
/// Note that this will throw away the [`Output::stderr`] field in the error case.
|
||||||
|
/// If the child process outputs useful informantion to stderr, you can:
|
||||||
|
/// * Use `cmd.stderr(Stdio::inherit())` to forward the
|
||||||
|
/// stderr child process to the parent's stderr,
|
||||||
|
/// usually printing it to console where the user can see it.
|
||||||
|
/// This is usually correct for command-line applications.
|
||||||
|
/// * Capture `stderr` using a custom error type.
|
||||||
|
/// This is usually correct for libraries.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(exit_status_error)]
|
||||||
|
/// # #[cfg(unix)] {
|
||||||
|
/// use std::process::Command;
|
||||||
|
/// assert!(Command::new("false").output().unwrap().exit_ok().is_err());
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "exit_status_error", issue = "84908")]
|
||||||
|
pub fn exit_ok(self) -> Result<Self, ExitStatusError> {
|
||||||
|
self.status.exit_ok()?;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If either stderr or stdout are valid utf8 strings it prints the valid
|
// If either stderr or stdout are valid utf8 strings it prints the valid
|
||||||
// strings, otherwise it prints the byte sequence instead
|
// strings, otherwise it prints the byte sequence instead
|
||||||
#[stable(feature = "process_output_debug", since = "1.7.0")]
|
#[stable(feature = "process_output_debug", since = "1.7.0")]
|
||||||
|
|
|
@ -274,6 +274,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
|
||||||
libc::ETXTBSY => ExecutableFileBusy,
|
libc::ETXTBSY => ExecutableFileBusy,
|
||||||
libc::EXDEV => CrossesDevices,
|
libc::EXDEV => CrossesDevices,
|
||||||
libc::EINPROGRESS => InProgress,
|
libc::EINPROGRESS => InProgress,
|
||||||
|
libc::EOPNOTSUPP => Unsupported,
|
||||||
|
|
||||||
libc::EACCES | libc::EPERM => PermissionDenied,
|
libc::EACCES | libc::EPERM => PermissionDenied,
|
||||||
|
|
||||||
|
|
|
@ -8,14 +8,19 @@ use crate::sys::weak::weak;
|
||||||
use crate::sys::{os, stack_overflow};
|
use crate::sys::{os, stack_overflow};
|
||||||
use crate::time::Duration;
|
use crate::time::Duration;
|
||||||
use crate::{cmp, io, ptr};
|
use crate::{cmp, io, ptr};
|
||||||
#[cfg(not(any(target_os = "l4re", target_os = "vxworks", target_os = "espidf")))]
|
#[cfg(not(any(
|
||||||
|
target_os = "l4re",
|
||||||
|
target_os = "vxworks",
|
||||||
|
target_os = "espidf",
|
||||||
|
target_os = "nuttx"
|
||||||
|
)))]
|
||||||
pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
|
pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
|
||||||
#[cfg(target_os = "l4re")]
|
#[cfg(target_os = "l4re")]
|
||||||
pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024;
|
pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024;
|
||||||
#[cfg(target_os = "vxworks")]
|
#[cfg(target_os = "vxworks")]
|
||||||
pub const DEFAULT_MIN_STACK_SIZE: usize = 256 * 1024;
|
pub const DEFAULT_MIN_STACK_SIZE: usize = 256 * 1024;
|
||||||
#[cfg(target_os = "espidf")]
|
#[cfg(any(target_os = "espidf", target_os = "nuttx"))]
|
||||||
pub const DEFAULT_MIN_STACK_SIZE: usize = 0; // 0 indicates that the stack size configured in the ESP-IDF menuconfig system should be used
|
pub const DEFAULT_MIN_STACK_SIZE: usize = 0; // 0 indicates that the stack size configured in the ESP-IDF/NuttX menuconfig system should be used
|
||||||
|
|
||||||
#[cfg(target_os = "fuchsia")]
|
#[cfg(target_os = "fuchsia")]
|
||||||
mod zircon {
|
mod zircon {
|
||||||
|
@ -52,10 +57,10 @@ impl Thread {
|
||||||
let mut attr: mem::MaybeUninit<libc::pthread_attr_t> = mem::MaybeUninit::uninit();
|
let mut attr: mem::MaybeUninit<libc::pthread_attr_t> = mem::MaybeUninit::uninit();
|
||||||
assert_eq!(libc::pthread_attr_init(attr.as_mut_ptr()), 0);
|
assert_eq!(libc::pthread_attr_init(attr.as_mut_ptr()), 0);
|
||||||
|
|
||||||
#[cfg(target_os = "espidf")]
|
#[cfg(any(target_os = "espidf", target_os = "nuttx"))]
|
||||||
if stack > 0 {
|
if stack > 0 {
|
||||||
// Only set the stack if a non-zero value is passed
|
// Only set the stack if a non-zero value is passed
|
||||||
// 0 is used as an indication that the default stack size configured in the ESP-IDF menuconfig system should be used
|
// 0 is used as an indication that the default stack size configured in the ESP-IDF/NuttX menuconfig system should be used
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
libc::pthread_attr_setstacksize(
|
libc::pthread_attr_setstacksize(
|
||||||
attr.as_mut_ptr(),
|
attr.as_mut_ptr(),
|
||||||
|
@ -65,7 +70,7 @@ impl Thread {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_os = "espidf"))]
|
#[cfg(not(any(target_os = "espidf", target_os = "nuttx")))]
|
||||||
{
|
{
|
||||||
let stack_size = cmp::max(stack, min_stack_size(attr.as_ptr()));
|
let stack_size = cmp::max(stack, min_stack_size(attr.as_ptr()));
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use r_efi::protocols::simple_text_output;
|
use r_efi::protocols::{simple_text_input, simple_text_output};
|
||||||
|
|
||||||
use crate::collections::BTreeMap;
|
use crate::collections::BTreeMap;
|
||||||
pub use crate::ffi::OsString as EnvKey;
|
pub use crate::ffi::OsString as EnvKey;
|
||||||
|
@ -23,6 +23,7 @@ pub struct Command {
|
||||||
args: Vec<OsString>,
|
args: Vec<OsString>,
|
||||||
stdout: Option<Stdio>,
|
stdout: Option<Stdio>,
|
||||||
stderr: Option<Stdio>,
|
stderr: Option<Stdio>,
|
||||||
|
stdin: Option<Stdio>,
|
||||||
env: CommandEnv,
|
env: CommandEnv,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,6 +49,7 @@ impl Command {
|
||||||
args: Vec::new(),
|
args: Vec::new(),
|
||||||
stdout: None,
|
stdout: None,
|
||||||
stderr: None,
|
stderr: None,
|
||||||
|
stdin: None,
|
||||||
env: Default::default(),
|
env: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,8 +66,8 @@ impl Command {
|
||||||
panic!("unsupported")
|
panic!("unsupported")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stdin(&mut self, _stdin: Stdio) {
|
pub fn stdin(&mut self, stdin: Stdio) {
|
||||||
panic!("unsupported")
|
self.stdin = Some(stdin);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stdout(&mut self, stdout: Stdio) {
|
pub fn stdout(&mut self, stdout: Stdio) {
|
||||||
|
@ -122,6 +124,22 @@ impl Command {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_stdin(
|
||||||
|
s: Stdio,
|
||||||
|
) -> io::Result<Option<helpers::OwnedProtocol<uefi_command_internal::InputProtocol>>> {
|
||||||
|
match s {
|
||||||
|
Stdio::Null => unsafe {
|
||||||
|
helpers::OwnedProtocol::create(
|
||||||
|
uefi_command_internal::InputProtocol::null(),
|
||||||
|
simple_text_input::PROTOCOL_GUID,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.map(Some),
|
||||||
|
Stdio::Inherit => Ok(None),
|
||||||
|
Stdio::MakePipe => unsupported(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
|
pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
|
||||||
let mut cmd = uefi_command_internal::Image::load_image(&self.prog)?;
|
let mut cmd = uefi_command_internal::Image::load_image(&self.prog)?;
|
||||||
|
|
||||||
|
@ -149,6 +167,15 @@ impl Command {
|
||||||
cmd.stderr_inherit()
|
cmd.stderr_inherit()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Setup Stdin
|
||||||
|
let stdin = self.stdin.unwrap_or(Stdio::Null);
|
||||||
|
let stdin = Self::create_stdin(stdin)?;
|
||||||
|
if let Some(con) = stdin {
|
||||||
|
cmd.stdin_init(con)
|
||||||
|
} else {
|
||||||
|
cmd.stdin_inherit()
|
||||||
|
};
|
||||||
|
|
||||||
let env = env_changes(&self.env);
|
let env = env_changes(&self.env);
|
||||||
|
|
||||||
// Set any new vars
|
// Set any new vars
|
||||||
|
@ -334,7 +361,7 @@ impl<'a> fmt::Debug for CommandArgs<'a> {
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
mod uefi_command_internal {
|
mod uefi_command_internal {
|
||||||
use r_efi::protocols::{loaded_image, simple_text_output};
|
use r_efi::protocols::{loaded_image, simple_text_input, simple_text_output};
|
||||||
|
|
||||||
use crate::ffi::{OsStr, OsString};
|
use crate::ffi::{OsStr, OsString};
|
||||||
use crate::io::{self, const_error};
|
use crate::io::{self, const_error};
|
||||||
|
@ -350,6 +377,7 @@ mod uefi_command_internal {
|
||||||
handle: NonNull<crate::ffi::c_void>,
|
handle: NonNull<crate::ffi::c_void>,
|
||||||
stdout: Option<helpers::OwnedProtocol<PipeProtocol>>,
|
stdout: Option<helpers::OwnedProtocol<PipeProtocol>>,
|
||||||
stderr: Option<helpers::OwnedProtocol<PipeProtocol>>,
|
stderr: Option<helpers::OwnedProtocol<PipeProtocol>>,
|
||||||
|
stdin: Option<helpers::OwnedProtocol<InputProtocol>>,
|
||||||
st: OwnedTable<r_efi::efi::SystemTable>,
|
st: OwnedTable<r_efi::efi::SystemTable>,
|
||||||
args: Option<(*mut u16, usize)>,
|
args: Option<(*mut u16, usize)>,
|
||||||
}
|
}
|
||||||
|
@ -384,7 +412,14 @@ mod uefi_command_internal {
|
||||||
helpers::open_protocol(child_handle, loaded_image::PROTOCOL_GUID).unwrap();
|
helpers::open_protocol(child_handle, loaded_image::PROTOCOL_GUID).unwrap();
|
||||||
let st = OwnedTable::from_table(unsafe { (*loaded_image.as_ptr()).system_table });
|
let st = OwnedTable::from_table(unsafe { (*loaded_image.as_ptr()).system_table });
|
||||||
|
|
||||||
Ok(Self { handle: child_handle, stdout: None, stderr: None, st, args: None })
|
Ok(Self {
|
||||||
|
handle: child_handle,
|
||||||
|
stdout: None,
|
||||||
|
stderr: None,
|
||||||
|
stdin: None,
|
||||||
|
st,
|
||||||
|
args: None,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -445,6 +480,17 @@ mod uefi_command_internal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_stdin(
|
||||||
|
&mut self,
|
||||||
|
handle: r_efi::efi::Handle,
|
||||||
|
protocol: *mut simple_text_input::Protocol,
|
||||||
|
) {
|
||||||
|
unsafe {
|
||||||
|
(*self.st.as_mut_ptr()).console_in_handle = handle;
|
||||||
|
(*self.st.as_mut_ptr()).con_in = protocol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn stdout_init(&mut self, protocol: helpers::OwnedProtocol<PipeProtocol>) {
|
pub fn stdout_init(&mut self, protocol: helpers::OwnedProtocol<PipeProtocol>) {
|
||||||
self.set_stdout(
|
self.set_stdout(
|
||||||
protocol.handle().as_ptr(),
|
protocol.handle().as_ptr(),
|
||||||
|
@ -471,6 +517,19 @@ mod uefi_command_internal {
|
||||||
unsafe { self.set_stderr((*st.as_ptr()).standard_error_handle, (*st.as_ptr()).std_err) }
|
unsafe { self.set_stderr((*st.as_ptr()).standard_error_handle, (*st.as_ptr()).std_err) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn stdin_init(&mut self, protocol: helpers::OwnedProtocol<InputProtocol>) {
|
||||||
|
self.set_stdin(
|
||||||
|
protocol.handle().as_ptr(),
|
||||||
|
protocol.as_ref() as *const InputProtocol as *mut simple_text_input::Protocol,
|
||||||
|
);
|
||||||
|
self.stdin = Some(protocol);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn stdin_inherit(&mut self) {
|
||||||
|
let st: NonNull<r_efi::efi::SystemTable> = system_table().cast();
|
||||||
|
unsafe { self.set_stdin((*st.as_ptr()).console_in_handle, (*st.as_ptr()).con_in) }
|
||||||
|
}
|
||||||
|
|
||||||
pub fn stderr(&self) -> io::Result<Vec<u8>> {
|
pub fn stderr(&self) -> io::Result<Vec<u8>> {
|
||||||
match &self.stderr {
|
match &self.stderr {
|
||||||
Some(stderr) => stderr.as_ref().utf8(),
|
Some(stderr) => stderr.as_ref().utf8(),
|
||||||
|
@ -722,6 +781,56 @@ mod uefi_command_internal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub(crate) struct InputProtocol {
|
||||||
|
reset: simple_text_input::ProtocolReset,
|
||||||
|
read_key_stroke: simple_text_input::ProtocolReadKeyStroke,
|
||||||
|
wait_for_key: r_efi::efi::Event,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InputProtocol {
|
||||||
|
pub(crate) fn null() -> Self {
|
||||||
|
let evt = helpers::OwnedEvent::new(
|
||||||
|
r_efi::efi::EVT_NOTIFY_WAIT,
|
||||||
|
r_efi::efi::TPL_CALLBACK,
|
||||||
|
Some(Self::empty_notify),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
reset: Self::null_reset,
|
||||||
|
read_key_stroke: Self::null_read_key,
|
||||||
|
wait_for_key: evt.into_raw(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "efiapi" fn null_reset(
|
||||||
|
_: *mut simple_text_input::Protocol,
|
||||||
|
_: r_efi::efi::Boolean,
|
||||||
|
) -> r_efi::efi::Status {
|
||||||
|
r_efi::efi::Status::SUCCESS
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "efiapi" fn null_read_key(
|
||||||
|
_: *mut simple_text_input::Protocol,
|
||||||
|
_: *mut simple_text_input::InputKey,
|
||||||
|
) -> r_efi::efi::Status {
|
||||||
|
r_efi::efi::Status::UNSUPPORTED
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "efiapi" fn empty_notify(_: r_efi::efi::Event, _: *mut crate::ffi::c_void) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for InputProtocol {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
// Close wait_for_key
|
||||||
|
unsafe {
|
||||||
|
let _ = helpers::OwnedEvent::from_raw(self.wait_for_key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn create_args(prog: &OsStr, args: &[OsString]) -> Box<[u16]> {
|
pub fn create_args(prog: &OsStr, args: &[OsString]) -> Box<[u16]> {
|
||||||
const QUOTE: u16 = 0x0022;
|
const QUOTE: u16 = 0x0022;
|
||||||
const SPACE: u16 = 0x0020;
|
const SPACE: u16 = 0x0020;
|
||||||
|
|
|
@ -142,9 +142,13 @@ impl io::Write for Stderr {
|
||||||
// UTF-16 character should occupy 4 bytes at most in UTF-8
|
// UTF-16 character should occupy 4 bytes at most in UTF-8
|
||||||
pub const STDIN_BUF_SIZE: usize = 4;
|
pub const STDIN_BUF_SIZE: usize = 4;
|
||||||
|
|
||||||
pub fn is_ebadf(_err: &io::Error) -> bool {
|
pub fn is_ebadf(err: &io::Error) -> bool {
|
||||||
|
if let Some(x) = err.raw_os_error() {
|
||||||
|
r_efi::efi::Status::UNSUPPORTED.as_usize() == x
|
||||||
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn panic_output() -> Option<impl io::Write> {
|
pub fn panic_output() -> Option<impl io::Write> {
|
||||||
uefi::env::try_system_table().map(|_| Stderr::new())
|
uefi::env::try_system_table().map(|_| Stderr::new())
|
||||||
|
|
|
@ -63,6 +63,24 @@ fn smoke_port_gone() {
|
||||||
assert!(tx.send(1).is_err());
|
assert!(tx.send(1).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn smoke_receiver_clone() {
|
||||||
|
let (tx, rx) = channel::<i32>();
|
||||||
|
let rx2 = rx.clone();
|
||||||
|
drop(rx);
|
||||||
|
tx.send(1).unwrap();
|
||||||
|
assert_eq!(rx2.recv().unwrap(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn smoke_receiver_clone_port_gone() {
|
||||||
|
let (tx, rx) = channel::<i32>();
|
||||||
|
let rx2 = rx.clone();
|
||||||
|
drop(rx);
|
||||||
|
drop(rx2);
|
||||||
|
assert!(tx.send(1).is_err());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn smoke_shared_port_gone() {
|
fn smoke_shared_port_gone() {
|
||||||
let (tx, rx) = channel::<i32>();
|
let (tx, rx) = channel::<i32>();
|
||||||
|
@ -124,6 +142,18 @@ fn chan_gone_concurrent() {
|
||||||
while rx.recv().is_ok() {}
|
while rx.recv().is_ok() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn receiver_cloning() {
|
||||||
|
let (tx, rx) = channel::<i32>();
|
||||||
|
let rx2 = rx.clone();
|
||||||
|
|
||||||
|
tx.send(1).unwrap();
|
||||||
|
tx.send(2).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(rx2.recv(), Ok(1));
|
||||||
|
assert_eq!(rx.recv(), Ok(2));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn stress() {
|
fn stress() {
|
||||||
let count = if cfg!(miri) { 100 } else { 10000 };
|
let count = if cfg!(miri) { 100 } else { 10000 };
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
use crate::core::build_steps::compile::{
|
use crate::core::build_steps::compile::{
|
||||||
add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo, std_crates_for_run_make,
|
add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo, std_crates_for_run_make,
|
||||||
};
|
};
|
||||||
use crate::core::build_steps::tool::{SourceType, prepare_tool_cargo};
|
use crate::core::build_steps::tool::{COMPILETEST_ALLOW_FEATURES, SourceType, prepare_tool_cargo};
|
||||||
use crate::core::builder::{
|
use crate::core::builder::{
|
||||||
self, Alias, Builder, Kind, RunConfig, ShouldRun, Step, crate_description,
|
self, Alias, Builder, Kind, RunConfig, ShouldRun, Step, crate_description,
|
||||||
};
|
};
|
||||||
|
@ -416,7 +416,7 @@ impl Step for Compiletest {
|
||||||
&[],
|
&[],
|
||||||
);
|
);
|
||||||
|
|
||||||
cargo.allow_features("test");
|
cargo.allow_features(COMPILETEST_ALLOW_FEATURES);
|
||||||
|
|
||||||
// For ./x.py clippy, don't run with --all-targets because
|
// For ./x.py clippy, don't run with --all-targets because
|
||||||
// linting tests and benchmarks can produce very noisy results
|
// linting tests and benchmarks can produce very noisy results
|
||||||
|
|
|
@ -15,7 +15,7 @@ use crate::core::build_steps::doc::DocumentationFormat;
|
||||||
use crate::core::build_steps::gcc::{Gcc, add_cg_gcc_cargo_flags};
|
use crate::core::build_steps::gcc::{Gcc, add_cg_gcc_cargo_flags};
|
||||||
use crate::core::build_steps::llvm::get_llvm_version;
|
use crate::core::build_steps::llvm::get_llvm_version;
|
||||||
use crate::core::build_steps::synthetic_targets::MirOptPanicAbortSyntheticTarget;
|
use crate::core::build_steps::synthetic_targets::MirOptPanicAbortSyntheticTarget;
|
||||||
use crate::core::build_steps::tool::{self, SourceType, Tool};
|
use crate::core::build_steps::tool::{self, COMPILETEST_ALLOW_FEATURES, SourceType, Tool};
|
||||||
use crate::core::build_steps::toolstate::ToolState;
|
use crate::core::build_steps::toolstate::ToolState;
|
||||||
use crate::core::build_steps::{compile, dist, llvm};
|
use crate::core::build_steps::{compile, dist, llvm};
|
||||||
use crate::core::builder::{
|
use crate::core::builder::{
|
||||||
|
@ -721,7 +721,7 @@ impl Step for CompiletestTest {
|
||||||
SourceType::InTree,
|
SourceType::InTree,
|
||||||
&[],
|
&[],
|
||||||
);
|
);
|
||||||
cargo.allow_features("test");
|
cargo.allow_features(COMPILETEST_ALLOW_FEATURES);
|
||||||
run_cargo_test(cargo, &[], &[], "compiletest self test", host, builder);
|
run_cargo_test(cargo, &[], &[], "compiletest self test", host, builder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -444,7 +444,11 @@ macro_rules! bootstrap_tool {
|
||||||
SourceType::InTree
|
SourceType::InTree
|
||||||
},
|
},
|
||||||
extra_features: vec![],
|
extra_features: vec![],
|
||||||
allow_features: concat!($($allow_features)*),
|
allow_features: {
|
||||||
|
let mut _value = "";
|
||||||
|
$( _value = $allow_features; )?
|
||||||
|
_value
|
||||||
|
},
|
||||||
cargo_args: vec![],
|
cargo_args: vec![],
|
||||||
artifact_kind: if false $(|| $artifact_kind == ToolArtifactKind::Library)* {
|
artifact_kind: if false $(|| $artifact_kind == ToolArtifactKind::Library)* {
|
||||||
ToolArtifactKind::Library
|
ToolArtifactKind::Library
|
||||||
|
@ -458,6 +462,8 @@ macro_rules! bootstrap_tool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) const COMPILETEST_ALLOW_FEATURES: &str = "test,internal_output_capture";
|
||||||
|
|
||||||
bootstrap_tool!(
|
bootstrap_tool!(
|
||||||
// This is marked as an external tool because it includes dependencies
|
// This is marked as an external tool because it includes dependencies
|
||||||
// from submodules. Trying to keep the lints in sync between all the repos
|
// from submodules. Trying to keep the lints in sync between all the repos
|
||||||
|
@ -468,7 +474,7 @@ bootstrap_tool!(
|
||||||
Tidy, "src/tools/tidy", "tidy";
|
Tidy, "src/tools/tidy", "tidy";
|
||||||
Linkchecker, "src/tools/linkchecker", "linkchecker";
|
Linkchecker, "src/tools/linkchecker", "linkchecker";
|
||||||
CargoTest, "src/tools/cargotest", "cargotest";
|
CargoTest, "src/tools/cargotest", "cargotest";
|
||||||
Compiletest, "src/tools/compiletest", "compiletest", is_unstable_tool = true, allow_features = "test";
|
Compiletest, "src/tools/compiletest", "compiletest", is_unstable_tool = true, allow_features = COMPILETEST_ALLOW_FEATURES;
|
||||||
BuildManifest, "src/tools/build-manifest", "build-manifest";
|
BuildManifest, "src/tools/build-manifest", "build-manifest";
|
||||||
RemoteTestClient, "src/tools/remote-test-client", "remote-test-client";
|
RemoteTestClient, "src/tools/remote-test-client", "remote-test-client";
|
||||||
RustInstaller, "src/tools/rust-installer", "rust-installer";
|
RustInstaller, "src/tools/rust-installer", "rust-installer";
|
||||||
|
@ -483,7 +489,8 @@ bootstrap_tool!(
|
||||||
GenerateCopyright, "src/tools/generate-copyright", "generate-copyright";
|
GenerateCopyright, "src/tools/generate-copyright", "generate-copyright";
|
||||||
SuggestTests, "src/tools/suggest-tests", "suggest-tests";
|
SuggestTests, "src/tools/suggest-tests", "suggest-tests";
|
||||||
GenerateWindowsSys, "src/tools/generate-windows-sys", "generate-windows-sys";
|
GenerateWindowsSys, "src/tools/generate-windows-sys", "generate-windows-sys";
|
||||||
RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test", is_unstable_tool = true, allow_features = "test";
|
// rustdoc-gui-test has a crate dependency on compiletest, so it needs the same unstable features.
|
||||||
|
RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test", is_unstable_tool = true, allow_features = COMPILETEST_ALLOW_FEATURES;
|
||||||
CoverageDump, "src/tools/coverage-dump", "coverage-dump";
|
CoverageDump, "src/tools/coverage-dump", "coverage-dump";
|
||||||
WasmComponentLd, "src/tools/wasm-component-ld", "wasm-component-ld", is_unstable_tool = true, allow_features = "min_specialization";
|
WasmComponentLd, "src/tools/wasm-component-ld", "wasm-component-ld", is_unstable_tool = true, allow_features = "min_specialization";
|
||||||
UnicodeTableGenerator, "src/tools/unicode-table-generator", "unicode-table-generator";
|
UnicodeTableGenerator, "src/tools/unicode-table-generator", "unicode-table-generator";
|
||||||
|
|
69
src/ci/docker/host-x86_64/x86_64-gnu-llvm-20/Dockerfile
Normal file
69
src/ci/docker/host-x86_64/x86_64-gnu-llvm-20/Dockerfile
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
FROM ubuntu:25.04
|
||||||
|
|
||||||
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
bzip2 \
|
||||||
|
g++ \
|
||||||
|
gcc-multilib \
|
||||||
|
make \
|
||||||
|
ninja-build \
|
||||||
|
file \
|
||||||
|
curl \
|
||||||
|
ca-certificates \
|
||||||
|
python3 \
|
||||||
|
git \
|
||||||
|
cmake \
|
||||||
|
sudo \
|
||||||
|
gdb \
|
||||||
|
llvm-20-tools \
|
||||||
|
llvm-20-dev \
|
||||||
|
libedit-dev \
|
||||||
|
libssl-dev \
|
||||||
|
pkg-config \
|
||||||
|
zlib1g-dev \
|
||||||
|
xz-utils \
|
||||||
|
nodejs \
|
||||||
|
mingw-w64 \
|
||||||
|
# libgccjit dependencies
|
||||||
|
flex \
|
||||||
|
libmpfr-dev \
|
||||||
|
libgmp-dev \
|
||||||
|
libmpc3 \
|
||||||
|
libmpc-dev \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Install powershell (universal package) so we can test x.ps1 on Linux
|
||||||
|
# FIXME: need a "universal" version that supports libicu74, but for now it still works to ignore that dep.
|
||||||
|
RUN curl -sL "https://github.com/PowerShell/PowerShell/releases/download/v7.3.1/powershell_7.3.1-1.deb_amd64.deb" > powershell.deb && \
|
||||||
|
dpkg --ignore-depends=libicu72 -i powershell.deb && \
|
||||||
|
rm -f powershell.deb
|
||||||
|
|
||||||
|
COPY scripts/sccache.sh /scripts/
|
||||||
|
RUN sh /scripts/sccache.sh
|
||||||
|
|
||||||
|
# We are disabling CI LLVM since this builder is intentionally using a host
|
||||||
|
# LLVM, rather than the typical src/llvm-project LLVM.
|
||||||
|
ENV NO_DOWNLOAD_CI_LLVM 1
|
||||||
|
ENV EXTERNAL_LLVM 1
|
||||||
|
|
||||||
|
# Using llvm-link-shared due to libffi issues -- see #34486
|
||||||
|
ENV RUST_CONFIGURE_ARGS \
|
||||||
|
--build=x86_64-unknown-linux-gnu \
|
||||||
|
--llvm-root=/usr/lib/llvm-20 \
|
||||||
|
--enable-llvm-link-shared \
|
||||||
|
--set rust.randomize-layout=true \
|
||||||
|
--set rust.thin-lto-import-instr-limit=10
|
||||||
|
|
||||||
|
COPY scripts/shared.sh /scripts/
|
||||||
|
|
||||||
|
ARG SCRIPT_ARG
|
||||||
|
|
||||||
|
COPY scripts/add_dummy_commit.sh /tmp/
|
||||||
|
COPY scripts/x86_64-gnu-llvm.sh /tmp/
|
||||||
|
COPY scripts/x86_64-gnu-llvm2.sh /tmp/
|
||||||
|
COPY scripts/x86_64-gnu-llvm3.sh /tmp/
|
||||||
|
COPY scripts/stage_2_test_set1.sh /tmp/
|
||||||
|
COPY scripts/stage_2_test_set2.sh /tmp/
|
||||||
|
|
||||||
|
ENV SCRIPT "/tmp/add_dummy_commit.sh && /tmp/${SCRIPT_ARG}"
|
|
@ -304,6 +304,31 @@ auto:
|
||||||
- name: x86_64-gnu-distcheck
|
- name: x86_64-gnu-distcheck
|
||||||
<<: *job-linux-8c
|
<<: *job-linux-8c
|
||||||
|
|
||||||
|
# The x86_64-gnu-llvm-20 job is split into multiple jobs to run tests in parallel.
|
||||||
|
# x86_64-gnu-llvm-20-1 skips tests that run in x86_64-gnu-llvm-20-{2,3}.
|
||||||
|
- name: x86_64-gnu-llvm-20-1
|
||||||
|
env:
|
||||||
|
RUST_BACKTRACE: 1
|
||||||
|
IMAGE: x86_64-gnu-llvm-20
|
||||||
|
DOCKER_SCRIPT: stage_2_test_set1.sh
|
||||||
|
<<: *job-linux-4c
|
||||||
|
|
||||||
|
# Skip tests that run in x86_64-gnu-llvm-20-{1,3}
|
||||||
|
- name: x86_64-gnu-llvm-20-2
|
||||||
|
env:
|
||||||
|
RUST_BACKTRACE: 1
|
||||||
|
IMAGE: x86_64-gnu-llvm-20
|
||||||
|
DOCKER_SCRIPT: x86_64-gnu-llvm2.sh
|
||||||
|
<<: *job-linux-4c
|
||||||
|
|
||||||
|
# Skip tests that run in x86_64-gnu-llvm-20-{1,2}
|
||||||
|
- name: x86_64-gnu-llvm-20-3
|
||||||
|
env:
|
||||||
|
RUST_BACKTRACE: 1
|
||||||
|
IMAGE: x86_64-gnu-llvm-20
|
||||||
|
DOCKER_SCRIPT: x86_64-gnu-llvm3.sh
|
||||||
|
<<: *job-linux-4c
|
||||||
|
|
||||||
# The x86_64-gnu-llvm-19 job is split into multiple jobs to run tests in parallel.
|
# The x86_64-gnu-llvm-19 job is split into multiple jobs to run tests in parallel.
|
||||||
# x86_64-gnu-llvm-19-1 skips tests that run in x86_64-gnu-llvm-19-{2,3}.
|
# x86_64-gnu-llvm-19-1 skips tests that run in x86_64-gnu-llvm-19-{2,3}.
|
||||||
- name: x86_64-gnu-llvm-19-1
|
- name: x86_64-gnu-llvm-19-1
|
||||||
|
|
|
@ -31,7 +31,6 @@ Term | Meaning
|
||||||
<span id="generics">generics</span> | The list of generic parameters defined on an item. There are three kinds of generic parameters: Type, lifetime and const parameters.
|
<span id="generics">generics</span> | The list of generic parameters defined on an item. There are three kinds of generic parameters: Type, lifetime and const parameters.
|
||||||
<span id="hir">HIR</span> | The _high-level [IR](#ir)_, created by lowering and desugaring the AST. ([see more](../hir.md))
|
<span id="hir">HIR</span> | The _high-level [IR](#ir)_, created by lowering and desugaring the AST. ([see more](../hir.md))
|
||||||
<span id="hir-id">`HirId`</span> | Identifies a particular node in the HIR by combining a def-id with an "intra-definition offset". See [the HIR chapter for more](../hir.md#identifiers-in-the-hir).
|
<span id="hir-id">`HirId`</span> | Identifies a particular node in the HIR by combining a def-id with an "intra-definition offset". See [the HIR chapter for more](../hir.md#identifiers-in-the-hir).
|
||||||
<span id="hir-map">HIR map</span> | The HIR map, accessible via `tcx.hir()`, allows you to quickly navigate the HIR and convert between various forms of identifiers.
|
|
||||||
<span id="ice">ICE</span> | Short for _internal compiler error_, this is when the compiler crashes.
|
<span id="ice">ICE</span> | Short for _internal compiler error_, this is when the compiler crashes.
|
||||||
<span id="ich">ICH</span> | Short for _incremental compilation hash_, these are used as fingerprints for things such as HIR and crate metadata, to check if changes have been made. This is useful in incremental compilation to see if part of a crate has changed and should be recompiled.
|
<span id="ich">ICH</span> | Short for _incremental compilation hash_, these are used as fingerprints for things such as HIR and crate metadata, to check if changes have been made. This is useful in incremental compilation to see if part of a crate has changed and should be recompiled.
|
||||||
<span id="infcx">`infcx`</span> | The type inference context (`InferCtxt`). (see `rustc_middle::infer`)
|
<span id="infcx">`infcx`</span> | The type inference context (`InferCtxt`). (see `rustc_middle::infer`)
|
||||||
|
|
|
@ -100,7 +100,7 @@ The HIR uses a bunch of different identifiers that coexist and serve different p
|
||||||
a wrapper around a [`HirId`]. For more info about HIR bodies, please refer to the
|
a wrapper around a [`HirId`]. For more info about HIR bodies, please refer to the
|
||||||
[HIR chapter][hir-bodies].
|
[HIR chapter][hir-bodies].
|
||||||
|
|
||||||
These identifiers can be converted into one another through the [HIR map][map].
|
These identifiers can be converted into one another through the `TyCtxt`.
|
||||||
|
|
||||||
[`DefId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.DefId.html
|
[`DefId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.DefId.html
|
||||||
[`LocalDefId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.LocalDefId.html
|
[`LocalDefId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.LocalDefId.html
|
||||||
|
@ -110,30 +110,24 @@ These identifiers can be converted into one another through the [HIR map][map].
|
||||||
[`CrateNum`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.CrateNum.html
|
[`CrateNum`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.CrateNum.html
|
||||||
[`DefIndex`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.DefIndex.html
|
[`DefIndex`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.DefIndex.html
|
||||||
[`Body`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.Body.html
|
[`Body`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.Body.html
|
||||||
[hir-map]: ./hir.md#the-hir-map
|
|
||||||
[hir-bodies]: ./hir.md#hir-bodies
|
[hir-bodies]: ./hir.md#hir-bodies
|
||||||
[map]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html
|
|
||||||
|
|
||||||
## The HIR Map
|
## HIR Operations
|
||||||
|
|
||||||
Most of the time when you are working with the HIR, you will do so via
|
Most of the time when you are working with the HIR, you will do so via
|
||||||
the **HIR Map**, accessible in the tcx via [`tcx.hir()`] (and defined in
|
`TyCtxt`. It contains a number of methods, defined in the `hir::map` module and
|
||||||
the [`hir::map`] module). The [HIR map] contains a [number of methods] to
|
mostly prefixed with `hir_`, to convert between IDs of various kinds and to
|
||||||
convert between IDs of various kinds and to lookup data associated
|
lookup data associated with a HIR node.
|
||||||
with a HIR node.
|
|
||||||
|
|
||||||
[`tcx.hir()`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.hir
|
[`TyCtxt`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html
|
||||||
[`hir::map`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/index.html
|
|
||||||
[HIR map]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html
|
|
||||||
[number of methods]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#methods
|
|
||||||
|
|
||||||
For example, if you have a [`LocalDefId`], and you would like to convert it
|
For example, if you have a [`LocalDefId`], and you would like to convert it
|
||||||
to a [`HirId`], you can use [`tcx.hir().local_def_id_to_hir_id(def_id)`][local_def_id_to_hir_id].
|
to a [`HirId`], you can use [`tcx.local_def_id_to_hir_id(def_id)`][local_def_id_to_hir_id].
|
||||||
You need a `LocalDefId`, rather than a `DefId`, since only local items have HIR nodes.
|
You need a `LocalDefId`, rather than a `DefId`, since only local items have HIR nodes.
|
||||||
|
|
||||||
[local_def_id_to_hir_id]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.local_def_id_to_hir_id
|
[local_def_id_to_hir_id]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.local_def_id_to_hir_id
|
||||||
|
|
||||||
Similarly, you can use [`tcx.hir().find(n)`][find] to lookup the node for a
|
Similarly, you can use [`tcx.hir_node(n)`][hir_node] to lookup the node for a
|
||||||
[`HirId`]. This returns a `Option<Node<'hir>>`, where [`Node`] is an enum
|
[`HirId`]. This returns a `Option<Node<'hir>>`, where [`Node`] is an enum
|
||||||
defined in the map. By matching on this, you can find out what sort of
|
defined in the map. By matching on this, you can find out what sort of
|
||||||
node the `HirId` referred to and also get a pointer to the data
|
node the `HirId` referred to and also get a pointer to the data
|
||||||
|
@ -142,15 +136,16 @@ that `n` must be some HIR expression, you can do
|
||||||
[`tcx.hir_expect_expr(n)`][expect_expr], which will extract and return the
|
[`tcx.hir_expect_expr(n)`][expect_expr], which will extract and return the
|
||||||
[`&hir::Expr`][Expr], panicking if `n` is not in fact an expression.
|
[`&hir::Expr`][Expr], panicking if `n` is not in fact an expression.
|
||||||
|
|
||||||
[find]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.find
|
[hir_node]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.hir_node
|
||||||
[`Node`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.Node.html
|
[`Node`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.Node.html
|
||||||
[expect_expr]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.expect_expr
|
[expect_expr]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.expect_expr
|
||||||
[Expr]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.Expr.html
|
[Expr]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.Expr.html
|
||||||
|
|
||||||
Finally, you can use the HIR map to find the parents of nodes, via
|
Finally, you can find the parents of nodes, via
|
||||||
calls like [`tcx.hir().get_parent(n)`][get_parent].
|
calls like [`tcx.parent_hir_node(n)`][parent_hir_node].
|
||||||
|
|
||||||
|
[get_parent_item]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.parent_hir_node
|
||||||
|
|
||||||
[get_parent]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.get_parent
|
|
||||||
|
|
||||||
## HIR Bodies
|
## HIR Bodies
|
||||||
|
|
||||||
|
@ -158,10 +153,10 @@ A [`rustc_hir::Body`] represents some kind of executable code, such as the body
|
||||||
of a function/closure or the definition of a constant. Bodies are
|
of a function/closure or the definition of a constant. Bodies are
|
||||||
associated with an **owner**, which is typically some kind of item
|
associated with an **owner**, which is typically some kind of item
|
||||||
(e.g. an `fn()` or `const`), but could also be a closure expression
|
(e.g. an `fn()` or `const`), but could also be a closure expression
|
||||||
(e.g. `|x, y| x + y`). You can use the HIR map to find the body
|
(e.g. `|x, y| x + y`). You can use the `TyCtxt` to find the body
|
||||||
associated with a given def-id ([`maybe_body_owned_by`]) or to find
|
associated with a given def-id ([`hir_maybe_body_owned_by`]) or to find
|
||||||
the owner of a body ([`body_owner_def_id`]).
|
the owner of a body ([`hir_body_owner_def_id`]).
|
||||||
|
|
||||||
[`rustc_hir::Body`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.Body.html
|
[`rustc_hir::Body`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.Body.html
|
||||||
[`maybe_body_owned_by`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.maybe_body_owned_by
|
[`hir_maybe_body_owned_by`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.hir_maybe_body_owned_by
|
||||||
[`body_owner_def_id`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.body_owner_def_id
|
[`hir_body_owner_def_id`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.hir_body_owner_def_id
|
||||||
|
|
|
@ -490,17 +490,17 @@ pub(crate) fn build_impl(
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if let Some(associated_trait) = associated_trait {
|
if let Some(associated_trait) = associated_trait {
|
||||||
let assoc_kind = match item.kind {
|
let assoc_tag = match item.kind {
|
||||||
hir::ImplItemKind::Const(..) => ty::AssocKind::Const,
|
hir::ImplItemKind::Const(..) => ty::AssocTag::Const,
|
||||||
hir::ImplItemKind::Fn(..) => ty::AssocKind::Fn,
|
hir::ImplItemKind::Fn(..) => ty::AssocTag::Fn,
|
||||||
hir::ImplItemKind::Type(..) => ty::AssocKind::Type,
|
hir::ImplItemKind::Type(..) => ty::AssocTag::Type,
|
||||||
};
|
};
|
||||||
let trait_item = tcx
|
let trait_item = tcx
|
||||||
.associated_items(associated_trait.def_id)
|
.associated_items(associated_trait.def_id)
|
||||||
.find_by_ident_and_kind(
|
.find_by_ident_and_kind(
|
||||||
tcx,
|
tcx,
|
||||||
item.ident,
|
item.ident,
|
||||||
assoc_kind,
|
assoc_tag,
|
||||||
associated_trait.def_id,
|
associated_trait.def_id,
|
||||||
)
|
)
|
||||||
.unwrap(); // SAFETY: For all impl items there exists trait item that has the same name.
|
.unwrap(); // SAFETY: For all impl items there exists trait item that has the same name.
|
||||||
|
@ -527,7 +527,7 @@ pub(crate) fn build_impl(
|
||||||
.find_by_ident_and_kind(
|
.find_by_ident_and_kind(
|
||||||
tcx,
|
tcx,
|
||||||
item.ident(tcx),
|
item.ident(tcx),
|
||||||
item.kind,
|
item.as_tag(),
|
||||||
associated_trait.def_id,
|
associated_trait.def_id,
|
||||||
)
|
)
|
||||||
.unwrap(); // corresponding associated item has to exist
|
.unwrap(); // corresponding associated item has to exist
|
||||||
|
|
|
@ -521,7 +521,7 @@ fn projection_to_path_segment<'tcx>(
|
||||||
let item = cx.tcx.associated_item(def_id);
|
let item = cx.tcx.associated_item(def_id);
|
||||||
let generics = cx.tcx.generics_of(def_id);
|
let generics = cx.tcx.generics_of(def_id);
|
||||||
PathSegment {
|
PathSegment {
|
||||||
name: item.name,
|
name: item.name(),
|
||||||
args: GenericArgs::AngleBracketed {
|
args: GenericArgs::AngleBracketed {
|
||||||
args: clean_middle_generic_args(
|
args: clean_middle_generic_args(
|
||||||
cx,
|
cx,
|
||||||
|
@ -1340,7 +1340,7 @@ pub(crate) fn clean_impl_item<'tcx>(
|
||||||
pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocContext<'_>) -> Item {
|
pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocContext<'_>) -> Item {
|
||||||
let tcx = cx.tcx;
|
let tcx = cx.tcx;
|
||||||
let kind = match assoc_item.kind {
|
let kind = match assoc_item.kind {
|
||||||
ty::AssocKind::Const => {
|
ty::AssocKind::Const { .. } => {
|
||||||
let ty = clean_middle_ty(
|
let ty = clean_middle_ty(
|
||||||
ty::Binder::dummy(tcx.type_of(assoc_item.def_id).instantiate_identity()),
|
ty::Binder::dummy(tcx.type_of(assoc_item.def_id).instantiate_identity()),
|
||||||
cx,
|
cx,
|
||||||
|
@ -1374,10 +1374,10 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::AssocKind::Fn => {
|
ty::AssocKind::Fn { has_self, .. } => {
|
||||||
let mut item = inline::build_function(cx, assoc_item.def_id);
|
let mut item = inline::build_function(cx, assoc_item.def_id);
|
||||||
|
|
||||||
if assoc_item.fn_has_self_parameter {
|
if has_self {
|
||||||
let self_ty = match assoc_item.container {
|
let self_ty = match assoc_item.container {
|
||||||
ty::AssocItemContainer::Impl => {
|
ty::AssocItemContainer::Impl => {
|
||||||
tcx.type_of(assoc_item.container_id(tcx)).instantiate_identity()
|
tcx.type_of(assoc_item.container_id(tcx)).instantiate_identity()
|
||||||
|
@ -1412,8 +1412,8 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo
|
||||||
RequiredMethodItem(item)
|
RequiredMethodItem(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::AssocKind::Type => {
|
ty::AssocKind::Type { .. } => {
|
||||||
let my_name = assoc_item.name;
|
let my_name = assoc_item.name();
|
||||||
|
|
||||||
fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool {
|
fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool {
|
||||||
match (¶m.kind, arg) {
|
match (¶m.kind, arg) {
|
||||||
|
@ -1554,7 +1554,7 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Item::from_def_id_and_parts(assoc_item.def_id, Some(assoc_item.name), kind, cx)
|
Item::from_def_id_and_parts(assoc_item.def_id, Some(assoc_item.name()), kind, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn first_non_private_clean_path<'tcx>(
|
fn first_non_private_clean_path<'tcx>(
|
||||||
|
@ -2223,7 +2223,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
|
||||||
|
|
||||||
Type::QPath(Box::new(QPathData {
|
Type::QPath(Box::new(QPathData {
|
||||||
assoc: PathSegment {
|
assoc: PathSegment {
|
||||||
name: cx.tcx.associated_item(def_id).name,
|
name: cx.tcx.associated_item(def_id).name(),
|
||||||
args: GenericArgs::AngleBracketed {
|
args: GenericArgs::AngleBracketed {
|
||||||
args: clean_middle_generic_args(
|
args: clean_middle_generic_args(
|
||||||
cx,
|
cx,
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue