Auto merge of #107318 - matthiaskrgr:rollup-776kd81, r=matthiaskrgr
Rollup of 9 pull requests Successful merges: - #97373 (impl DispatchFromDyn for Cell and UnsafeCell) - #106625 (Remove backwards compat for LLVM 12 coverage format) - #106779 (Avoid __cxa_thread_atexit_impl on Emscripten) - #106811 (Append .dwp to the binary filename instead of replacing the existing extension.) - #106836 (Remove optimistic spinning from `mpsc::SyncSender`) - #106946 (implement Hash for proc_macro::LineColumn) - #107074 (remove unnecessary check for opaque types) - #107287 (Improve fn pointer notes) - #107304 (Use `can_eq` to compare types for default assoc type error) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
40fda7b3fe
28 changed files with 942 additions and 732 deletions
|
@ -1,6 +1,5 @@
|
||||||
use crate::common::CodegenCx;
|
use crate::common::CodegenCx;
|
||||||
use crate::coverageinfo;
|
use crate::coverageinfo;
|
||||||
use crate::errors::InstrumentCoverageRequiresLLVM12;
|
|
||||||
use crate::llvm;
|
use crate::llvm;
|
||||||
|
|
||||||
use llvm::coverageinfo::CounterMappingRegion;
|
use llvm::coverageinfo::CounterMappingRegion;
|
||||||
|
@ -19,8 +18,8 @@ use std::ffi::CString;
|
||||||
|
|
||||||
/// Generates and exports the Coverage Map.
|
/// Generates and exports the Coverage Map.
|
||||||
///
|
///
|
||||||
/// Rust Coverage Map generation supports LLVM Coverage Mapping Format versions
|
/// Rust Coverage Map generation supports LLVM Coverage Mapping Format version
|
||||||
/// 5 (LLVM 12, only) and 6 (zero-based encoded as 4 and 5, respectively), as defined at
|
/// 6 (zero-based encoded as 5), as defined at
|
||||||
/// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format).
|
/// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format).
|
||||||
/// These versions are supported by the LLVM coverage tools (`llvm-profdata` and `llvm-cov`)
|
/// These versions are supported by the LLVM coverage tools (`llvm-profdata` and `llvm-cov`)
|
||||||
/// bundled with Rust's fork of LLVM.
|
/// bundled with Rust's fork of LLVM.
|
||||||
|
@ -33,13 +32,10 @@ use std::ffi::CString;
|
||||||
pub fn finalize(cx: &CodegenCx<'_, '_>) {
|
pub fn finalize(cx: &CodegenCx<'_, '_>) {
|
||||||
let tcx = cx.tcx;
|
let tcx = cx.tcx;
|
||||||
|
|
||||||
// Ensure the installed version of LLVM supports at least Coverage Map
|
// Ensure the installed version of LLVM supports Coverage Map Version 6
|
||||||
// Version 5 (encoded as a zero-based value: 4), which was introduced with
|
// (encoded as a zero-based value: 5), which was introduced with LLVM 13.
|
||||||
// LLVM 12.
|
|
||||||
let version = coverageinfo::mapping_version();
|
let version = coverageinfo::mapping_version();
|
||||||
if version < 4 {
|
assert_eq!(version, 5, "The `CoverageMappingVersion` exposed by `llvm-wrapper` is out of sync");
|
||||||
tcx.sess.emit_fatal(InstrumentCoverageRequiresLLVM12);
|
|
||||||
}
|
|
||||||
|
|
||||||
debug!("Generating coverage map for CodegenUnit: `{}`", cx.codegen_unit.name());
|
debug!("Generating coverage map for CodegenUnit: `{}`", cx.codegen_unit.name());
|
||||||
|
|
||||||
|
@ -61,7 +57,7 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut mapgen = CoverageMapGenerator::new(tcx, version);
|
let mut mapgen = CoverageMapGenerator::new(tcx);
|
||||||
|
|
||||||
// Encode coverage mappings and generate function records
|
// Encode coverage mappings and generate function records
|
||||||
let mut function_data = Vec::new();
|
let mut function_data = Vec::new();
|
||||||
|
@ -124,25 +120,18 @@ struct CoverageMapGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CoverageMapGenerator {
|
impl CoverageMapGenerator {
|
||||||
fn new(tcx: TyCtxt<'_>, version: u32) -> Self {
|
fn new(tcx: TyCtxt<'_>) -> Self {
|
||||||
let mut filenames = FxIndexSet::default();
|
let mut filenames = FxIndexSet::default();
|
||||||
if version >= 5 {
|
|
||||||
// LLVM Coverage Mapping Format version 6 (zero-based encoded as 5)
|
// LLVM Coverage Mapping Format version 6 (zero-based encoded as 5)
|
||||||
// requires setting the first filename to the compilation directory.
|
// requires setting the first filename to the compilation directory.
|
||||||
// Since rustc generates coverage maps with relative paths, the
|
// Since rustc generates coverage maps with relative paths, the
|
||||||
// compilation directory can be combined with the relative paths
|
// compilation directory can be combined with the relative paths
|
||||||
// to get absolute paths, if needed.
|
// to get absolute paths, if needed.
|
||||||
let working_dir = tcx
|
let working_dir =
|
||||||
.sess
|
tcx.sess.opts.working_dir.remapped_path_if_available().to_string_lossy().to_string();
|
||||||
.opts
|
|
||||||
.working_dir
|
|
||||||
.remapped_path_if_available()
|
|
||||||
.to_string_lossy()
|
|
||||||
.to_string();
|
|
||||||
let c_filename =
|
let c_filename =
|
||||||
CString::new(working_dir).expect("null error converting filename to C string");
|
CString::new(working_dir).expect("null error converting filename to C string");
|
||||||
filenames.insert(c_filename);
|
filenames.insert(c_filename);
|
||||||
}
|
|
||||||
Self { filenames }
|
Self { filenames }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,10 +39,6 @@ pub(crate) struct ErrorCreatingImportLibrary<'a> {
|
||||||
pub error: String,
|
pub error: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
|
||||||
#[diag(codegen_llvm_instrument_coverage_requires_llvm_12)]
|
|
||||||
pub(crate) struct InstrumentCoverageRequiresLLVM12;
|
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(codegen_llvm_symbol_already_defined)]
|
#[diag(codegen_llvm_symbol_already_defined)]
|
||||||
pub(crate) struct SymbolAlreadyDefined<'a> {
|
pub(crate) struct SymbolAlreadyDefined<'a> {
|
||||||
|
|
|
@ -599,7 +599,8 @@ fn link_dwarf_object<'a>(
|
||||||
cg_results: &CodegenResults,
|
cg_results: &CodegenResults,
|
||||||
executable_out_filename: &Path,
|
executable_out_filename: &Path,
|
||||||
) {
|
) {
|
||||||
let dwp_out_filename = executable_out_filename.with_extension("dwp");
|
let mut dwp_out_filename = executable_out_filename.to_path_buf().into_os_string();
|
||||||
|
dwp_out_filename.push(".dwp");
|
||||||
debug!(?dwp_out_filename, ?executable_out_filename);
|
debug!(?dwp_out_filename, ?executable_out_filename);
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|
|
@ -13,7 +13,7 @@ use rustc_middle::mir::{
|
||||||
ProjectionElem, RetagKind, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind,
|
ProjectionElem, RetagKind, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind,
|
||||||
Terminator, TerminatorKind, UnOp, START_BLOCK,
|
Terminator, TerminatorKind, UnOp, START_BLOCK,
|
||||||
};
|
};
|
||||||
use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitable};
|
use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt};
|
||||||
use rustc_mir_dataflow::impls::MaybeStorageLive;
|
use rustc_mir_dataflow::impls::MaybeStorageLive;
|
||||||
use rustc_mir_dataflow::storage::always_storage_live_locals;
|
use rustc_mir_dataflow::storage::always_storage_live_locals;
|
||||||
use rustc_mir_dataflow::{Analysis, ResultsCursor};
|
use rustc_mir_dataflow::{Analysis, ResultsCursor};
|
||||||
|
@ -230,11 +230,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
// Equal types, all is good.
|
// Equal types, all is good.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// Normalization reveals opaque types, but we may be validating MIR while computing
|
|
||||||
// said opaque types, causing cycles.
|
|
||||||
if (src, dest).has_opaque_types() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
crate::util::is_subtype(self.tcx, self.param_env, src, dest)
|
crate::util::is_subtype(self.tcx, self.param_env, src, dest)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,9 +11,6 @@ codegen_llvm_unknown_ctarget_feature_prefix =
|
||||||
codegen_llvm_error_creating_import_library =
|
codegen_llvm_error_creating_import_library =
|
||||||
Error creating import library for {$lib_name}: {$error}
|
Error creating import library for {$lib_name}: {$error}
|
||||||
|
|
||||||
codegen_llvm_instrument_coverage_requires_llvm_12 =
|
|
||||||
rustc option `-C instrument-coverage` requires LLVM 12 or higher.
|
|
||||||
|
|
||||||
codegen_llvm_symbol_already_defined =
|
codegen_llvm_symbol_already_defined =
|
||||||
symbol `{$symbol_name}` is already defined
|
symbol `{$symbol_name}` is already defined
|
||||||
|
|
||||||
|
|
|
@ -79,6 +79,7 @@ use std::path::PathBuf;
|
||||||
use std::{cmp, fmt, iter};
|
use std::{cmp, fmt, iter};
|
||||||
|
|
||||||
mod note;
|
mod note;
|
||||||
|
mod note_and_explain;
|
||||||
mod suggest;
|
mod suggest;
|
||||||
|
|
||||||
pub(crate) mod need_type_info;
|
pub(crate) mod need_type_info;
|
||||||
|
@ -1846,7 +1847,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.check_and_note_conflicting_crates(diag, terr);
|
self.check_and_note_conflicting_crates(diag, terr);
|
||||||
self.tcx.note_and_explain_type_err(diag, terr, cause, span, cause.body_id.to_def_id());
|
|
||||||
|
self.note_and_explain_type_err(diag, terr, cause, span, cause.body_id.to_def_id());
|
||||||
|
|
||||||
if let Some(ValuePairs::PolyTraitRefs(exp_found)) = values
|
if let Some(ValuePairs::PolyTraitRefs(exp_found)) = values
|
||||||
&& let ty::Closure(def_id, _) = exp_found.expected.skip_binder().self_ty().kind()
|
&& let ty::Closure(def_id, _) = exp_found.expected.skip_binder().self_ty().kind()
|
||||||
|
|
|
@ -0,0 +1,654 @@
|
||||||
|
use super::TypeErrCtxt;
|
||||||
|
use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
|
||||||
|
use rustc_errors::{pluralize, Diagnostic, MultiSpan};
|
||||||
|
use rustc_hir::{self as hir, def::DefKind};
|
||||||
|
use rustc_middle::traits::ObligationCauseCode;
|
||||||
|
use rustc_middle::ty::error::ExpectedFound;
|
||||||
|
use rustc_middle::ty::print::Printer;
|
||||||
|
use rustc_middle::{
|
||||||
|
traits::ObligationCause,
|
||||||
|
ty::{self, error::TypeError, print::FmtPrinter, suggest_constraining_type_param, Ty},
|
||||||
|
};
|
||||||
|
use rustc_span::{def_id::DefId, sym, BytePos, Span, Symbol};
|
||||||
|
|
||||||
|
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||||
|
pub fn note_and_explain_type_err(
|
||||||
|
&self,
|
||||||
|
diag: &mut Diagnostic,
|
||||||
|
err: TypeError<'tcx>,
|
||||||
|
cause: &ObligationCause<'tcx>,
|
||||||
|
sp: Span,
|
||||||
|
body_owner_def_id: DefId,
|
||||||
|
) {
|
||||||
|
use ty::error::TypeError::*;
|
||||||
|
debug!("note_and_explain_type_err err={:?} cause={:?}", err, cause);
|
||||||
|
|
||||||
|
let tcx = self.tcx;
|
||||||
|
|
||||||
|
match err {
|
||||||
|
ArgumentSorts(values, _) | Sorts(values) => {
|
||||||
|
match (values.expected.kind(), values.found.kind()) {
|
||||||
|
(ty::Closure(..), ty::Closure(..)) => {
|
||||||
|
diag.note("no two closures, even if identical, have the same type");
|
||||||
|
diag.help("consider boxing your closure and/or using it as a trait object");
|
||||||
|
}
|
||||||
|
(ty::Alias(ty::Opaque, ..), ty::Alias(ty::Opaque, ..)) => {
|
||||||
|
// Issue #63167
|
||||||
|
diag.note("distinct uses of `impl Trait` result in different opaque types");
|
||||||
|
}
|
||||||
|
(ty::Float(_), ty::Infer(ty::IntVar(_)))
|
||||||
|
if let Ok(
|
||||||
|
// Issue #53280
|
||||||
|
snippet,
|
||||||
|
) = tcx.sess.source_map().span_to_snippet(sp) =>
|
||||||
|
{
|
||||||
|
if snippet.chars().all(|c| c.is_digit(10) || c == '-' || c == '_') {
|
||||||
|
diag.span_suggestion(
|
||||||
|
sp,
|
||||||
|
"use a float literal",
|
||||||
|
format!("{}.0", snippet),
|
||||||
|
MachineApplicable,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(ty::Param(expected), ty::Param(found)) => {
|
||||||
|
let generics = tcx.generics_of(body_owner_def_id);
|
||||||
|
let e_span = tcx.def_span(generics.type_param(expected, tcx).def_id);
|
||||||
|
if !sp.contains(e_span) {
|
||||||
|
diag.span_label(e_span, "expected type parameter");
|
||||||
|
}
|
||||||
|
let f_span = tcx.def_span(generics.type_param(found, tcx).def_id);
|
||||||
|
if !sp.contains(f_span) {
|
||||||
|
diag.span_label(f_span, "found type parameter");
|
||||||
|
}
|
||||||
|
diag.note(
|
||||||
|
"a type parameter was expected, but a different one was found; \
|
||||||
|
you might be missing a type parameter or trait bound",
|
||||||
|
);
|
||||||
|
diag.note(
|
||||||
|
"for more information, visit \
|
||||||
|
https://doc.rust-lang.org/book/ch10-02-traits.html\
|
||||||
|
#traits-as-parameters",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
(ty::Alias(ty::Projection, _), ty::Alias(ty::Projection, _)) => {
|
||||||
|
diag.note("an associated type was expected, but a different one was found");
|
||||||
|
}
|
||||||
|
(ty::Param(p), ty::Alias(ty::Projection, proj)) | (ty::Alias(ty::Projection, proj), ty::Param(p))
|
||||||
|
if tcx.def_kind(proj.def_id) != DefKind::ImplTraitPlaceholder =>
|
||||||
|
{
|
||||||
|
let generics = tcx.generics_of(body_owner_def_id);
|
||||||
|
let p_span = tcx.def_span(generics.type_param(p, tcx).def_id);
|
||||||
|
if !sp.contains(p_span) {
|
||||||
|
diag.span_label(p_span, "this type parameter");
|
||||||
|
}
|
||||||
|
let hir = tcx.hir();
|
||||||
|
let mut note = true;
|
||||||
|
if let Some(generics) = generics
|
||||||
|
.type_param(p, tcx)
|
||||||
|
.def_id
|
||||||
|
.as_local()
|
||||||
|
.map(|id| hir.local_def_id_to_hir_id(id))
|
||||||
|
.and_then(|id| tcx.hir().find_parent(id))
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|node| node.generics())
|
||||||
|
{
|
||||||
|
// Synthesize the associated type restriction `Add<Output = Expected>`.
|
||||||
|
// FIXME: extract this logic for use in other diagnostics.
|
||||||
|
let (trait_ref, assoc_substs) = proj.trait_ref_and_own_substs(tcx);
|
||||||
|
let path =
|
||||||
|
tcx.def_path_str_with_substs(trait_ref.def_id, trait_ref.substs);
|
||||||
|
let item_name = tcx.item_name(proj.def_id);
|
||||||
|
let item_args = self.format_generic_args(assoc_substs);
|
||||||
|
|
||||||
|
let path = if path.ends_with('>') {
|
||||||
|
format!(
|
||||||
|
"{}, {}{} = {}>",
|
||||||
|
&path[..path.len() - 1],
|
||||||
|
item_name,
|
||||||
|
item_args,
|
||||||
|
p
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
format!("{}<{}{} = {}>", path, item_name, item_args, p)
|
||||||
|
};
|
||||||
|
note = !suggest_constraining_type_param(
|
||||||
|
tcx,
|
||||||
|
generics,
|
||||||
|
diag,
|
||||||
|
&format!("{}", proj.self_ty()),
|
||||||
|
&path,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if note {
|
||||||
|
diag.note("you might be missing a type parameter or trait bound");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(ty::Param(p), ty::Dynamic(..) | ty::Alias(ty::Opaque, ..))
|
||||||
|
| (ty::Dynamic(..) | ty::Alias(ty::Opaque, ..), ty::Param(p)) => {
|
||||||
|
let generics = tcx.generics_of(body_owner_def_id);
|
||||||
|
let p_span = tcx.def_span(generics.type_param(p, tcx).def_id);
|
||||||
|
if !sp.contains(p_span) {
|
||||||
|
diag.span_label(p_span, "this type parameter");
|
||||||
|
}
|
||||||
|
diag.help("type parameters must be constrained to match other types");
|
||||||
|
if tcx.sess.teach(&diag.get_code().unwrap()) {
|
||||||
|
diag.help(
|
||||||
|
"given a type parameter `T` and a method `foo`:
|
||||||
|
```
|
||||||
|
trait Trait<T> { fn foo(&tcx) -> T; }
|
||||||
|
```
|
||||||
|
the only ways to implement method `foo` are:
|
||||||
|
- constrain `T` with an explicit type:
|
||||||
|
```
|
||||||
|
impl Trait<String> for X {
|
||||||
|
fn foo(&tcx) -> String { String::new() }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- add a trait bound to `T` and call a method on that trait that returns `Self`:
|
||||||
|
```
|
||||||
|
impl<T: std::default::Default> Trait<T> for X {
|
||||||
|
fn foo(&tcx) -> T { <T as std::default::Default>::default() }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- change `foo` to return an argument of type `T`:
|
||||||
|
```
|
||||||
|
impl<T> Trait<T> for X {
|
||||||
|
fn foo(&tcx, x: T) -> T { x }
|
||||||
|
}
|
||||||
|
```",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
diag.note(
|
||||||
|
"for more information, visit \
|
||||||
|
https://doc.rust-lang.org/book/ch10-02-traits.html\
|
||||||
|
#traits-as-parameters",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
(ty::Param(p), ty::Closure(..) | ty::Generator(..)) => {
|
||||||
|
let generics = tcx.generics_of(body_owner_def_id);
|
||||||
|
let p_span = tcx.def_span(generics.type_param(p, tcx).def_id);
|
||||||
|
if !sp.contains(p_span) {
|
||||||
|
diag.span_label(p_span, "this type parameter");
|
||||||
|
}
|
||||||
|
diag.help(&format!(
|
||||||
|
"every closure has a distinct type and so could not always match the \
|
||||||
|
caller-chosen type of parameter `{}`",
|
||||||
|
p
|
||||||
|
));
|
||||||
|
}
|
||||||
|
(ty::Param(p), _) | (_, ty::Param(p)) => {
|
||||||
|
let generics = tcx.generics_of(body_owner_def_id);
|
||||||
|
let p_span = tcx.def_span(generics.type_param(p, tcx).def_id);
|
||||||
|
if !sp.contains(p_span) {
|
||||||
|
diag.span_label(p_span, "this type parameter");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(ty::Alias(ty::Projection, proj_ty), _) if tcx.def_kind(proj_ty.def_id) != DefKind::ImplTraitPlaceholder => {
|
||||||
|
self.expected_projection(
|
||||||
|
diag,
|
||||||
|
proj_ty,
|
||||||
|
values,
|
||||||
|
body_owner_def_id,
|
||||||
|
cause.code(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
(_, ty::Alias(ty::Projection, proj_ty)) if tcx.def_kind(proj_ty.def_id) != DefKind::ImplTraitPlaceholder => {
|
||||||
|
let msg = format!(
|
||||||
|
"consider constraining the associated type `{}` to `{}`",
|
||||||
|
values.found, values.expected,
|
||||||
|
);
|
||||||
|
if !(self.suggest_constraining_opaque_associated_type(
|
||||||
|
diag,
|
||||||
|
&msg,
|
||||||
|
proj_ty,
|
||||||
|
values.expected,
|
||||||
|
) || self.suggest_constraint(
|
||||||
|
diag,
|
||||||
|
&msg,
|
||||||
|
body_owner_def_id,
|
||||||
|
proj_ty,
|
||||||
|
values.expected,
|
||||||
|
)) {
|
||||||
|
diag.help(&msg);
|
||||||
|
diag.note(
|
||||||
|
"for more information, visit \
|
||||||
|
https://doc.rust-lang.org/book/ch19-03-advanced-traits.html",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
debug!(
|
||||||
|
"note_and_explain_type_err expected={:?} ({:?}) found={:?} ({:?})",
|
||||||
|
values.expected,
|
||||||
|
values.expected.kind(),
|
||||||
|
values.found,
|
||||||
|
values.found.kind(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
CyclicTy(ty) => {
|
||||||
|
// Watch out for various cases of cyclic types and try to explain.
|
||||||
|
if ty.is_closure() || ty.is_generator() {
|
||||||
|
diag.note(
|
||||||
|
"closures cannot capture themselves or take themselves as argument;\n\
|
||||||
|
this error may be the result of a recent compiler bug-fix,\n\
|
||||||
|
see issue #46062 <https://github.com/rust-lang/rust/issues/46062>\n\
|
||||||
|
for more information",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TargetFeatureCast(def_id) => {
|
||||||
|
let target_spans = tcx.get_attrs(def_id, sym::target_feature).map(|attr| attr.span);
|
||||||
|
diag.note(
|
||||||
|
"functions with `#[target_feature]` can only be coerced to `unsafe` function pointers"
|
||||||
|
);
|
||||||
|
diag.span_labels(target_spans, "`#[target_feature]` added here");
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn suggest_constraint(
|
||||||
|
&self,
|
||||||
|
diag: &mut Diagnostic,
|
||||||
|
msg: &str,
|
||||||
|
body_owner_def_id: DefId,
|
||||||
|
proj_ty: &ty::AliasTy<'tcx>,
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
) -> bool {
|
||||||
|
let tcx = self.tcx;
|
||||||
|
let assoc = tcx.associated_item(proj_ty.def_id);
|
||||||
|
let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(tcx);
|
||||||
|
if let Some(item) = tcx.hir().get_if_local(body_owner_def_id) {
|
||||||
|
if let Some(hir_generics) = item.generics() {
|
||||||
|
// Get the `DefId` for the type parameter corresponding to `A` in `<A as T>::Foo`.
|
||||||
|
// This will also work for `impl Trait`.
|
||||||
|
let def_id = if let ty::Param(param_ty) = proj_ty.self_ty().kind() {
|
||||||
|
let generics = tcx.generics_of(body_owner_def_id);
|
||||||
|
generics.type_param(param_ty, tcx).def_id
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let Some(def_id) = def_id.as_local() else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// First look in the `where` clause, as this might be
|
||||||
|
// `fn foo<T>(x: T) where T: Trait`.
|
||||||
|
for pred in hir_generics.bounds_for_param(def_id) {
|
||||||
|
if self.constrain_generic_bound_associated_type_structured_suggestion(
|
||||||
|
diag,
|
||||||
|
&trait_ref,
|
||||||
|
pred.bounds,
|
||||||
|
&assoc,
|
||||||
|
assoc_substs,
|
||||||
|
ty,
|
||||||
|
msg,
|
||||||
|
false,
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An associated type was expected and a different type was found.
|
||||||
|
///
|
||||||
|
/// We perform a few different checks to see what we can suggest:
|
||||||
|
///
|
||||||
|
/// - In the current item, look for associated functions that return the expected type and
|
||||||
|
/// suggest calling them. (Not a structured suggestion.)
|
||||||
|
/// - If any of the item's generic bounds can be constrained, we suggest constraining the
|
||||||
|
/// associated type to the found type.
|
||||||
|
/// - If the associated type has a default type and was expected inside of a `trait`, we
|
||||||
|
/// mention that this is disallowed.
|
||||||
|
/// - If all other things fail, and the error is not because of a mismatch between the `trait`
|
||||||
|
/// and the `impl`, we provide a generic `help` to constrain the assoc type or call an assoc
|
||||||
|
/// fn that returns the type.
|
||||||
|
fn expected_projection(
|
||||||
|
&self,
|
||||||
|
diag: &mut Diagnostic,
|
||||||
|
proj_ty: &ty::AliasTy<'tcx>,
|
||||||
|
values: ExpectedFound<Ty<'tcx>>,
|
||||||
|
body_owner_def_id: DefId,
|
||||||
|
cause_code: &ObligationCauseCode<'_>,
|
||||||
|
) {
|
||||||
|
let tcx = self.tcx;
|
||||||
|
|
||||||
|
let msg = format!(
|
||||||
|
"consider constraining the associated type `{}` to `{}`",
|
||||||
|
values.expected, values.found
|
||||||
|
);
|
||||||
|
let body_owner = tcx.hir().get_if_local(body_owner_def_id);
|
||||||
|
let current_method_ident = body_owner.and_then(|n| n.ident()).map(|i| i.name);
|
||||||
|
|
||||||
|
// We don't want to suggest calling an assoc fn in a scope where that isn't feasible.
|
||||||
|
let callable_scope = matches!(
|
||||||
|
body_owner,
|
||||||
|
Some(
|
||||||
|
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. })
|
||||||
|
| hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. })
|
||||||
|
| hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
let impl_comparison =
|
||||||
|
matches!(cause_code, ObligationCauseCode::CompareImplItemObligation { .. });
|
||||||
|
let assoc = tcx.associated_item(proj_ty.def_id);
|
||||||
|
if !callable_scope || impl_comparison {
|
||||||
|
// We do not want to suggest calling functions when the reason of the
|
||||||
|
// type error is a comparison of an `impl` with its `trait` or when the
|
||||||
|
// scope is outside of a `Body`.
|
||||||
|
} else {
|
||||||
|
// If we find a suitable associated function that returns the expected type, we don't
|
||||||
|
// want the more general suggestion later in this method about "consider constraining
|
||||||
|
// the associated type or calling a method that returns the associated type".
|
||||||
|
let point_at_assoc_fn = self.point_at_methods_that_satisfy_associated_type(
|
||||||
|
diag,
|
||||||
|
assoc.container_id(tcx),
|
||||||
|
current_method_ident,
|
||||||
|
proj_ty.def_id,
|
||||||
|
values.expected,
|
||||||
|
);
|
||||||
|
// Possibly suggest constraining the associated type to conform to the
|
||||||
|
// found type.
|
||||||
|
if self.suggest_constraint(diag, &msg, body_owner_def_id, proj_ty, values.found)
|
||||||
|
|| point_at_assoc_fn
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.suggest_constraining_opaque_associated_type(diag, &msg, proj_ty, values.found);
|
||||||
|
|
||||||
|
if self.point_at_associated_type(diag, body_owner_def_id, values.found) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !impl_comparison {
|
||||||
|
// Generic suggestion when we can't be more specific.
|
||||||
|
if callable_scope {
|
||||||
|
diag.help(&format!(
|
||||||
|
"{} or calling a method that returns `{}`",
|
||||||
|
msg, values.expected
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
diag.help(&msg);
|
||||||
|
}
|
||||||
|
diag.note(
|
||||||
|
"for more information, visit \
|
||||||
|
https://doc.rust-lang.org/book/ch19-03-advanced-traits.html",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if tcx.sess.teach(&diag.get_code().unwrap()) {
|
||||||
|
diag.help(
|
||||||
|
"given an associated type `T` and a method `foo`:
|
||||||
|
```
|
||||||
|
trait Trait {
|
||||||
|
type T;
|
||||||
|
fn foo(&tcx) -> Self::T;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
the only way of implementing method `foo` is to constrain `T` with an explicit associated type:
|
||||||
|
```
|
||||||
|
impl Trait for X {
|
||||||
|
type T = String;
|
||||||
|
fn foo(&tcx) -> Self::T { String::new() }
|
||||||
|
}
|
||||||
|
```",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// When the expected `impl Trait` is not defined in the current item, it will come from
|
||||||
|
/// a return type. This can occur when dealing with `TryStream` (#71035).
|
||||||
|
fn suggest_constraining_opaque_associated_type(
|
||||||
|
&self,
|
||||||
|
diag: &mut Diagnostic,
|
||||||
|
msg: &str,
|
||||||
|
proj_ty: &ty::AliasTy<'tcx>,
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
) -> bool {
|
||||||
|
let tcx = self.tcx;
|
||||||
|
|
||||||
|
let assoc = tcx.associated_item(proj_ty.def_id);
|
||||||
|
if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *proj_ty.self_ty().kind() {
|
||||||
|
let opaque_local_def_id = def_id.as_local();
|
||||||
|
let opaque_hir_ty = if let Some(opaque_local_def_id) = opaque_local_def_id {
|
||||||
|
match &tcx.hir().expect_item(opaque_local_def_id).kind {
|
||||||
|
hir::ItemKind::OpaqueTy(opaque_hir_ty) => opaque_hir_ty,
|
||||||
|
_ => bug!("The HirId comes from a `ty::Opaque`"),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(tcx);
|
||||||
|
|
||||||
|
self.constrain_generic_bound_associated_type_structured_suggestion(
|
||||||
|
diag,
|
||||||
|
&trait_ref,
|
||||||
|
opaque_hir_ty.bounds,
|
||||||
|
assoc,
|
||||||
|
assoc_substs,
|
||||||
|
ty,
|
||||||
|
msg,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn point_at_methods_that_satisfy_associated_type(
|
||||||
|
&self,
|
||||||
|
diag: &mut Diagnostic,
|
||||||
|
assoc_container_id: DefId,
|
||||||
|
current_method_ident: Option<Symbol>,
|
||||||
|
proj_ty_item_def_id: DefId,
|
||||||
|
expected: Ty<'tcx>,
|
||||||
|
) -> bool {
|
||||||
|
let tcx = self.tcx;
|
||||||
|
|
||||||
|
let items = tcx.associated_items(assoc_container_id);
|
||||||
|
// Find all the methods in the trait that could be called to construct the
|
||||||
|
// expected associated type.
|
||||||
|
// FIXME: consider suggesting the use of associated `const`s.
|
||||||
|
let methods: Vec<(Span, String)> = items
|
||||||
|
.in_definition_order()
|
||||||
|
.filter(|item| {
|
||||||
|
ty::AssocKind::Fn == item.kind && Some(item.name) != current_method_ident
|
||||||
|
})
|
||||||
|
.filter_map(|item| {
|
||||||
|
let method = tcx.fn_sig(item.def_id);
|
||||||
|
match *method.output().skip_binder().kind() {
|
||||||
|
ty::Alias(ty::Projection, ty::AliasTy { def_id: item_def_id, .. })
|
||||||
|
if item_def_id == proj_ty_item_def_id =>
|
||||||
|
{
|
||||||
|
Some((
|
||||||
|
tcx.def_span(item.def_id),
|
||||||
|
format!("consider calling `{}`", tcx.def_path_str(item.def_id)),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
if !methods.is_empty() {
|
||||||
|
// Use a single `help:` to show all the methods in the trait that can
|
||||||
|
// be used to construct the expected associated type.
|
||||||
|
let mut span: MultiSpan =
|
||||||
|
methods.iter().map(|(sp, _)| *sp).collect::<Vec<Span>>().into();
|
||||||
|
let msg = format!(
|
||||||
|
"{some} method{s} {are} available that return{r} `{ty}`",
|
||||||
|
some = if methods.len() == 1 { "a" } else { "some" },
|
||||||
|
s = pluralize!(methods.len()),
|
||||||
|
are = pluralize!("is", methods.len()),
|
||||||
|
r = if methods.len() == 1 { "s" } else { "" },
|
||||||
|
ty = expected
|
||||||
|
);
|
||||||
|
for (sp, label) in methods.into_iter() {
|
||||||
|
span.push_span_label(sp, label);
|
||||||
|
}
|
||||||
|
diag.span_help(span, &msg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn point_at_associated_type(
|
||||||
|
&self,
|
||||||
|
diag: &mut Diagnostic,
|
||||||
|
body_owner_def_id: DefId,
|
||||||
|
found: Ty<'tcx>,
|
||||||
|
) -> bool {
|
||||||
|
let tcx = self.tcx;
|
||||||
|
|
||||||
|
let Some(hir_id) = body_owner_def_id.as_local() else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let hir_id = tcx.hir().local_def_id_to_hir_id(hir_id);
|
||||||
|
// When `body_owner` is an `impl` or `trait` item, look in its associated types for
|
||||||
|
// `expected` and point at it.
|
||||||
|
let parent_id = tcx.hir().get_parent_item(hir_id);
|
||||||
|
let item = tcx.hir().find_by_def_id(parent_id.def_id);
|
||||||
|
|
||||||
|
debug!("expected_projection parent item {:?}", item);
|
||||||
|
|
||||||
|
let param_env = tcx.param_env(body_owner_def_id);
|
||||||
|
|
||||||
|
match item {
|
||||||
|
Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Trait(.., items), .. })) => {
|
||||||
|
// FIXME: account for `#![feature(specialization)]`
|
||||||
|
for item in &items[..] {
|
||||||
|
match item.kind {
|
||||||
|
hir::AssocItemKind::Type => {
|
||||||
|
// FIXME: account for returning some type in a trait fn impl that has
|
||||||
|
// an assoc type as a return type (#72076).
|
||||||
|
if let hir::Defaultness::Default { has_value: true } =
|
||||||
|
tcx.impl_defaultness(item.id.owner_id)
|
||||||
|
{
|
||||||
|
let assoc_ty = tcx.bound_type_of(item.id.owner_id).subst_identity();
|
||||||
|
if self.infcx.can_eq(param_env, assoc_ty, found).is_ok() {
|
||||||
|
diag.span_label(
|
||||||
|
item.span,
|
||||||
|
"associated type defaults can't be assumed inside the \
|
||||||
|
trait defining them",
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(hir::Node::Item(hir::Item {
|
||||||
|
kind: hir::ItemKind::Impl(hir::Impl { items, .. }),
|
||||||
|
..
|
||||||
|
})) => {
|
||||||
|
for item in &items[..] {
|
||||||
|
if let hir::AssocItemKind::Type = item.kind {
|
||||||
|
let assoc_ty = tcx.bound_type_of(item.id.owner_id).subst_identity();
|
||||||
|
|
||||||
|
if self.infcx.can_eq(param_env, assoc_ty, found).is_ok() {
|
||||||
|
diag.span_label(item.span, "expected this associated type");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Given a slice of `hir::GenericBound`s, if any of them corresponds to the `trait_ref`
|
||||||
|
/// requirement, provide a structured suggestion to constrain it to a given type `ty`.
|
||||||
|
///
|
||||||
|
/// `is_bound_surely_present` indicates whether we know the bound we're looking for is
|
||||||
|
/// inside `bounds`. If that's the case then we can consider `bounds` containing only one
|
||||||
|
/// trait bound as the one we're looking for. This can help in cases where the associated
|
||||||
|
/// type is defined on a supertrait of the one present in the bounds.
|
||||||
|
fn constrain_generic_bound_associated_type_structured_suggestion(
|
||||||
|
&self,
|
||||||
|
diag: &mut Diagnostic,
|
||||||
|
trait_ref: &ty::TraitRef<'tcx>,
|
||||||
|
bounds: hir::GenericBounds<'_>,
|
||||||
|
assoc: &ty::AssocItem,
|
||||||
|
assoc_substs: &[ty::GenericArg<'tcx>],
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
msg: &str,
|
||||||
|
is_bound_surely_present: bool,
|
||||||
|
) -> bool {
|
||||||
|
// FIXME: we would want to call `resolve_vars_if_possible` on `ty` before suggesting.
|
||||||
|
|
||||||
|
let trait_bounds = bounds.iter().filter_map(|bound| match bound {
|
||||||
|
hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::None) => Some(ptr),
|
||||||
|
_ => None,
|
||||||
|
});
|
||||||
|
|
||||||
|
let matching_trait_bounds = trait_bounds
|
||||||
|
.clone()
|
||||||
|
.filter(|ptr| ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let span = match &matching_trait_bounds[..] {
|
||||||
|
&[ptr] => ptr.span,
|
||||||
|
&[] if is_bound_surely_present => match &trait_bounds.collect::<Vec<_>>()[..] {
|
||||||
|
&[ptr] => ptr.span,
|
||||||
|
_ => return false,
|
||||||
|
},
|
||||||
|
_ => return false,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.constrain_associated_type_structured_suggestion(
|
||||||
|
diag,
|
||||||
|
span,
|
||||||
|
assoc,
|
||||||
|
assoc_substs,
|
||||||
|
ty,
|
||||||
|
msg,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Given a span corresponding to a bound, provide a structured suggestion to set an
|
||||||
|
/// associated type to a given type `ty`.
|
||||||
|
fn constrain_associated_type_structured_suggestion(
|
||||||
|
&self,
|
||||||
|
diag: &mut Diagnostic,
|
||||||
|
span: Span,
|
||||||
|
assoc: &ty::AssocItem,
|
||||||
|
assoc_substs: &[ty::GenericArg<'tcx>],
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
msg: &str,
|
||||||
|
) -> bool {
|
||||||
|
let tcx = self.tcx;
|
||||||
|
|
||||||
|
if let Ok(has_params) =
|
||||||
|
tcx.sess.source_map().span_to_snippet(span).map(|snippet| snippet.ends_with('>'))
|
||||||
|
{
|
||||||
|
let (span, sugg) = if has_params {
|
||||||
|
let pos = span.hi() - BytePos(1);
|
||||||
|
let span = Span::new(pos, pos, span.ctxt(), span.parent());
|
||||||
|
(span, format!(", {} = {}", assoc.ident(tcx), ty))
|
||||||
|
} else {
|
||||||
|
let item_args = self.format_generic_args(assoc_substs);
|
||||||
|
(span.shrink_to_hi(), format!("<{}{} = {}>", assoc.ident(tcx), item_args, ty))
|
||||||
|
};
|
||||||
|
diag.span_suggestion_verbose(span, msg, sugg, MaybeIncorrect);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn format_generic_args(&self, args: &[ty::GenericArg<'tcx>]) -> String {
|
||||||
|
FmtPrinter::new(self.tcx, hir::def::Namespace::TypeNS)
|
||||||
|
.path_generic_args(Ok, args)
|
||||||
|
.expect("could not write to `String`.")
|
||||||
|
.into_buffer()
|
||||||
|
}
|
||||||
|
}
|
|
@ -380,7 +380,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (msg, sugg) = match (expected.is_ref(), found.is_ref()) {
|
let (msg, sug) = match (expected.is_ref(), found.is_ref()) {
|
||||||
(true, false) => {
|
(true, false) => {
|
||||||
let msg = "consider using a reference";
|
let msg = "consider using a reference";
|
||||||
let sug = format!("&{fn_name}");
|
let sug = format!("&{fn_name}");
|
||||||
|
@ -404,7 +404,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||||
(msg, sug)
|
(msg, sug)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
diag.span_suggestion(span, msg, &sugg, Applicability::MaybeIncorrect);
|
diag.span_suggestion(span, msg, sug, Applicability::MaybeIncorrect);
|
||||||
}
|
}
|
||||||
(ty::FnDef(did1, substs1), ty::FnDef(did2, substs2)) => {
|
(ty::FnDef(did1, substs1), ty::FnDef(did2, substs2)) => {
|
||||||
let expected_sig =
|
let expected_sig =
|
||||||
|
@ -412,14 +412,50 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||||
let found_sig =
|
let found_sig =
|
||||||
&(self.normalize_fn_sig)(self.tcx.bound_fn_sig(*did2).subst(self.tcx, substs2));
|
&(self.normalize_fn_sig)(self.tcx.bound_fn_sig(*did2).subst(self.tcx, substs2));
|
||||||
|
|
||||||
if self.same_type_modulo_infer(*found_sig, *expected_sig) {
|
if self.same_type_modulo_infer(*expected_sig, *found_sig) {
|
||||||
diag.note(
|
diag.note("different fn items have unique types, even if their signatures are the same");
|
||||||
"different fn items have unique types, even if their signatures are the same",
|
}
|
||||||
|
|
||||||
|
if !self.same_type_modulo_infer(*found_sig, *expected_sig)
|
||||||
|
|| !found_sig.is_suggestable(self.tcx, true)
|
||||||
|
|| !expected_sig.is_suggestable(self.tcx, true)
|
||||||
|
|| ty::util::is_intrinsic(self.tcx, *did1)
|
||||||
|
|| ty::util::is_intrinsic(self.tcx, *did2)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let fn_name = self.tcx.def_path_str_with_substs(*did2, substs2);
|
||||||
|
let sug = if found.is_ref() {
|
||||||
|
format!("&({fn_name} as {found_sig})")
|
||||||
|
} else {
|
||||||
|
format!("{fn_name} as {found_sig}")
|
||||||
|
};
|
||||||
|
|
||||||
|
let msg = format!(
|
||||||
|
"consider casting both fn items to fn pointers using `as {expected_sig}`"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
diag.span_suggestion_hidden(span, msg, sug, Applicability::MaybeIncorrect);
|
||||||
}
|
}
|
||||||
|
(ty::FnDef(did, substs), ty::FnPtr(sig)) => {
|
||||||
|
let expected_sig =
|
||||||
|
&(self.normalize_fn_sig)(self.tcx.bound_fn_sig(*did).subst(self.tcx, substs));
|
||||||
|
let found_sig = &(self.normalize_fn_sig)(*sig);
|
||||||
|
|
||||||
|
if !self.same_type_modulo_infer(*found_sig, *expected_sig) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
(ty::FnDef(_, _), ty::FnPtr(_)) => {
|
|
||||||
diag.note("fn items are distinct from fn pointers");
|
let fn_name = self.tcx.def_path_str_with_substs(*did, substs);
|
||||||
|
|
||||||
|
let casting = if expected.is_ref() {
|
||||||
|
format!("&({fn_name} as {found_sig})")
|
||||||
|
} else {
|
||||||
|
format!("{fn_name} as {found_sig}")
|
||||||
|
};
|
||||||
|
|
||||||
|
diag.help(&format!("consider casting the fn item to a fn pointer: `{}`", casting));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -130,7 +130,7 @@ 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<'tcx> {
|
pub struct AssocItems<'tcx> {
|
||||||
pub(super) items: SortedIndexMultiMap<u32, Symbol, &'tcx ty::AssocItem>,
|
items: SortedIndexMultiMap<u32, Symbol, &'tcx ty::AssocItem>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> AssocItems<'tcx> {
|
impl<'tcx> AssocItems<'tcx> {
|
||||||
|
|
|
@ -1,24 +1,18 @@
|
||||||
use crate::traits::{ObligationCause, ObligationCauseCode};
|
use crate::ty::print::{with_forced_trimmed_paths, FmtPrinter, PrettyPrinter};
|
||||||
use crate::ty::diagnostics::suggest_constraining_type_param;
|
|
||||||
use crate::ty::print::{with_forced_trimmed_paths, FmtPrinter, Printer};
|
|
||||||
use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt};
|
use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt};
|
||||||
use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
|
use rustc_errors::pluralize;
|
||||||
use rustc_errors::{pluralize, Diagnostic, MultiSpan};
|
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{CtorOf, DefKind};
|
use rustc_hir::def::{CtorOf, DefKind};
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_span::symbol::{sym, Symbol};
|
use rustc_span::symbol::Symbol;
|
||||||
use rustc_span::{BytePos, Span};
|
|
||||||
use rustc_target::spec::abi;
|
use rustc_target::spec::abi;
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::collections::hash_map::DefaultHasher;
|
use std::collections::hash_map::DefaultHasher;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::Hash;
|
||||||
|
use std::hash::Hasher;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use super::print::PrettyPrinter;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable, Lift)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable, Lift)]
|
||||||
pub struct ExpectedFound<T> {
|
pub struct ExpectedFound<T> {
|
||||||
pub expected: T,
|
pub expected: T,
|
||||||
|
@ -391,620 +385,6 @@ impl<'tcx> Ty<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> TyCtxt<'tcx> {
|
impl<'tcx> TyCtxt<'tcx> {
|
||||||
pub fn note_and_explain_type_err(
|
|
||||||
self,
|
|
||||||
diag: &mut Diagnostic,
|
|
||||||
err: TypeError<'tcx>,
|
|
||||||
cause: &ObligationCause<'tcx>,
|
|
||||||
sp: Span,
|
|
||||||
body_owner_def_id: DefId,
|
|
||||||
) {
|
|
||||||
use self::TypeError::*;
|
|
||||||
debug!("note_and_explain_type_err err={:?} cause={:?}", err, cause);
|
|
||||||
match err {
|
|
||||||
ArgumentSorts(values, _) | Sorts(values) => {
|
|
||||||
match (values.expected.kind(), values.found.kind()) {
|
|
||||||
(ty::Closure(..), ty::Closure(..)) => {
|
|
||||||
diag.note("no two closures, even if identical, have the same type");
|
|
||||||
diag.help("consider boxing your closure and/or using it as a trait object");
|
|
||||||
}
|
|
||||||
(ty::Alias(ty::Opaque, ..), ty::Alias(ty::Opaque, ..)) => {
|
|
||||||
// Issue #63167
|
|
||||||
diag.note("distinct uses of `impl Trait` result in different opaque types");
|
|
||||||
}
|
|
||||||
(ty::Float(_), ty::Infer(ty::IntVar(_)))
|
|
||||||
if let Ok(
|
|
||||||
// Issue #53280
|
|
||||||
snippet,
|
|
||||||
) = self.sess.source_map().span_to_snippet(sp) =>
|
|
||||||
{
|
|
||||||
if snippet.chars().all(|c| c.is_digit(10) || c == '-' || c == '_') {
|
|
||||||
diag.span_suggestion(
|
|
||||||
sp,
|
|
||||||
"use a float literal",
|
|
||||||
format!("{}.0", snippet),
|
|
||||||
MachineApplicable,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(ty::Param(expected), ty::Param(found)) => {
|
|
||||||
let generics = self.generics_of(body_owner_def_id);
|
|
||||||
let e_span = self.def_span(generics.type_param(expected, self).def_id);
|
|
||||||
if !sp.contains(e_span) {
|
|
||||||
diag.span_label(e_span, "expected type parameter");
|
|
||||||
}
|
|
||||||
let f_span = self.def_span(generics.type_param(found, self).def_id);
|
|
||||||
if !sp.contains(f_span) {
|
|
||||||
diag.span_label(f_span, "found type parameter");
|
|
||||||
}
|
|
||||||
diag.note(
|
|
||||||
"a type parameter was expected, but a different one was found; \
|
|
||||||
you might be missing a type parameter or trait bound",
|
|
||||||
);
|
|
||||||
diag.note(
|
|
||||||
"for more information, visit \
|
|
||||||
https://doc.rust-lang.org/book/ch10-02-traits.html\
|
|
||||||
#traits-as-parameters",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
(ty::Alias(ty::Projection, _), ty::Alias(ty::Projection, _)) => {
|
|
||||||
diag.note("an associated type was expected, but a different one was found");
|
|
||||||
}
|
|
||||||
(ty::Param(p), ty::Alias(ty::Projection, proj)) | (ty::Alias(ty::Projection, proj), ty::Param(p))
|
|
||||||
if self.def_kind(proj.def_id) != DefKind::ImplTraitPlaceholder =>
|
|
||||||
{
|
|
||||||
let generics = self.generics_of(body_owner_def_id);
|
|
||||||
let p_span = self.def_span(generics.type_param(p, self).def_id);
|
|
||||||
if !sp.contains(p_span) {
|
|
||||||
diag.span_label(p_span, "this type parameter");
|
|
||||||
}
|
|
||||||
let hir = self.hir();
|
|
||||||
let mut note = true;
|
|
||||||
if let Some(generics) = generics
|
|
||||||
.type_param(p, self)
|
|
||||||
.def_id
|
|
||||||
.as_local()
|
|
||||||
.map(|id| hir.local_def_id_to_hir_id(id))
|
|
||||||
.and_then(|id| self.hir().find_parent(id))
|
|
||||||
.as_ref()
|
|
||||||
.and_then(|node| node.generics())
|
|
||||||
{
|
|
||||||
// Synthesize the associated type restriction `Add<Output = Expected>`.
|
|
||||||
// FIXME: extract this logic for use in other diagnostics.
|
|
||||||
let (trait_ref, assoc_substs) = proj.trait_ref_and_own_substs(self);
|
|
||||||
let path =
|
|
||||||
self.def_path_str_with_substs(trait_ref.def_id, trait_ref.substs);
|
|
||||||
let item_name = self.item_name(proj.def_id);
|
|
||||||
let item_args = self.format_generic_args(assoc_substs);
|
|
||||||
|
|
||||||
let path = if path.ends_with('>') {
|
|
||||||
format!(
|
|
||||||
"{}, {}{} = {}>",
|
|
||||||
&path[..path.len() - 1],
|
|
||||||
item_name,
|
|
||||||
item_args,
|
|
||||||
p
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
format!("{}<{}{} = {}>", path, item_name, item_args, p)
|
|
||||||
};
|
|
||||||
note = !suggest_constraining_type_param(
|
|
||||||
self,
|
|
||||||
generics,
|
|
||||||
diag,
|
|
||||||
&format!("{}", proj.self_ty()),
|
|
||||||
&path,
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if note {
|
|
||||||
diag.note("you might be missing a type parameter or trait bound");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(ty::Param(p), ty::Dynamic(..) | ty::Alias(ty::Opaque, ..))
|
|
||||||
| (ty::Dynamic(..) | ty::Alias(ty::Opaque, ..), ty::Param(p)) => {
|
|
||||||
let generics = self.generics_of(body_owner_def_id);
|
|
||||||
let p_span = self.def_span(generics.type_param(p, self).def_id);
|
|
||||||
if !sp.contains(p_span) {
|
|
||||||
diag.span_label(p_span, "this type parameter");
|
|
||||||
}
|
|
||||||
diag.help("type parameters must be constrained to match other types");
|
|
||||||
if self.sess.teach(&diag.get_code().unwrap()) {
|
|
||||||
diag.help(
|
|
||||||
"given a type parameter `T` and a method `foo`:
|
|
||||||
```
|
|
||||||
trait Trait<T> { fn foo(&self) -> T; }
|
|
||||||
```
|
|
||||||
the only ways to implement method `foo` are:
|
|
||||||
- constrain `T` with an explicit type:
|
|
||||||
```
|
|
||||||
impl Trait<String> for X {
|
|
||||||
fn foo(&self) -> String { String::new() }
|
|
||||||
}
|
|
||||||
```
|
|
||||||
- add a trait bound to `T` and call a method on that trait that returns `Self`:
|
|
||||||
```
|
|
||||||
impl<T: std::default::Default> Trait<T> for X {
|
|
||||||
fn foo(&self) -> T { <T as std::default::Default>::default() }
|
|
||||||
}
|
|
||||||
```
|
|
||||||
- change `foo` to return an argument of type `T`:
|
|
||||||
```
|
|
||||||
impl<T> Trait<T> for X {
|
|
||||||
fn foo(&self, x: T) -> T { x }
|
|
||||||
}
|
|
||||||
```",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
diag.note(
|
|
||||||
"for more information, visit \
|
|
||||||
https://doc.rust-lang.org/book/ch10-02-traits.html\
|
|
||||||
#traits-as-parameters",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
(ty::Param(p), ty::Closure(..) | ty::Generator(..)) => {
|
|
||||||
let generics = self.generics_of(body_owner_def_id);
|
|
||||||
let p_span = self.def_span(generics.type_param(p, self).def_id);
|
|
||||||
if !sp.contains(p_span) {
|
|
||||||
diag.span_label(p_span, "this type parameter");
|
|
||||||
}
|
|
||||||
diag.help(&format!(
|
|
||||||
"every closure has a distinct type and so could not always match the \
|
|
||||||
caller-chosen type of parameter `{}`",
|
|
||||||
p
|
|
||||||
));
|
|
||||||
}
|
|
||||||
(ty::Param(p), _) | (_, ty::Param(p)) => {
|
|
||||||
let generics = self.generics_of(body_owner_def_id);
|
|
||||||
let p_span = self.def_span(generics.type_param(p, self).def_id);
|
|
||||||
if !sp.contains(p_span) {
|
|
||||||
diag.span_label(p_span, "this type parameter");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(ty::Alias(ty::Projection, proj_ty), _) if self.def_kind(proj_ty.def_id) != DefKind::ImplTraitPlaceholder => {
|
|
||||||
self.expected_projection(
|
|
||||||
diag,
|
|
||||||
proj_ty,
|
|
||||||
values,
|
|
||||||
body_owner_def_id,
|
|
||||||
cause.code(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
(_, ty::Alias(ty::Projection, proj_ty)) if self.def_kind(proj_ty.def_id) != DefKind::ImplTraitPlaceholder => {
|
|
||||||
let msg = format!(
|
|
||||||
"consider constraining the associated type `{}` to `{}`",
|
|
||||||
values.found, values.expected,
|
|
||||||
);
|
|
||||||
if !(self.suggest_constraining_opaque_associated_type(
|
|
||||||
diag,
|
|
||||||
&msg,
|
|
||||||
proj_ty,
|
|
||||||
values.expected,
|
|
||||||
) || self.suggest_constraint(
|
|
||||||
diag,
|
|
||||||
&msg,
|
|
||||||
body_owner_def_id,
|
|
||||||
proj_ty,
|
|
||||||
values.expected,
|
|
||||||
)) {
|
|
||||||
diag.help(&msg);
|
|
||||||
diag.note(
|
|
||||||
"for more information, visit \
|
|
||||||
https://doc.rust-lang.org/book/ch19-03-advanced-traits.html",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
debug!(
|
|
||||||
"note_and_explain_type_err expected={:?} ({:?}) found={:?} ({:?})",
|
|
||||||
values.expected,
|
|
||||||
values.expected.kind(),
|
|
||||||
values.found,
|
|
||||||
values.found.kind(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
CyclicTy(ty) => {
|
|
||||||
// Watch out for various cases of cyclic types and try to explain.
|
|
||||||
if ty.is_closure() || ty.is_generator() {
|
|
||||||
diag.note(
|
|
||||||
"closures cannot capture themselves or take themselves as argument;\n\
|
|
||||||
this error may be the result of a recent compiler bug-fix,\n\
|
|
||||||
see issue #46062 <https://github.com/rust-lang/rust/issues/46062>\n\
|
|
||||||
for more information",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TargetFeatureCast(def_id) => {
|
|
||||||
let target_spans =
|
|
||||||
self.get_attrs(def_id, sym::target_feature).map(|attr| attr.span);
|
|
||||||
diag.note(
|
|
||||||
"functions with `#[target_feature]` can only be coerced to `unsafe` function pointers"
|
|
||||||
);
|
|
||||||
diag.span_labels(target_spans, "`#[target_feature]` added here");
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn suggest_constraint(
|
|
||||||
self,
|
|
||||||
diag: &mut Diagnostic,
|
|
||||||
msg: &str,
|
|
||||||
body_owner_def_id: DefId,
|
|
||||||
proj_ty: &ty::AliasTy<'tcx>,
|
|
||||||
ty: Ty<'tcx>,
|
|
||||||
) -> bool {
|
|
||||||
let assoc = self.associated_item(proj_ty.def_id);
|
|
||||||
let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(self);
|
|
||||||
if let Some(item) = self.hir().get_if_local(body_owner_def_id) {
|
|
||||||
if let Some(hir_generics) = item.generics() {
|
|
||||||
// Get the `DefId` for the type parameter corresponding to `A` in `<A as T>::Foo`.
|
|
||||||
// This will also work for `impl Trait`.
|
|
||||||
let def_id = if let ty::Param(param_ty) = proj_ty.self_ty().kind() {
|
|
||||||
let generics = self.generics_of(body_owner_def_id);
|
|
||||||
generics.type_param(param_ty, self).def_id
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
let Some(def_id) = def_id.as_local() else {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
// First look in the `where` clause, as this might be
|
|
||||||
// `fn foo<T>(x: T) where T: Trait`.
|
|
||||||
for pred in hir_generics.bounds_for_param(def_id) {
|
|
||||||
if self.constrain_generic_bound_associated_type_structured_suggestion(
|
|
||||||
diag,
|
|
||||||
&trait_ref,
|
|
||||||
pred.bounds,
|
|
||||||
&assoc,
|
|
||||||
assoc_substs,
|
|
||||||
ty,
|
|
||||||
msg,
|
|
||||||
false,
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An associated type was expected and a different type was found.
|
|
||||||
///
|
|
||||||
/// We perform a few different checks to see what we can suggest:
|
|
||||||
///
|
|
||||||
/// - In the current item, look for associated functions that return the expected type and
|
|
||||||
/// suggest calling them. (Not a structured suggestion.)
|
|
||||||
/// - If any of the item's generic bounds can be constrained, we suggest constraining the
|
|
||||||
/// associated type to the found type.
|
|
||||||
/// - If the associated type has a default type and was expected inside of a `trait`, we
|
|
||||||
/// mention that this is disallowed.
|
|
||||||
/// - If all other things fail, and the error is not because of a mismatch between the `trait`
|
|
||||||
/// and the `impl`, we provide a generic `help` to constrain the assoc type or call an assoc
|
|
||||||
/// fn that returns the type.
|
|
||||||
fn expected_projection(
|
|
||||||
self,
|
|
||||||
diag: &mut Diagnostic,
|
|
||||||
proj_ty: &ty::AliasTy<'tcx>,
|
|
||||||
values: ExpectedFound<Ty<'tcx>>,
|
|
||||||
body_owner_def_id: DefId,
|
|
||||||
cause_code: &ObligationCauseCode<'_>,
|
|
||||||
) {
|
|
||||||
let msg = format!(
|
|
||||||
"consider constraining the associated type `{}` to `{}`",
|
|
||||||
values.expected, values.found
|
|
||||||
);
|
|
||||||
let body_owner = self.hir().get_if_local(body_owner_def_id);
|
|
||||||
let current_method_ident = body_owner.and_then(|n| n.ident()).map(|i| i.name);
|
|
||||||
|
|
||||||
// We don't want to suggest calling an assoc fn in a scope where that isn't feasible.
|
|
||||||
let callable_scope = matches!(
|
|
||||||
body_owner,
|
|
||||||
Some(
|
|
||||||
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. })
|
|
||||||
| hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. })
|
|
||||||
| hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }),
|
|
||||||
)
|
|
||||||
);
|
|
||||||
let impl_comparison =
|
|
||||||
matches!(cause_code, ObligationCauseCode::CompareImplItemObligation { .. });
|
|
||||||
let assoc = self.associated_item(proj_ty.def_id);
|
|
||||||
if !callable_scope || impl_comparison {
|
|
||||||
// We do not want to suggest calling functions when the reason of the
|
|
||||||
// type error is a comparison of an `impl` with its `trait` or when the
|
|
||||||
// scope is outside of a `Body`.
|
|
||||||
} else {
|
|
||||||
// If we find a suitable associated function that returns the expected type, we don't
|
|
||||||
// want the more general suggestion later in this method about "consider constraining
|
|
||||||
// the associated type or calling a method that returns the associated type".
|
|
||||||
let point_at_assoc_fn = self.point_at_methods_that_satisfy_associated_type(
|
|
||||||
diag,
|
|
||||||
assoc.container_id(self),
|
|
||||||
current_method_ident,
|
|
||||||
proj_ty.def_id,
|
|
||||||
values.expected,
|
|
||||||
);
|
|
||||||
// Possibly suggest constraining the associated type to conform to the
|
|
||||||
// found type.
|
|
||||||
if self.suggest_constraint(diag, &msg, body_owner_def_id, proj_ty, values.found)
|
|
||||||
|| point_at_assoc_fn
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.suggest_constraining_opaque_associated_type(diag, &msg, proj_ty, values.found);
|
|
||||||
|
|
||||||
if self.point_at_associated_type(diag, body_owner_def_id, values.found) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if !impl_comparison {
|
|
||||||
// Generic suggestion when we can't be more specific.
|
|
||||||
if callable_scope {
|
|
||||||
diag.help(&format!(
|
|
||||||
"{} or calling a method that returns `{}`",
|
|
||||||
msg, values.expected
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
diag.help(&msg);
|
|
||||||
}
|
|
||||||
diag.note(
|
|
||||||
"for more information, visit \
|
|
||||||
https://doc.rust-lang.org/book/ch19-03-advanced-traits.html",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if self.sess.teach(&diag.get_code().unwrap()) {
|
|
||||||
diag.help(
|
|
||||||
"given an associated type `T` and a method `foo`:
|
|
||||||
```
|
|
||||||
trait Trait {
|
|
||||||
type T;
|
|
||||||
fn foo(&self) -> Self::T;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
the only way of implementing method `foo` is to constrain `T` with an explicit associated type:
|
|
||||||
```
|
|
||||||
impl Trait for X {
|
|
||||||
type T = String;
|
|
||||||
fn foo(&self) -> Self::T { String::new() }
|
|
||||||
}
|
|
||||||
```",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// When the expected `impl Trait` is not defined in the current item, it will come from
|
|
||||||
/// a return type. This can occur when dealing with `TryStream` (#71035).
|
|
||||||
fn suggest_constraining_opaque_associated_type(
|
|
||||||
self,
|
|
||||||
diag: &mut Diagnostic,
|
|
||||||
msg: &str,
|
|
||||||
proj_ty: &ty::AliasTy<'tcx>,
|
|
||||||
ty: Ty<'tcx>,
|
|
||||||
) -> bool {
|
|
||||||
let assoc = self.associated_item(proj_ty.def_id);
|
|
||||||
if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *proj_ty.self_ty().kind() {
|
|
||||||
let opaque_local_def_id = def_id.as_local();
|
|
||||||
let opaque_hir_ty = if let Some(opaque_local_def_id) = opaque_local_def_id {
|
|
||||||
match &self.hir().expect_item(opaque_local_def_id).kind {
|
|
||||||
hir::ItemKind::OpaqueTy(opaque_hir_ty) => opaque_hir_ty,
|
|
||||||
_ => bug!("The HirId comes from a `ty::Opaque`"),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(self);
|
|
||||||
|
|
||||||
self.constrain_generic_bound_associated_type_structured_suggestion(
|
|
||||||
diag,
|
|
||||||
&trait_ref,
|
|
||||||
opaque_hir_ty.bounds,
|
|
||||||
assoc,
|
|
||||||
assoc_substs,
|
|
||||||
ty,
|
|
||||||
msg,
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn point_at_methods_that_satisfy_associated_type(
|
|
||||||
self,
|
|
||||||
diag: &mut Diagnostic,
|
|
||||||
assoc_container_id: DefId,
|
|
||||||
current_method_ident: Option<Symbol>,
|
|
||||||
proj_ty_item_def_id: DefId,
|
|
||||||
expected: Ty<'tcx>,
|
|
||||||
) -> bool {
|
|
||||||
let items = self.associated_items(assoc_container_id);
|
|
||||||
// Find all the methods in the trait that could be called to construct the
|
|
||||||
// expected associated type.
|
|
||||||
// FIXME: consider suggesting the use of associated `const`s.
|
|
||||||
let methods: Vec<(Span, String)> = items
|
|
||||||
.items
|
|
||||||
.iter()
|
|
||||||
.filter(|(name, item)| {
|
|
||||||
ty::AssocKind::Fn == item.kind && Some(**name) != current_method_ident
|
|
||||||
})
|
|
||||||
.filter_map(|(_, item)| {
|
|
||||||
let method = self.fn_sig(item.def_id);
|
|
||||||
match *method.output().skip_binder().kind() {
|
|
||||||
ty::Alias(ty::Projection, ty::AliasTy { def_id: item_def_id, .. })
|
|
||||||
if item_def_id == proj_ty_item_def_id =>
|
|
||||||
{
|
|
||||||
Some((
|
|
||||||
self.def_span(item.def_id),
|
|
||||||
format!("consider calling `{}`", self.def_path_str(item.def_id)),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
if !methods.is_empty() {
|
|
||||||
// Use a single `help:` to show all the methods in the trait that can
|
|
||||||
// be used to construct the expected associated type.
|
|
||||||
let mut span: MultiSpan =
|
|
||||||
methods.iter().map(|(sp, _)| *sp).collect::<Vec<Span>>().into();
|
|
||||||
let msg = format!(
|
|
||||||
"{some} method{s} {are} available that return{r} `{ty}`",
|
|
||||||
some = if methods.len() == 1 { "a" } else { "some" },
|
|
||||||
s = pluralize!(methods.len()),
|
|
||||||
are = pluralize!("is", methods.len()),
|
|
||||||
r = if methods.len() == 1 { "s" } else { "" },
|
|
||||||
ty = expected
|
|
||||||
);
|
|
||||||
for (sp, label) in methods.into_iter() {
|
|
||||||
span.push_span_label(sp, label);
|
|
||||||
}
|
|
||||||
diag.span_help(span, &msg);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
fn point_at_associated_type(
|
|
||||||
self,
|
|
||||||
diag: &mut Diagnostic,
|
|
||||||
body_owner_def_id: DefId,
|
|
||||||
found: Ty<'tcx>,
|
|
||||||
) -> bool {
|
|
||||||
let Some(hir_id) = body_owner_def_id.as_local() else {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
let hir_id = self.hir().local_def_id_to_hir_id(hir_id);
|
|
||||||
// When `body_owner` is an `impl` or `trait` item, look in its associated types for
|
|
||||||
// `expected` and point at it.
|
|
||||||
let parent_id = self.hir().get_parent_item(hir_id);
|
|
||||||
let item = self.hir().find_by_def_id(parent_id.def_id);
|
|
||||||
debug!("expected_projection parent item {:?}", item);
|
|
||||||
match item {
|
|
||||||
Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Trait(.., items), .. })) => {
|
|
||||||
// FIXME: account for `#![feature(specialization)]`
|
|
||||||
for item in &items[..] {
|
|
||||||
match item.kind {
|
|
||||||
hir::AssocItemKind::Type => {
|
|
||||||
// FIXME: account for returning some type in a trait fn impl that has
|
|
||||||
// an assoc type as a return type (#72076).
|
|
||||||
if let hir::Defaultness::Default { has_value: true } =
|
|
||||||
self.impl_defaultness(item.id.owner_id)
|
|
||||||
{
|
|
||||||
if self.type_of(item.id.owner_id) == found {
|
|
||||||
diag.span_label(
|
|
||||||
item.span,
|
|
||||||
"associated type defaults can't be assumed inside the \
|
|
||||||
trait defining them",
|
|
||||||
);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(hir::Node::Item(hir::Item {
|
|
||||||
kind: hir::ItemKind::Impl(hir::Impl { items, .. }),
|
|
||||||
..
|
|
||||||
})) => {
|
|
||||||
for item in &items[..] {
|
|
||||||
if let hir::AssocItemKind::Type = item.kind {
|
|
||||||
if self.type_of(item.id.owner_id) == found {
|
|
||||||
diag.span_label(item.span, "expected this associated type");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Given a slice of `hir::GenericBound`s, if any of them corresponds to the `trait_ref`
|
|
||||||
/// requirement, provide a structured suggestion to constrain it to a given type `ty`.
|
|
||||||
///
|
|
||||||
/// `is_bound_surely_present` indicates whether we know the bound we're looking for is
|
|
||||||
/// inside `bounds`. If that's the case then we can consider `bounds` containing only one
|
|
||||||
/// trait bound as the one we're looking for. This can help in cases where the associated
|
|
||||||
/// type is defined on a supertrait of the one present in the bounds.
|
|
||||||
fn constrain_generic_bound_associated_type_structured_suggestion(
|
|
||||||
self,
|
|
||||||
diag: &mut Diagnostic,
|
|
||||||
trait_ref: &ty::TraitRef<'tcx>,
|
|
||||||
bounds: hir::GenericBounds<'_>,
|
|
||||||
assoc: &ty::AssocItem,
|
|
||||||
assoc_substs: &[ty::GenericArg<'tcx>],
|
|
||||||
ty: Ty<'tcx>,
|
|
||||||
msg: &str,
|
|
||||||
is_bound_surely_present: bool,
|
|
||||||
) -> bool {
|
|
||||||
// FIXME: we would want to call `resolve_vars_if_possible` on `ty` before suggesting.
|
|
||||||
|
|
||||||
let trait_bounds = bounds.iter().filter_map(|bound| match bound {
|
|
||||||
hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::None) => Some(ptr),
|
|
||||||
_ => None,
|
|
||||||
});
|
|
||||||
|
|
||||||
let matching_trait_bounds = trait_bounds
|
|
||||||
.clone()
|
|
||||||
.filter(|ptr| ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let span = match &matching_trait_bounds[..] {
|
|
||||||
&[ptr] => ptr.span,
|
|
||||||
&[] if is_bound_surely_present => match &trait_bounds.collect::<Vec<_>>()[..] {
|
|
||||||
&[ptr] => ptr.span,
|
|
||||||
_ => return false,
|
|
||||||
},
|
|
||||||
_ => return false,
|
|
||||||
};
|
|
||||||
|
|
||||||
self.constrain_associated_type_structured_suggestion(
|
|
||||||
diag,
|
|
||||||
span,
|
|
||||||
assoc,
|
|
||||||
assoc_substs,
|
|
||||||
ty,
|
|
||||||
msg,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Given a span corresponding to a bound, provide a structured suggestion to set an
|
|
||||||
/// associated type to a given type `ty`.
|
|
||||||
fn constrain_associated_type_structured_suggestion(
|
|
||||||
self,
|
|
||||||
diag: &mut Diagnostic,
|
|
||||||
span: Span,
|
|
||||||
assoc: &ty::AssocItem,
|
|
||||||
assoc_substs: &[ty::GenericArg<'tcx>],
|
|
||||||
ty: Ty<'tcx>,
|
|
||||||
msg: &str,
|
|
||||||
) -> bool {
|
|
||||||
if let Ok(has_params) =
|
|
||||||
self.sess.source_map().span_to_snippet(span).map(|snippet| snippet.ends_with('>'))
|
|
||||||
{
|
|
||||||
let (span, sugg) = if has_params {
|
|
||||||
let pos = span.hi() - BytePos(1);
|
|
||||||
let span = Span::new(pos, pos, span.ctxt(), span.parent());
|
|
||||||
(span, format!(", {} = {}", assoc.ident(self), ty))
|
|
||||||
} else {
|
|
||||||
let item_args = self.format_generic_args(assoc_substs);
|
|
||||||
(span.shrink_to_hi(), format!("<{}{} = {}>", assoc.ident(self), item_args, ty))
|
|
||||||
};
|
|
||||||
diag.span_suggestion_verbose(span, msg, sugg, MaybeIncorrect);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn short_ty_string(self, ty: Ty<'tcx>) -> (String, Option<PathBuf>) {
|
pub fn short_ty_string(self, ty: Ty<'tcx>) -> (String, Option<PathBuf>) {
|
||||||
let width = self.sess.diagnostic_width();
|
let width = self.sess.diagnostic_width();
|
||||||
let length_limit = width.saturating_sub(30);
|
let length_limit = width.saturating_sub(30);
|
||||||
|
@ -1047,11 +427,4 @@ fn foo(&self) -> Self::T { String::new() }
|
||||||
Err(_) => (regular, None),
|
Err(_) => (regular, None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_generic_args(self, args: &[ty::GenericArg<'tcx>]) -> String {
|
|
||||||
FmtPrinter::new(self, hir::def::Namespace::TypeNS)
|
|
||||||
.path_generic_args(Ok, args)
|
|
||||||
.expect("could not write to `String`.")
|
|
||||||
.into_buffer()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -441,6 +441,10 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
self.opt_def_kind(def_id)
|
self.opt_def_kind(def_id)
|
||||||
.unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", def_id))
|
.unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", def_id))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn bound_type_of(self, def_id: impl IntoQueryParam<DefId>) -> ty::EarlyBinder<Ty<'tcx>> {
|
||||||
|
ty::EarlyBinder(self.type_of(def_id))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> TyCtxtAt<'tcx> {
|
impl<'tcx> TyCtxtAt<'tcx> {
|
||||||
|
@ -449,4 +453,8 @@ impl<'tcx> TyCtxtAt<'tcx> {
|
||||||
self.opt_def_kind(def_id)
|
self.opt_def_kind(def_id)
|
||||||
.unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", def_id))
|
.unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", def_id))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn bound_type_of(self, def_id: impl IntoQueryParam<DefId>) -> ty::EarlyBinder<Ty<'tcx>> {
|
||||||
|
ty::EarlyBinder(self.type_of(def_id))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||||
use crate::mir;
|
use crate::mir;
|
||||||
use crate::ty::layout::IntegerExt;
|
use crate::ty::layout::IntegerExt;
|
||||||
use crate::ty::query::TyCtxtAt;
|
|
||||||
use crate::ty::{
|
use crate::ty::{
|
||||||
self, DefIdTree, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
|
self, DefIdTree, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
|
||||||
TypeVisitable,
|
TypeVisitable,
|
||||||
|
@ -637,10 +636,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
if visitor.found_recursion { Err(expanded_type) } else { Ok(expanded_type) }
|
if visitor.found_recursion { Err(expanded_type) } else { Ok(expanded_type) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bound_type_of(self, def_id: DefId) -> ty::EarlyBinder<Ty<'tcx>> {
|
|
||||||
ty::EarlyBinder(self.type_of(def_id))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn bound_return_position_impl_trait_in_trait_tys(
|
pub fn bound_return_position_impl_trait_in_trait_tys(
|
||||||
self,
|
self,
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
|
@ -738,12 +733,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> TyCtxtAt<'tcx> {
|
|
||||||
pub fn bound_type_of(self, def_id: DefId) -> ty::EarlyBinder<Ty<'tcx>> {
|
|
||||||
ty::EarlyBinder(self.type_of(def_id))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct OpaqueTypeExpander<'tcx> {
|
struct OpaqueTypeExpander<'tcx> {
|
||||||
// Contains the DefIds of the opaque types that are currently being
|
// Contains the DefIds of the opaque types that are currently being
|
||||||
// expanded. When we expand an opaque type we insert the DefId of
|
// expanded. When we expand an opaque type we insert the DefId of
|
||||||
|
|
|
@ -196,7 +196,7 @@ use crate::cmp::Ordering;
|
||||||
use crate::fmt::{self, Debug, Display};
|
use crate::fmt::{self, Debug, Display};
|
||||||
use crate::marker::{PhantomData, Unsize};
|
use crate::marker::{PhantomData, Unsize};
|
||||||
use crate::mem;
|
use crate::mem;
|
||||||
use crate::ops::{CoerceUnsized, Deref, DerefMut};
|
use crate::ops::{CoerceUnsized, Deref, DerefMut, DispatchFromDyn};
|
||||||
use crate::ptr::{self, NonNull};
|
use crate::ptr::{self, NonNull};
|
||||||
|
|
||||||
mod lazy;
|
mod lazy;
|
||||||
|
@ -571,6 +571,16 @@ impl<T: Default> Cell<T> {
|
||||||
#[unstable(feature = "coerce_unsized", issue = "18598")]
|
#[unstable(feature = "coerce_unsized", issue = "18598")]
|
||||||
impl<T: CoerceUnsized<U>, U> CoerceUnsized<Cell<U>> for Cell<T> {}
|
impl<T: CoerceUnsized<U>, U> CoerceUnsized<Cell<U>> for Cell<T> {}
|
||||||
|
|
||||||
|
// Allow types that wrap `Cell` to also implement `DispatchFromDyn`
|
||||||
|
// and become object safe method receivers.
|
||||||
|
// Note that currently `Cell` itself cannot be a method receiver
|
||||||
|
// because it does not implement Deref.
|
||||||
|
// In other words:
|
||||||
|
// `self: Cell<&Self>` won't work
|
||||||
|
// `self: CellWrapper<Self>` becomes possible
|
||||||
|
#[unstable(feature = "dispatch_from_dyn", issue = "none")]
|
||||||
|
impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<Cell<U>> for Cell<T> {}
|
||||||
|
|
||||||
impl<T> Cell<[T]> {
|
impl<T> Cell<[T]> {
|
||||||
/// Returns a `&[Cell<T>]` from a `&Cell<[T]>`
|
/// Returns a `&[Cell<T>]` from a `&Cell<[T]>`
|
||||||
///
|
///
|
||||||
|
@ -2078,6 +2088,16 @@ impl<T> const From<T> for UnsafeCell<T> {
|
||||||
#[unstable(feature = "coerce_unsized", issue = "18598")]
|
#[unstable(feature = "coerce_unsized", issue = "18598")]
|
||||||
impl<T: CoerceUnsized<U>, U> CoerceUnsized<UnsafeCell<U>> for UnsafeCell<T> {}
|
impl<T: CoerceUnsized<U>, U> CoerceUnsized<UnsafeCell<U>> for UnsafeCell<T> {}
|
||||||
|
|
||||||
|
// Allow types that wrap `UnsafeCell` to also implement `DispatchFromDyn`
|
||||||
|
// and become object safe method receivers.
|
||||||
|
// Note that currently `UnsafeCell` itself cannot be a method receiver
|
||||||
|
// because it does not implement Deref.
|
||||||
|
// In other words:
|
||||||
|
// `self: UnsafeCell<&Self>` won't work
|
||||||
|
// `self: UnsafeCellWrapper<Self>` becomes possible
|
||||||
|
#[unstable(feature = "dispatch_from_dyn", issue = "none")]
|
||||||
|
impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<UnsafeCell<U>> for UnsafeCell<T> {}
|
||||||
|
|
||||||
/// [`UnsafeCell`], but [`Sync`].
|
/// [`UnsafeCell`], but [`Sync`].
|
||||||
///
|
///
|
||||||
/// This is just an `UnsafeCell`, except it implements `Sync`
|
/// This is just an `UnsafeCell`, except it implements `Sync`
|
||||||
|
@ -2169,6 +2189,17 @@ impl<T> const From<T> for SyncUnsafeCell<T> {
|
||||||
//#[unstable(feature = "sync_unsafe_cell", issue = "95439")]
|
//#[unstable(feature = "sync_unsafe_cell", issue = "95439")]
|
||||||
impl<T: CoerceUnsized<U>, U> CoerceUnsized<SyncUnsafeCell<U>> for SyncUnsafeCell<T> {}
|
impl<T: CoerceUnsized<U>, U> CoerceUnsized<SyncUnsafeCell<U>> for SyncUnsafeCell<T> {}
|
||||||
|
|
||||||
|
// Allow types that wrap `SyncUnsafeCell` to also implement `DispatchFromDyn`
|
||||||
|
// and become object safe method receivers.
|
||||||
|
// Note that currently `SyncUnsafeCell` itself cannot be a method receiver
|
||||||
|
// because it does not implement Deref.
|
||||||
|
// In other words:
|
||||||
|
// `self: SyncUnsafeCell<&Self>` won't work
|
||||||
|
// `self: SyncUnsafeCellWrapper<Self>` becomes possible
|
||||||
|
#[unstable(feature = "dispatch_from_dyn", issue = "none")]
|
||||||
|
//#[unstable(feature = "sync_unsafe_cell", issue = "95439")]
|
||||||
|
impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<SyncUnsafeCell<U>> for SyncUnsafeCell<T> {}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
fn assert_coerce_unsized(
|
fn assert_coerce_unsized(
|
||||||
a: UnsafeCell<&i32>,
|
a: UnsafeCell<&i32>,
|
||||||
|
|
|
@ -582,7 +582,7 @@ impl fmt::Debug for Span {
|
||||||
|
|
||||||
/// A line-column pair representing the start or end of a `Span`.
|
/// A line-column pair representing the start or end of a `Span`.
|
||||||
#[unstable(feature = "proc_macro_span", issue = "54725")]
|
#[unstable(feature = "proc_macro_span", issue = "54725")]
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct LineColumn {
|
pub struct LineColumn {
|
||||||
/// The 1-indexed line in the source file on which the span starts or ends (inclusive).
|
/// The 1-indexed line in the source file on which the span starts or ends (inclusive).
|
||||||
#[unstable(feature = "proc_macro_span", issue = "54725")]
|
#[unstable(feature = "proc_macro_span", issue = "54725")]
|
||||||
|
|
|
@ -319,21 +319,12 @@ impl<T> Channel<T> {
|
||||||
) -> Result<(), SendTimeoutError<T>> {
|
) -> Result<(), SendTimeoutError<T>> {
|
||||||
let token = &mut Token::default();
|
let token = &mut Token::default();
|
||||||
loop {
|
loop {
|
||||||
// Try sending a message several times.
|
// Try sending a message.
|
||||||
let backoff = Backoff::new();
|
|
||||||
loop {
|
|
||||||
if self.start_send(token) {
|
if self.start_send(token) {
|
||||||
let res = unsafe { self.write(token, msg) };
|
let res = unsafe { self.write(token, msg) };
|
||||||
return res.map_err(SendTimeoutError::Disconnected);
|
return res.map_err(SendTimeoutError::Disconnected);
|
||||||
}
|
}
|
||||||
|
|
||||||
if backoff.is_completed() {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
backoff.spin_light();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(d) = deadline {
|
if let Some(d) = deadline {
|
||||||
if Instant::now() >= d {
|
if Instant::now() >= d {
|
||||||
return Err(SendTimeoutError::Timeout(msg));
|
return Err(SendTimeoutError::Timeout(msg));
|
||||||
|
@ -379,6 +370,7 @@ impl<T> Channel<T> {
|
||||||
pub(crate) fn recv(&self, deadline: Option<Instant>) -> Result<T, RecvTimeoutError> {
|
pub(crate) fn recv(&self, deadline: Option<Instant>) -> Result<T, RecvTimeoutError> {
|
||||||
let token = &mut Token::default();
|
let token = &mut Token::default();
|
||||||
loop {
|
loop {
|
||||||
|
// Try receiving a message.
|
||||||
if self.start_recv(token) {
|
if self.start_recv(token) {
|
||||||
let res = unsafe { self.read(token) };
|
let res = unsafe { self.read(token) };
|
||||||
return res.map_err(|_| RecvTimeoutError::Disconnected);
|
return res.map_err(|_| RecvTimeoutError::Disconnected);
|
||||||
|
|
|
@ -105,10 +105,8 @@ impl Backoff {
|
||||||
|
|
||||||
/// Backs off using lightweight spinning.
|
/// Backs off using lightweight spinning.
|
||||||
///
|
///
|
||||||
/// This method should be used for:
|
/// This method should be used for retrying an operation because another thread made
|
||||||
/// - Retrying an operation because another thread made progress. i.e. on CAS failure.
|
/// progress. i.e. on CAS failure.
|
||||||
/// - Waiting for an operation to complete by spinning optimistically for a few iterations
|
|
||||||
/// before falling back to parking the thread (see `Backoff::is_completed`).
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn spin_light(&self) {
|
pub fn spin_light(&self) {
|
||||||
let step = self.step.get().min(SPIN_LIMIT);
|
let step = self.step.get().min(SPIN_LIMIT);
|
||||||
|
@ -134,10 +132,4 @@ impl Backoff {
|
||||||
|
|
||||||
self.step.set(self.step.get() + 1);
|
self.step.set(self.step.get() + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if quadratic backoff has completed and parking the thread is advised.
|
|
||||||
#[inline]
|
|
||||||
pub fn is_completed(&self) -> bool {
|
|
||||||
self.step.get() > SPIN_LIMIT
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,13 +11,7 @@
|
||||||
// Note, however, that we run on lots older linuxes, as well as cross
|
// Note, however, that we run on lots older linuxes, as well as cross
|
||||||
// compiling from a newer linux to an older linux, so we also have a
|
// compiling from a newer linux to an older linux, so we also have a
|
||||||
// fallback implementation to use as well.
|
// fallback implementation to use as well.
|
||||||
#[cfg(any(
|
#[cfg(any(target_os = "linux", target_os = "fuchsia", target_os = "redox"))]
|
||||||
target_os = "linux",
|
|
||||||
target_os = "fuchsia",
|
|
||||||
target_os = "redox",
|
|
||||||
target_os = "emscripten"
|
|
||||||
))]
|
|
||||||
#[cfg_attr(target_family = "wasm", allow(unused))] // might remain unused depending on target details (e.g. wasm32-unknown-emscripten)
|
|
||||||
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
|
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
|
||||||
use crate::mem;
|
use crate::mem;
|
||||||
use crate::sys_common::thread_local_dtor::register_dtor_fallback;
|
use crate::sys_common::thread_local_dtor::register_dtor_fallback;
|
||||||
|
@ -89,7 +83,8 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(target_os = "vxworks", target_os = "horizon"))]
|
#[cfg(any(target_os = "vxworks", target_os = "horizon", target_os = "emscripten"))]
|
||||||
|
#[cfg_attr(target_family = "wasm", allow(unused))] // might remain unused depending on target details (e.g. wasm32-unknown-emscripten)
|
||||||
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
|
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
|
||||||
use crate::sys_common::thread_local_dtor::register_dtor_fallback;
|
use crate::sys_common::thread_local_dtor::register_dtor_fallback;
|
||||||
register_dtor_fallback(t, dtor);
|
register_dtor_fallback(t, dtor);
|
||||||
|
|
|
@ -44,4 +44,18 @@ impl AssocConst for () {
|
||||||
const C: Self::Ty = 0u8;
|
const C: Self::Ty = 0u8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait Trait {
|
||||||
|
type Res = isize; //~ NOTE associated type defaults can't be assumed inside the trait defining them
|
||||||
|
|
||||||
|
fn infer_me_correctly() -> Self::Res {
|
||||||
|
//~^ NOTE expected `<Self as Trait>::Res` because of return type
|
||||||
|
|
||||||
|
// {integer} == isize
|
||||||
|
2
|
||||||
|
//~^ ERROR mismatched types
|
||||||
|
//~| NOTE expected associated type, found integer
|
||||||
|
//~| NOTE expected associated type `<Self as Trait>::Res`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -24,6 +24,21 @@ LL | const C: Self::Ty = 0u8;
|
||||||
= note: expected associated type `<Self as AssocConst>::Ty`
|
= note: expected associated type `<Self as AssocConst>::Ty`
|
||||||
found type `u8`
|
found type `u8`
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/defaults-in-other-trait-items.rs:54:9
|
||||||
|
|
|
||||||
|
LL | type Res = isize;
|
||||||
|
| ----------------- associated type defaults can't be assumed inside the trait defining them
|
||||||
|
LL |
|
||||||
|
LL | fn infer_me_correctly() -> Self::Res {
|
||||||
|
| --------- expected `<Self as Trait>::Res` because of return type
|
||||||
|
...
|
||||||
|
LL | 2
|
||||||
|
| ^ expected associated type, found integer
|
||||||
|
|
|
||||||
|
= note: expected associated type `<Self as Trait>::Res`
|
||||||
|
found type `{integer}`
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0308`.
|
For more information about this error, try `rustc --explain E0308`.
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/issue-26681.rs:17:39
|
--> $DIR/issue-26681.rs:17:39
|
||||||
|
|
|
|
||||||
|
LL | type Fv: Foo = u8;
|
||||||
|
| ------------------ associated type defaults can't be assumed inside the trait defining them
|
||||||
LL | const C: <Self::Fv as Foo>::Bar = 6665;
|
LL | const C: <Self::Fv as Foo>::Bar = 6665;
|
||||||
| ^^^^ expected associated type, found integer
|
| ^^^^ expected associated type, found integer
|
||||||
|
|
|
|
||||||
= note: expected associated type `<<Self as Baz>::Fv as Foo>::Bar`
|
= note: expected associated type `<<Self as Baz>::Fv as Foo>::Bar`
|
||||||
found type `{integer}`
|
found type `{integer}`
|
||||||
= help: consider constraining the associated type `<<Self as Baz>::Fv as Foo>::Bar` to `{integer}`
|
|
||||||
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
// Check that even though Cell: DispatchFromDyn it remains an invalid self parameter type
|
||||||
|
|
||||||
|
use std::cell::Cell;
|
||||||
|
|
||||||
|
trait Trait{
|
||||||
|
fn cell(self: Cell<&Self>); //~ ERROR invalid `self` parameter type: Cell<&Self>
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,12 @@
|
||||||
|
error[E0307]: invalid `self` parameter type: Cell<&Self>
|
||||||
|
--> $DIR/feature-gate-dispatch-from-dyn-cell.rs:6:19
|
||||||
|
|
|
||||||
|
LL | fn cell(self: Cell<&Self>);
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: type of `self` must be `Self` or a type that dereferences to it
|
||||||
|
= help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0307`.
|
|
@ -0,0 +1,35 @@
|
||||||
|
// Check that a self parameter type requires a DispatchFromDyn impl to be object safe
|
||||||
|
|
||||||
|
#![feature(arbitrary_self_types, unsize, coerce_unsized)]
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
marker::Unsize,
|
||||||
|
ops::{CoerceUnsized, Deref},
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Ptr<T: ?Sized>(Box<T>);
|
||||||
|
|
||||||
|
impl<T: ?Sized> Deref for Ptr<T> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
fn deref(&self) -> &T {
|
||||||
|
&*self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Unsize<U> + ?Sized, U: ?Sized> CoerceUnsized<Ptr<U>> for Ptr<T> {}
|
||||||
|
// Because this impl is missing the coercion below fails.
|
||||||
|
// impl<T: Unsize<U> + ?Sized, U: ?Sized> DispatchFromDyn<Ptr<U>> for Ptr<T> {}
|
||||||
|
|
||||||
|
trait Trait {
|
||||||
|
fn ptr(self: Ptr<Self>);
|
||||||
|
}
|
||||||
|
impl Trait for i32 {
|
||||||
|
fn ptr(self: Ptr<Self>) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
Ptr(Box::new(4)) as Ptr<dyn Trait>;
|
||||||
|
//~^ ERROR the trait `Trait` cannot be made into an object
|
||||||
|
//~^^ ERROR the trait `Trait` cannot be made into an object
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
error[E0038]: the trait `Trait` cannot be made into an object
|
||||||
|
--> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:32:25
|
||||||
|
|
|
||||||
|
LL | fn ptr(self: Ptr<Self>);
|
||||||
|
| --------- help: consider changing method `ptr`'s `self` parameter to be `&self`: `&Self`
|
||||||
|
...
|
||||||
|
LL | Ptr(Box::new(4)) as Ptr<dyn Trait>;
|
||||||
|
| ^^^^^^^^^^^^^^ `Trait` cannot be made into an object
|
||||||
|
|
|
||||||
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
|
||||||
|
--> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:25:18
|
||||||
|
|
|
||||||
|
LL | trait Trait {
|
||||||
|
| ----- this trait cannot be made into an object...
|
||||||
|
LL | fn ptr(self: Ptr<Self>);
|
||||||
|
| ^^^^^^^^^ ...because method `ptr`'s `self` parameter cannot be dispatched on
|
||||||
|
|
||||||
|
error[E0038]: the trait `Trait` cannot be made into an object
|
||||||
|
--> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:32:5
|
||||||
|
|
|
||||||
|
LL | fn ptr(self: Ptr<Self>);
|
||||||
|
| --------- help: consider changing method `ptr`'s `self` parameter to be `&self`: `&Self`
|
||||||
|
...
|
||||||
|
LL | Ptr(Box::new(4)) as Ptr<dyn Trait>;
|
||||||
|
| ^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object
|
||||||
|
|
|
||||||
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
|
||||||
|
--> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:25:18
|
||||||
|
|
|
||||||
|
LL | trait Trait {
|
||||||
|
| ----- this trait cannot be made into an object...
|
||||||
|
LL | fn ptr(self: Ptr<Self>);
|
||||||
|
| ^^^^^^^^^ ...because method `ptr`'s `self` parameter cannot be dispatched on
|
||||||
|
note: required for `Ptr<{integer}>` to implement `CoerceUnsized<Ptr<dyn Trait>>`
|
||||||
|
--> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:20:40
|
||||||
|
|
|
||||||
|
LL | impl<T: Unsize<U> + ?Sized, U: ?Sized> CoerceUnsized<Ptr<U>> for Ptr<T> {}
|
||||||
|
| --------- ^^^^^^^^^^^^^^^^^^^^^ ^^^^^^
|
||||||
|
| |
|
||||||
|
| unsatisfied trait bound introduced here
|
||||||
|
= note: required by cast to type `Ptr<dyn Trait>`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0038`.
|
|
@ -20,6 +20,7 @@ LL | let x = f == g;
|
||||||
= note: expected fn item `fn() {f}`
|
= note: expected fn item `fn() {f}`
|
||||||
found fn item `fn() {g}`
|
found fn item `fn() {g}`
|
||||||
= note: different fn items have unique types, even if their signatures are the same
|
= note: different fn items have unique types, even if their signatures are the same
|
||||||
|
= help: consider casting both fn items to fn pointers using `as fn()`
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ note: function defined here
|
||||||
|
|
|
|
||||||
LL | fn eq<T>(x: T, y: T) {}
|
LL | fn eq<T>(x: T, y: T) {}
|
||||||
| ^^ ----
|
| ^^ ----
|
||||||
|
= help: consider casting both fn items to fn pointers using `as fn(isize) -> isize`
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/fn-item-type.rs:29:19
|
--> $DIR/fn-item-type.rs:29:19
|
||||||
|
@ -31,6 +32,7 @@ note: function defined here
|
||||||
|
|
|
|
||||||
LL | fn eq<T>(x: T, y: T) {}
|
LL | fn eq<T>(x: T, y: T) {}
|
||||||
| ^^ ----
|
| ^^ ----
|
||||||
|
= help: consider casting both fn items to fn pointers using `as fn(isize) -> isize`
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/fn-item-type.rs:34:23
|
--> $DIR/fn-item-type.rs:34:23
|
||||||
|
@ -48,6 +50,7 @@ note: function defined here
|
||||||
|
|
|
|
||||||
LL | fn eq<T>(x: T, y: T) {}
|
LL | fn eq<T>(x: T, y: T) {}
|
||||||
| ^^ ----
|
| ^^ ----
|
||||||
|
= help: consider casting both fn items to fn pointers using `as fn(isize) -> isize`
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/fn-item-type.rs:41:26
|
--> $DIR/fn-item-type.rs:41:26
|
||||||
|
@ -65,6 +68,7 @@ note: function defined here
|
||||||
|
|
|
|
||||||
LL | fn eq<T>(x: T, y: T) {}
|
LL | fn eq<T>(x: T, y: T) {}
|
||||||
| ^^ ----
|
| ^^ ----
|
||||||
|
= help: consider casting both fn items to fn pointers using `as fn()`
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/fn-item-type.rs:46:19
|
--> $DIR/fn-item-type.rs:46:19
|
||||||
|
@ -76,7 +80,7 @@ LL | eq(foo::<u8>, bar::<u8> as fn(isize) -> isize);
|
||||||
|
|
|
|
||||||
= note: expected fn item `fn(_) -> _ {foo::<u8>}`
|
= note: expected fn item `fn(_) -> _ {foo::<u8>}`
|
||||||
found fn pointer `fn(_) -> _`
|
found fn pointer `fn(_) -> _`
|
||||||
= note: fn items are distinct from fn pointers
|
= help: consider casting the fn item to a fn pointer: `foo::<u8> as fn(isize) -> isize`
|
||||||
note: function defined here
|
note: function defined here
|
||||||
--> $DIR/fn-item-type.rs:11:4
|
--> $DIR/fn-item-type.rs:11:4
|
||||||
|
|
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ LL | let g = if n % 2 == 0 { &foo } else { &bar };
|
||||||
= note: expected reference `&fn(u32) -> u32 {foo}`
|
= note: expected reference `&fn(u32) -> u32 {foo}`
|
||||||
found reference `&fn(u32) -> u32 {bar}`
|
found reference `&fn(u32) -> u32 {bar}`
|
||||||
= note: different fn items have unique types, even if their signatures are the same
|
= note: different fn items have unique types, even if their signatures are the same
|
||||||
|
= help: consider casting both fn items to fn pointers using `as fn(u32) -> u32`
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/fn-pointer-mismatch.rs:23:9
|
--> $DIR/fn-pointer-mismatch.rs:23:9
|
||||||
|
@ -21,6 +22,7 @@ LL | a = bar;
|
||||||
= note: expected fn item `fn(_) -> _ {foo}`
|
= note: expected fn item `fn(_) -> _ {foo}`
|
||||||
found fn item `fn(_) -> _ {bar}`
|
found fn item `fn(_) -> _ {bar}`
|
||||||
= note: different fn items have unique types, even if their signatures are the same
|
= note: different fn items have unique types, even if their signatures are the same
|
||||||
|
= help: consider casting both fn items to fn pointers using `as fn(u32) -> u32`
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/fn-pointer-mismatch.rs:31:18
|
--> $DIR/fn-pointer-mismatch.rs:31:18
|
||||||
|
@ -35,6 +37,7 @@ LL | b = Box::new(bar);
|
||||||
= note: different fn items have unique types, even if their signatures are the same
|
= note: different fn items have unique types, even if their signatures are the same
|
||||||
note: associated function defined here
|
note: associated function defined here
|
||||||
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
|
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
|
||||||
|
= help: consider casting both fn items to fn pointers using `as fn(u32) -> u32`
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/fn-pointer-mismatch.rs:36:29
|
--> $DIR/fn-pointer-mismatch.rs:36:29
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#![feature(rustc_attrs)]
|
#![feature(rustc_attrs)]
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
|
cell::Cell,
|
||||||
ops::{Deref, CoerceUnsized, DispatchFromDyn},
|
ops::{Deref, CoerceUnsized, DispatchFromDyn},
|
||||||
marker::Unsize,
|
marker::Unsize,
|
||||||
};
|
};
|
||||||
|
@ -20,6 +21,20 @@ impl<T: ?Sized> Deref for Ptr<T> {
|
||||||
impl<T: Unsize<U> + ?Sized, U: ?Sized> CoerceUnsized<Ptr<U>> for Ptr<T> {}
|
impl<T: Unsize<U> + ?Sized, U: ?Sized> CoerceUnsized<Ptr<U>> for Ptr<T> {}
|
||||||
impl<T: Unsize<U> + ?Sized, U: ?Sized> DispatchFromDyn<Ptr<U>> for Ptr<T> {}
|
impl<T: Unsize<U> + ?Sized, U: ?Sized> DispatchFromDyn<Ptr<U>> for Ptr<T> {}
|
||||||
|
|
||||||
|
|
||||||
|
struct CellPtr<'a, T: ?Sized>(Cell<&'a T>);
|
||||||
|
|
||||||
|
impl<'a, T: ?Sized> Deref for CellPtr<'a, T> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
fn deref(&self) -> &T {
|
||||||
|
self.0.get()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: Unsize<U> + ?Sized, U: ?Sized> CoerceUnsized<CellPtr<'a, U>> for CellPtr<'a, T> {}
|
||||||
|
impl<'a, T: Unsize<U> + ?Sized, U: ?Sized> DispatchFromDyn<CellPtr<'a, U>> for CellPtr<'a, T> {}
|
||||||
|
|
||||||
struct Wrapper<T: ?Sized>(T);
|
struct Wrapper<T: ?Sized>(T);
|
||||||
|
|
||||||
impl<T: ?Sized> Deref for Wrapper<T> {
|
impl<T: ?Sized> Deref for Wrapper<T> {
|
||||||
|
@ -42,6 +57,7 @@ trait Trait {
|
||||||
fn ptr_wrapper(self: Ptr<Wrapper<Self>>) -> i32;
|
fn ptr_wrapper(self: Ptr<Wrapper<Self>>) -> i32;
|
||||||
fn wrapper_ptr(self: Wrapper<Ptr<Self>>) -> i32;
|
fn wrapper_ptr(self: Wrapper<Ptr<Self>>) -> i32;
|
||||||
fn wrapper_ptr_wrapper(self: Wrapper<Ptr<Wrapper<Self>>>) -> i32;
|
fn wrapper_ptr_wrapper(self: Wrapper<Ptr<Wrapper<Self>>>) -> i32;
|
||||||
|
fn cell(self: CellPtr<Self>) -> i32;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Trait for i32 {
|
impl Trait for i32 {
|
||||||
|
@ -54,6 +70,9 @@ impl Trait for i32 {
|
||||||
fn wrapper_ptr_wrapper(self: Wrapper<Ptr<Wrapper<Self>>>) -> i32 {
|
fn wrapper_ptr_wrapper(self: Wrapper<Ptr<Wrapper<Self>>>) -> i32 {
|
||||||
***self
|
***self
|
||||||
}
|
}
|
||||||
|
fn cell(self: CellPtr<Self>) -> i32 {
|
||||||
|
*self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -65,4 +84,7 @@ fn main() {
|
||||||
|
|
||||||
let wpw = Wrapper(Ptr(Box::new(Wrapper(7)))) as Wrapper<Ptr<Wrapper<dyn Trait>>>;
|
let wpw = Wrapper(Ptr(Box::new(Wrapper(7)))) as Wrapper<Ptr<Wrapper<dyn Trait>>>;
|
||||||
assert_eq!(wpw.wrapper_ptr_wrapper(), 7);
|
assert_eq!(wpw.wrapper_ptr_wrapper(), 7);
|
||||||
|
|
||||||
|
let c = CellPtr(Cell::new(&8)) as CellPtr<dyn Trait>;
|
||||||
|
assert_eq!(c.cell(), 8);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue