Auto merge of #96459 - Dylan-DPC:rollup-de6ud9d, r=Dylan-DPC
Rollup of 6 pull requests Successful merges: - #92569 (Improve Error Messaging for Unconstructed Structs and Enum Variants in Generic Contexts) - #96370 (Cleanup `report_method_error` a bit) - #96383 (Fix erased region escaping into wfcheck due to #95395) - #96385 (Recover most `impl Trait` and `dyn Trait` lifetime bound suggestions under NLL) - #96410 (rustdoc: do not write `{{root}}` in `pub use ::foo` docs) - #96430 (Fix handling of `!` in rustdoc search) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
99b70ee230
@ -1,17 +1,17 @@
|
||||
//! Error reporting machinery for lifetime errors.
|
||||
|
||||
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
|
||||
use rustc_errors::{Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
|
||||
use rustc_infer::infer::{
|
||||
error_reporting::nice_region_error::NiceRegionError,
|
||||
error_reporting::unexpected_hidden_region_diagnostic, NllRegionVariableOrigin,
|
||||
RelateParamBound,
|
||||
error_reporting::nice_region_error::{self, find_param_with_region, NiceRegionError},
|
||||
error_reporting::unexpected_hidden_region_diagnostic,
|
||||
NllRegionVariableOrigin, RelateParamBound,
|
||||
};
|
||||
use rustc_middle::hir::place::PlaceBase;
|
||||
use rustc_middle::mir::{ConstraintCategory, ReturnConstraint};
|
||||
use rustc_middle::ty::subst::{InternalSubsts, Subst};
|
||||
use rustc_middle::ty::subst::InternalSubsts;
|
||||
use rustc_middle::ty::{self, RegionVid, Ty};
|
||||
use rustc_span::symbol::{kw, sym};
|
||||
use rustc_span::{BytePos, Span};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
|
||||
use crate::borrowck_errors;
|
||||
|
||||
@ -651,82 +651,47 @@ fn add_static_impl_trait_suggestion(
|
||||
fr_name: RegionName,
|
||||
outlived_fr: RegionVid,
|
||||
) {
|
||||
if let (Some(f), Some(ty::ReStatic)) =
|
||||
(self.to_error_region(fr), self.to_error_region(outlived_fr).as_deref())
|
||||
if let (Some(f), Some(outlived_f)) =
|
||||
(self.to_error_region(fr), self.to_error_region(outlived_fr))
|
||||
{
|
||||
if let Some(&ty::Opaque(did, substs)) = self
|
||||
if *outlived_f != ty::ReStatic {
|
||||
return;
|
||||
}
|
||||
|
||||
let fn_returns = self
|
||||
.infcx
|
||||
.tcx
|
||||
.is_suitable_region(f)
|
||||
.map(|r| r.def_id)
|
||||
.and_then(|id| self.infcx.tcx.return_type_impl_trait(id))
|
||||
.map(|(ty, _)| ty.kind())
|
||||
{
|
||||
// Check whether or not the impl trait return type is intended to capture
|
||||
// data with the static lifetime.
|
||||
//
|
||||
// eg. check for `impl Trait + 'static` instead of `impl Trait`.
|
||||
let has_static_predicate = {
|
||||
let bounds = self.infcx.tcx.explicit_item_bounds(did);
|
||||
.map(|r| self.infcx.tcx.return_type_impl_or_dyn_traits(r.def_id))
|
||||
.unwrap_or_default();
|
||||
|
||||
let mut found = false;
|
||||
for (bound, _) in bounds {
|
||||
if let ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(_, r)) =
|
||||
bound.kind().skip_binder()
|
||||
{
|
||||
let r = r.subst(self.infcx.tcx, substs);
|
||||
if r.is_static() {
|
||||
found = true;
|
||||
break;
|
||||
} else {
|
||||
// If there's already a lifetime bound, don't
|
||||
// suggest anything.
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
found
|
||||
};
|
||||
|
||||
debug!(
|
||||
"add_static_impl_trait_suggestion: has_static_predicate={:?}",
|
||||
has_static_predicate
|
||||
);
|
||||
let static_str = kw::StaticLifetime;
|
||||
// If there is a static predicate, then the only sensible suggestion is to replace
|
||||
// fr with `'static`.
|
||||
if has_static_predicate {
|
||||
diag.help(&format!("consider replacing `{fr_name}` with `{static_str}`"));
|
||||
} else {
|
||||
// Otherwise, we should suggest adding a constraint on the return type.
|
||||
let span = self.infcx.tcx.def_span(did);
|
||||
if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
|
||||
let suggestable_fr_name = if fr_name.was_named() {
|
||||
fr_name.to_string()
|
||||
} else {
|
||||
"'_".to_string()
|
||||
};
|
||||
let span = if snippet.ends_with(';') {
|
||||
// `type X = impl Trait;`
|
||||
span.with_hi(span.hi() - BytePos(1))
|
||||
} else {
|
||||
span
|
||||
};
|
||||
let suggestion = format!(" + {suggestable_fr_name}");
|
||||
let span = span.shrink_to_hi();
|
||||
diag.span_suggestion(
|
||||
span,
|
||||
&format!(
|
||||
"to allow this `impl Trait` to capture borrowed data with lifetime \
|
||||
`{fr_name}`, add `{suggestable_fr_name}` as a bound",
|
||||
),
|
||||
suggestion,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
if fn_returns.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let param = if let Some(param) = find_param_with_region(self.infcx.tcx, f, outlived_f) {
|
||||
param
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
|
||||
let lifetime = if f.has_name() { fr_name.to_string() } else { "'_".to_string() };
|
||||
|
||||
let arg = match param.param.pat.simple_ident() {
|
||||
Some(simple_ident) => format!("argument `{}`", simple_ident),
|
||||
None => "the argument".to_string(),
|
||||
};
|
||||
let captures = format!("captures data from {}", arg);
|
||||
|
||||
return nice_region_error::suggest_new_region_bound(
|
||||
self.infcx.tcx,
|
||||
diag,
|
||||
fn_returns,
|
||||
lifetime,
|
||||
Some(arg),
|
||||
captures,
|
||||
Some((param.param_ty_span, param.param_ty.to_string())),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3314,6 +3314,12 @@ pub fn fn_kind(self) -> Option<FnKind<'hir>> {
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the fields for the tuple-constructor,
|
||||
/// if this node is a tuple constructor, otherwise None
|
||||
pub fn tuple_fields(&self) -> Option<&'hir [FieldDef<'hir>]> {
|
||||
if let Node::Ctor(&VariantData::Tuple(fields, _)) = self { Some(fields) } else { None }
|
||||
}
|
||||
}
|
||||
|
||||
// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
|
||||
|
@ -15,6 +15,7 @@
|
||||
mod util;
|
||||
|
||||
pub use static_impl_trait::suggest_new_region_bound;
|
||||
pub use util::find_param_with_region;
|
||||
|
||||
impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
||||
pub fn try_report_nice_region_error(&self, error: &RegionResolutionError<'tcx>) -> bool {
|
||||
|
@ -2,6 +2,7 @@
|
||||
//! anonymous regions.
|
||||
|
||||
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
|
||||
use crate::infer::TyCtxt;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_middle::ty::{self, Binder, DefIdTree, Region, Ty, TypeFoldable};
|
||||
@ -9,7 +10,7 @@
|
||||
|
||||
/// Information about the anonymous region we are searching for.
|
||||
#[derive(Debug)]
|
||||
pub(super) struct AnonymousParamInfo<'tcx> {
|
||||
pub struct AnonymousParamInfo<'tcx> {
|
||||
/// The parameter corresponding to the anonymous region.
|
||||
pub param: &'tcx hir::Param<'tcx>,
|
||||
/// The type corresponding to the anonymous region parameter.
|
||||
@ -22,76 +23,83 @@ pub(super) struct AnonymousParamInfo<'tcx> {
|
||||
pub is_first: bool,
|
||||
}
|
||||
|
||||
// This method walks the Type of the function body parameters using
|
||||
// `fold_regions()` function and returns the
|
||||
// &hir::Param of the function parameter corresponding to the anonymous
|
||||
// region and the Ty corresponding to the named region.
|
||||
// Currently only the case where the function declaration consists of
|
||||
// one named region and one anonymous region is handled.
|
||||
// Consider the example `fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32`
|
||||
// Here, we would return the hir::Param for y, we return the type &'a
|
||||
// i32, which is the type of y but with the anonymous region replaced
|
||||
// with 'a, the corresponding bound region and is_first which is true if
|
||||
// the hir::Param is the first parameter in the function declaration.
|
||||
pub fn find_param_with_region<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
anon_region: Region<'tcx>,
|
||||
replace_region: Region<'tcx>,
|
||||
) -> Option<AnonymousParamInfo<'tcx>> {
|
||||
let (id, bound_region) = match *anon_region {
|
||||
ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region),
|
||||
ty::ReEarlyBound(ebr) => {
|
||||
(tcx.parent(ebr.def_id).unwrap(), ty::BoundRegionKind::BrNamed(ebr.def_id, ebr.name))
|
||||
}
|
||||
_ => return None, // not a free region
|
||||
};
|
||||
|
||||
let hir = &tcx.hir();
|
||||
let hir_id = hir.local_def_id_to_hir_id(id.as_local()?);
|
||||
let body_id = hir.maybe_body_owned_by(hir_id)?;
|
||||
let body = hir.body(body_id);
|
||||
let owner_id = hir.body_owner(body_id);
|
||||
let fn_decl = hir.fn_decl_by_hir_id(owner_id).unwrap();
|
||||
let poly_fn_sig = tcx.fn_sig(id);
|
||||
let fn_sig = tcx.liberate_late_bound_regions(id, poly_fn_sig);
|
||||
body.params
|
||||
.iter()
|
||||
.take(if fn_sig.c_variadic {
|
||||
fn_sig.inputs().len()
|
||||
} else {
|
||||
assert_eq!(fn_sig.inputs().len(), body.params.len());
|
||||
body.params.len()
|
||||
})
|
||||
.enumerate()
|
||||
.find_map(|(index, param)| {
|
||||
// May return None; sometimes the tables are not yet populated.
|
||||
let ty = fn_sig.inputs()[index];
|
||||
let mut found_anon_region = false;
|
||||
let new_param_ty = tcx.fold_regions(ty, &mut false, |r, _| {
|
||||
if r == anon_region {
|
||||
found_anon_region = true;
|
||||
replace_region
|
||||
} else {
|
||||
r
|
||||
}
|
||||
});
|
||||
if found_anon_region {
|
||||
let ty_hir_id = fn_decl.inputs[index].hir_id;
|
||||
let param_ty_span = hir.span(ty_hir_id);
|
||||
let is_first = index == 0;
|
||||
Some(AnonymousParamInfo {
|
||||
param,
|
||||
param_ty: new_param_ty,
|
||||
param_ty_span,
|
||||
bound_region,
|
||||
is_first,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
||||
// This method walks the Type of the function body parameters using
|
||||
// `fold_regions()` function and returns the
|
||||
// &hir::Param of the function parameter corresponding to the anonymous
|
||||
// region and the Ty corresponding to the named region.
|
||||
// Currently only the case where the function declaration consists of
|
||||
// one named region and one anonymous region is handled.
|
||||
// Consider the example `fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32`
|
||||
// Here, we would return the hir::Param for y, we return the type &'a
|
||||
// i32, which is the type of y but with the anonymous region replaced
|
||||
// with 'a, the corresponding bound region and is_first which is true if
|
||||
// the hir::Param is the first parameter in the function declaration.
|
||||
pub(super) fn find_param_with_region(
|
||||
&self,
|
||||
anon_region: Region<'tcx>,
|
||||
replace_region: Region<'tcx>,
|
||||
) -> Option<AnonymousParamInfo<'_>> {
|
||||
let (id, bound_region) = match *anon_region {
|
||||
ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region),
|
||||
ty::ReEarlyBound(ebr) => (
|
||||
self.tcx().parent(ebr.def_id).unwrap(),
|
||||
ty::BoundRegionKind::BrNamed(ebr.def_id, ebr.name),
|
||||
),
|
||||
_ => return None, // not a free region
|
||||
};
|
||||
|
||||
let hir = &self.tcx().hir();
|
||||
let hir_id = hir.local_def_id_to_hir_id(id.as_local()?);
|
||||
let body_id = hir.maybe_body_owned_by(hir_id)?;
|
||||
let body = hir.body(body_id);
|
||||
let owner_id = hir.body_owner(body_id);
|
||||
let fn_decl = hir.fn_decl_by_hir_id(owner_id).unwrap();
|
||||
let poly_fn_sig = self.tcx().fn_sig(id);
|
||||
let fn_sig = self.tcx().liberate_late_bound_regions(id, poly_fn_sig);
|
||||
body.params
|
||||
.iter()
|
||||
.take(if fn_sig.c_variadic {
|
||||
fn_sig.inputs().len()
|
||||
} else {
|
||||
assert_eq!(fn_sig.inputs().len(), body.params.len());
|
||||
body.params.len()
|
||||
})
|
||||
.enumerate()
|
||||
.find_map(|(index, param)| {
|
||||
// May return None; sometimes the tables are not yet populated.
|
||||
let ty = fn_sig.inputs()[index];
|
||||
let mut found_anon_region = false;
|
||||
let new_param_ty = self.tcx().fold_regions(ty, &mut false, |r, _| {
|
||||
if r == anon_region {
|
||||
found_anon_region = true;
|
||||
replace_region
|
||||
} else {
|
||||
r
|
||||
}
|
||||
});
|
||||
if found_anon_region {
|
||||
let ty_hir_id = fn_decl.inputs[index].hir_id;
|
||||
let param_ty_span = hir.span(ty_hir_id);
|
||||
let is_first = index == 0;
|
||||
Some(AnonymousParamInfo {
|
||||
param,
|
||||
param_ty: new_param_ty,
|
||||
param_ty_span,
|
||||
bound_region,
|
||||
is_first,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
find_param_with_region(self.tcx(), anon_region, replace_region)
|
||||
}
|
||||
|
||||
// Here, we check for the case where the anonymous region
|
||||
|
@ -2681,21 +2681,21 @@ fn suggest_trait_fn_ty_for_impl_fn_infer(
|
||||
let trait_ref =
|
||||
self.instantiate_mono_trait_ref(i.of_trait.as_ref()?, self.ast_ty_to_ty(i.self_ty));
|
||||
|
||||
let x: &ty::AssocItem = tcx.associated_items(trait_ref.def_id).find_by_name_and_kind(
|
||||
let assoc = tcx.associated_items(trait_ref.def_id).find_by_name_and_kind(
|
||||
tcx,
|
||||
*ident,
|
||||
ty::AssocKind::Fn,
|
||||
trait_ref.def_id,
|
||||
)?;
|
||||
|
||||
let fn_sig = tcx.fn_sig(x.def_id).subst(
|
||||
let fn_sig = tcx.fn_sig(assoc.def_id).subst(
|
||||
tcx,
|
||||
trait_ref.substs.extend_to(tcx, x.def_id, |param, _| tcx.mk_param_from_def(param)),
|
||||
trait_ref.substs.extend_to(tcx, assoc.def_id, |param, _| tcx.mk_param_from_def(param)),
|
||||
);
|
||||
|
||||
let ty = if let Some(arg_idx) = arg_idx { fn_sig.input(arg_idx) } else { fn_sig.output() };
|
||||
|
||||
Some(tcx.erase_late_bound_regions(ty))
|
||||
Some(tcx.liberate_late_bound_regions(fn_hir_id.expect_owner().to_def_id(), ty))
|
||||
}
|
||||
|
||||
fn validate_late_bound_regions(
|
||||
|
@ -21,11 +21,13 @@
|
||||
};
|
||||
use crate::type_error_struct;
|
||||
|
||||
use super::suggest_call_constructor;
|
||||
use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive};
|
||||
use rustc_ast as ast;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_errors::Diagnostic;
|
||||
use rustc_errors::EmissionGuarantee;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, DiagnosticId};
|
||||
use rustc_hir as hir;
|
||||
@ -1986,6 +1988,26 @@ fn check_field(
|
||||
self.tcx().ty_error()
|
||||
}
|
||||
|
||||
fn check_call_constructor<G: EmissionGuarantee>(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'_, G>,
|
||||
base: &'tcx hir::Expr<'tcx>,
|
||||
def_id: DefId,
|
||||
) {
|
||||
let local_id = def_id.expect_local();
|
||||
let hir_id = self.tcx.hir().local_def_id_to_hir_id(local_id);
|
||||
let node = self.tcx.hir().get(hir_id);
|
||||
|
||||
if let Some(fields) = node.tuple_fields() {
|
||||
let kind = match self.tcx.opt_def_kind(local_id) {
|
||||
Some(DefKind::Ctor(of, _)) => of,
|
||||
_ => return,
|
||||
};
|
||||
|
||||
suggest_call_constructor(base.span, kind, fields.len(), err);
|
||||
}
|
||||
}
|
||||
|
||||
fn suggest_await_on_field_access(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
@ -2055,6 +2077,9 @@ fn ban_nonexisting_field(
|
||||
ty::Opaque(_, _) => {
|
||||
self.suggest_await_on_field_access(&mut err, field, base, expr_t.peel_refs());
|
||||
}
|
||||
ty::FnDef(def_id, _) => {
|
||||
self.check_call_constructor(&mut err, base, def_id);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
MultiSpan,
|
||||
};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{ExprKind, Node, QPath};
|
||||
@ -29,7 +30,7 @@
|
||||
use std::iter;
|
||||
|
||||
use super::probe::{Mode, ProbeScope};
|
||||
use super::{CandidateSource, MethodError, NoMatchData};
|
||||
use super::{super::suggest_call_constructor, CandidateSource, MethodError, NoMatchData};
|
||||
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
|
||||
@ -271,207 +272,84 @@ pub fn report_method_error(
|
||||
(None, true) => "variant",
|
||||
}
|
||||
};
|
||||
// FIXME(eddyb) this indentation is probably unnecessary.
|
||||
let mut err = {
|
||||
// Suggest clamping down the type if the method that is being attempted to
|
||||
// be used exists at all, and the type is an ambiguous numeric type
|
||||
// ({integer}/{float}).
|
||||
let mut candidates = all_traits(self.tcx)
|
||||
.into_iter()
|
||||
.filter_map(|info| self.associated_value(info.def_id, item_name));
|
||||
// There are methods that are defined on the primitive types and won't be
|
||||
// found when exploring `all_traits`, but we also need them to be accurate on
|
||||
// our suggestions (#47759).
|
||||
let found_assoc = |ty: Ty<'tcx>| {
|
||||
simplify_type(tcx, ty, TreatParams::AsPlaceholders)
|
||||
.and_then(|simp| {
|
||||
tcx.incoherent_impls(simp)
|
||||
|
||||
if self.suggest_constraining_numerical_ty(
|
||||
tcx, actual, source, span, item_kind, item_name, &ty_str,
|
||||
) {
|
||||
return None;
|
||||
}
|
||||
|
||||
span = item_name.span;
|
||||
|
||||
// Don't show generic arguments when the method can't be found in any implementation (#81576).
|
||||
let mut ty_str_reported = ty_str.clone();
|
||||
if let ty::Adt(_, generics) = actual.kind() {
|
||||
if generics.len() > 0 {
|
||||
let mut autoderef = self.autoderef(span, actual);
|
||||
let candidate_found = autoderef.any(|(ty, _)| {
|
||||
if let ty::Adt(adt_deref, _) = ty.kind() {
|
||||
self.tcx
|
||||
.inherent_impls(adt_deref.did())
|
||||
.iter()
|
||||
.find_map(|&id| self.associated_value(id, item_name))
|
||||
})
|
||||
.is_some()
|
||||
};
|
||||
let found_candidate = candidates.next().is_some()
|
||||
|| found_assoc(tcx.types.i8)
|
||||
|| found_assoc(tcx.types.i16)
|
||||
|| found_assoc(tcx.types.i32)
|
||||
|| found_assoc(tcx.types.i64)
|
||||
|| found_assoc(tcx.types.i128)
|
||||
|| found_assoc(tcx.types.u8)
|
||||
|| found_assoc(tcx.types.u16)
|
||||
|| found_assoc(tcx.types.u32)
|
||||
|| found_assoc(tcx.types.u64)
|
||||
|| found_assoc(tcx.types.u128)
|
||||
|| found_assoc(tcx.types.f32)
|
||||
|| found_assoc(tcx.types.f32);
|
||||
if let (true, false, SelfSource::MethodCall(expr), true) = (
|
||||
actual.is_numeric(),
|
||||
actual.has_concrete_skeleton(),
|
||||
source,
|
||||
found_candidate,
|
||||
) {
|
||||
let mut err = struct_span_err!(
|
||||
tcx.sess,
|
||||
span,
|
||||
E0689,
|
||||
"can't call {} `{}` on ambiguous numeric type `{}`",
|
||||
item_kind,
|
||||
item_name,
|
||||
ty_str
|
||||
);
|
||||
let concrete_type = if actual.is_integral() { "i32" } else { "f32" };
|
||||
match expr.kind {
|
||||
ExprKind::Lit(ref lit) => {
|
||||
// numeric literal
|
||||
let snippet = tcx
|
||||
.sess
|
||||
.source_map()
|
||||
.span_to_snippet(lit.span)
|
||||
.unwrap_or_else(|_| "<numeric literal>".to_owned());
|
||||
|
||||
// If this is a floating point literal that ends with '.',
|
||||
// get rid of it to stop this from becoming a member access.
|
||||
let snippet = snippet.strip_suffix('.').unwrap_or(&snippet);
|
||||
|
||||
err.span_suggestion(
|
||||
lit.span,
|
||||
&format!(
|
||||
"you must specify a concrete type for this numeric value, \
|
||||
like `{}`",
|
||||
concrete_type
|
||||
),
|
||||
format!("{snippet}_{concrete_type}"),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
.filter_map(|def_id| self.associated_value(*def_id, item_name))
|
||||
.count()
|
||||
>= 1
|
||||
} else {
|
||||
false
|
||||
}
|
||||
ExprKind::Path(QPath::Resolved(_, path)) => {
|
||||
// local binding
|
||||
if let hir::def::Res::Local(hir_id) = path.res {
|
||||
let span = tcx.hir().span(hir_id);
|
||||
let snippet = tcx.sess.source_map().span_to_snippet(span);
|
||||
let filename = tcx.sess.source_map().span_to_filename(span);
|
||||
|
||||
let parent_node =
|
||||
self.tcx.hir().get(self.tcx.hir().get_parent_node(hir_id));
|
||||
let msg = format!(
|
||||
"you must specify a type for this binding, like `{}`",
|
||||
concrete_type,
|
||||
);
|
||||
|
||||
match (filename, parent_node, snippet) {
|
||||
(
|
||||
FileName::Real(_),
|
||||
Node::Local(hir::Local {
|
||||
source: hir::LocalSource::Normal,
|
||||
ty,
|
||||
..
|
||||
}),
|
||||
Ok(ref snippet),
|
||||
) => {
|
||||
err.span_suggestion(
|
||||
// account for `let x: _ = 42;`
|
||||
// ^^^^
|
||||
span.to(ty
|
||||
.as_ref()
|
||||
.map(|ty| ty.span)
|
||||
.unwrap_or(span)),
|
||||
&msg,
|
||||
format!("{}: {}", snippet, concrete_type),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
err.span_label(span, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
err.emit();
|
||||
return None;
|
||||
} else {
|
||||
span = item_name.span;
|
||||
|
||||
// Don't show generic arguments when the method can't be found in any implementation (#81576).
|
||||
let mut ty_str_reported = ty_str.clone();
|
||||
if let ty::Adt(_, generics) = actual.kind() {
|
||||
if generics.len() > 0 {
|
||||
let mut autoderef = self.autoderef(span, actual);
|
||||
let candidate_found = autoderef.any(|(ty, _)| {
|
||||
if let ty::Adt(adt_deref, _) = ty.kind() {
|
||||
self.tcx
|
||||
.inherent_impls(adt_deref.did())
|
||||
.iter()
|
||||
.filter_map(|def_id| {
|
||||
self.associated_value(*def_id, item_name)
|
||||
})
|
||||
.count()
|
||||
>= 1
|
||||
} else {
|
||||
false
|
||||
}
|
||||
});
|
||||
let has_deref = autoderef.step_count() > 0;
|
||||
if !candidate_found
|
||||
&& !has_deref
|
||||
&& unsatisfied_predicates.is_empty()
|
||||
{
|
||||
if let Some((path_string, _)) = ty_str.split_once('<') {
|
||||
ty_str_reported = path_string.to_string();
|
||||
}
|
||||
}
|
||||
});
|
||||
let has_deref = autoderef.step_count() > 0;
|
||||
if !candidate_found && !has_deref && unsatisfied_predicates.is_empty() {
|
||||
if let Some((path_string, _)) = ty_str.split_once('<') {
|
||||
ty_str_reported = path_string.to_string();
|
||||
}
|
||||
}
|
||||
|
||||
let mut err = struct_span_err!(
|
||||
tcx.sess,
|
||||
span,
|
||||
E0599,
|
||||
"no {} named `{}` found for {} `{}` in the current scope",
|
||||
item_kind,
|
||||
item_name,
|
||||
actual.prefix_string(self.tcx),
|
||||
ty_str_reported,
|
||||
);
|
||||
if let Mode::MethodCall = mode && let SelfSource::MethodCall(cal) = source {
|
||||
self.suggest_await_before_method(
|
||||
&mut err, item_name, actual, cal, span,
|
||||
);
|
||||
}
|
||||
if let Some(span) =
|
||||
tcx.resolutions(()).confused_type_with_std_module.get(&span)
|
||||
{
|
||||
if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(*span) {
|
||||
err.span_suggestion(
|
||||
*span,
|
||||
"you are looking for the module in `std`, \
|
||||
not the primitive type",
|
||||
format!("std::{}", snippet),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
if let ty::RawPtr(_) = &actual.kind() {
|
||||
err.note(
|
||||
"try using `<*const T>::as_ref()` to get a reference to the \
|
||||
type behind the pointer: https://doc.rust-lang.org/std/\
|
||||
primitive.pointer.html#method.as_ref",
|
||||
);
|
||||
err.note(
|
||||
"using `<*const T>::as_ref()` on a pointer \
|
||||
which is unaligned or points to invalid \
|
||||
or uninitialized memory is undefined behavior",
|
||||
);
|
||||
}
|
||||
err
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let mut err = struct_span_err!(
|
||||
tcx.sess,
|
||||
span,
|
||||
E0599,
|
||||
"no {} named `{}` found for {} `{}` in the current scope",
|
||||
item_kind,
|
||||
item_name,
|
||||
actual.prefix_string(self.tcx),
|
||||
ty_str_reported,
|
||||
);
|
||||
if actual.references_error() {
|
||||
err.downgrade_to_delayed_bug();
|
||||
}
|
||||
|
||||
if let Mode::MethodCall = mode && let SelfSource::MethodCall(cal) = source {
|
||||
self.suggest_await_before_method(
|
||||
&mut err, item_name, actual, cal, span,
|
||||
);
|
||||
}
|
||||
if let Some(span) = tcx.resolutions(()).confused_type_with_std_module.get(&span) {
|
||||
if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(*span) {
|
||||
err.span_suggestion(
|
||||
*span,
|
||||
"you are looking for the module in `std`, \
|
||||
not the primitive type",
|
||||
format!("std::{}", snippet),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
if let ty::RawPtr(_) = &actual.kind() {
|
||||
err.note(
|
||||
"try using `<*const T>::as_ref()` to get a reference to the \
|
||||
type behind the pointer: https://doc.rust-lang.org/std/\
|
||||
primitive.pointer.html#method.as_ref",
|
||||
);
|
||||
err.note(
|
||||
"using `<*const T>::as_ref()` on a pointer \
|
||||
which is unaligned or points to invalid \
|
||||
or uninitialized memory is undefined behavior",
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(def) = actual.ty_adt_def() {
|
||||
if let Some(full_sp) = tcx.hir().span_if_local(def.did()) {
|
||||
let def_sp = tcx.sess.source_map().guess_head_span(full_sp);
|
||||
@ -488,19 +366,32 @@ pub fn report_method_error(
|
||||
}
|
||||
|
||||
if self.is_fn_ty(rcvr_ty, span) {
|
||||
fn report_function<T: std::fmt::Display>(err: &mut Diagnostic, name: T) {
|
||||
err.note(
|
||||
&format!("`{}` is a function, perhaps you wish to call it", name,),
|
||||
);
|
||||
}
|
||||
|
||||
if let SelfSource::MethodCall(expr) = source {
|
||||
if let Ok(expr_string) = tcx.sess.source_map().span_to_snippet(expr.span) {
|
||||
report_function(&mut err, expr_string);
|
||||
} else if let ExprKind::Path(QPath::Resolved(_, path)) = expr.kind {
|
||||
if let Some(segment) = path.segments.last() {
|
||||
report_function(&mut err, segment.ident);
|
||||
let suggest = if let ty::FnDef(def_id, _) = rcvr_ty.kind() {
|
||||
let local_id = def_id.expect_local();
|
||||
let hir_id = tcx.hir().local_def_id_to_hir_id(local_id);
|
||||
let node = tcx.hir().get(hir_id);
|
||||
let fields = node.tuple_fields();
|
||||
|
||||
if let Some(fields) = fields
|
||||
&& let Some(DefKind::Ctor(of, _)) = self.tcx.opt_def_kind(local_id) {
|
||||
Some((fields, of))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// If the function is a tuple constructor, we recommend that they call it
|
||||
if let Some((fields, kind)) = suggest {
|
||||
suggest_call_constructor(expr.span, kind, fields.len(), &mut err);
|
||||
} else {
|
||||
// General case
|
||||
err.span_label(
|
||||
expr.span,
|
||||
"this is a function, perhaps you wish to call it",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -985,7 +876,7 @@ trait bound{s}",
|
||||
}
|
||||
}
|
||||
|
||||
let mut label_span_not_found = || {
|
||||
let label_span_not_found = |err: &mut DiagnosticBuilder<'_, _>| {
|
||||
if unsatisfied_predicates.is_empty() {
|
||||
err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
|
||||
let is_string_or_ref_str = match actual.kind() {
|
||||
@ -1071,62 +962,14 @@ trait bound{s}",
|
||||
// If the method name is the name of a field with a function or closure type,
|
||||
// give a helping note that it has to be called as `(x.f)(...)`.
|
||||
if let SelfSource::MethodCall(expr) = source {
|
||||
let field_receiver =
|
||||
self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind() {
|
||||
ty::Adt(def, substs) if !def.is_enum() => {
|
||||
let variant = &def.non_enum_variant();
|
||||
self.tcx.find_field_index(item_name, variant).map(|index| {
|
||||
let field = &variant.fields[index];
|
||||
let field_ty = field.ty(tcx, substs);
|
||||
(field, field_ty)
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
});
|
||||
|
||||
if let Some((field, field_ty)) = field_receiver {
|
||||
let scope = self.tcx.parent_module(self.body_id).to_def_id();
|
||||
let is_accessible = field.vis.is_accessible_from(scope, self.tcx);
|
||||
|
||||
if is_accessible {
|
||||
if self.is_fn_ty(field_ty, span) {
|
||||
let expr_span = expr.span.to(item_name.span);
|
||||
err.multipart_suggestion(
|
||||
&format!(
|
||||
"to call the function stored in `{}`, \
|
||||
surround the field access with parentheses",
|
||||
item_name,
|
||||
),
|
||||
vec![
|
||||
(expr_span.shrink_to_lo(), '('.to_string()),
|
||||
(expr_span.shrink_to_hi(), ')'.to_string()),
|
||||
],
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else {
|
||||
let call_expr = self
|
||||
.tcx
|
||||
.hir()
|
||||
.expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
|
||||
|
||||
if let Some(span) = call_expr.span.trim_start(item_name.span) {
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"remove the arguments",
|
||||
String::new(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let field_kind = if is_accessible { "field" } else { "private field" };
|
||||
err.span_label(item_name.span, format!("{}, not a method", field_kind));
|
||||
} else if lev_candidate.is_none() && !custom_span_label {
|
||||
label_span_not_found();
|
||||
if !self.suggest_field_call(span, rcvr_ty, expr, item_name, &mut err)
|
||||
&& lev_candidate.is_none()
|
||||
&& !custom_span_label
|
||||
{
|
||||
label_span_not_found(&mut err);
|
||||
}
|
||||
} else if !custom_span_label {
|
||||
label_span_not_found();
|
||||
label_span_not_found(&mut err);
|
||||
}
|
||||
|
||||
if let SelfSource::MethodCall(expr) = source
|
||||
@ -1313,6 +1156,187 @@ trait bound{s}",
|
||||
None
|
||||
}
|
||||
|
||||
fn suggest_field_call(
|
||||
&self,
|
||||
span: Span,
|
||||
rcvr_ty: Ty<'tcx>,
|
||||
expr: &hir::Expr<'_>,
|
||||
item_name: Ident,
|
||||
err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
|
||||
) -> bool {
|
||||
let tcx = self.tcx;
|
||||
let field_receiver = self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind() {
|
||||
ty::Adt(def, substs) if !def.is_enum() => {
|
||||
let variant = &def.non_enum_variant();
|
||||
tcx.find_field_index(item_name, variant).map(|index| {
|
||||
let field = &variant.fields[index];
|
||||
let field_ty = field.ty(tcx, substs);
|
||||
(field, field_ty)
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
});
|
||||
if let Some((field, field_ty)) = field_receiver {
|
||||
let scope = tcx.parent_module(self.body_id).to_def_id();
|
||||
let is_accessible = field.vis.is_accessible_from(scope, tcx);
|
||||
|
||||
if is_accessible {
|
||||
if self.is_fn_ty(field_ty, span) {
|
||||
let expr_span = expr.span.to(item_name.span);
|
||||
err.multipart_suggestion(
|
||||
&format!(
|
||||
"to call the function stored in `{}`, \
|
||||
surround the field access with parentheses",
|
||||
item_name,
|
||||
),
|
||||
vec![
|
||||
(expr_span.shrink_to_lo(), '('.to_string()),
|
||||
(expr_span.shrink_to_hi(), ')'.to_string()),
|
||||
],
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else {
|
||||
let call_expr = tcx.hir().expect_expr(tcx.hir().get_parent_node(expr.hir_id));
|
||||
|
||||
if let Some(span) = call_expr.span.trim_start(item_name.span) {
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"remove the arguments",
|
||||
String::new(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let field_kind = if is_accessible { "field" } else { "private field" };
|
||||
err.span_label(item_name.span, format!("{}, not a method", field_kind));
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn suggest_constraining_numerical_ty(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
actual: Ty<'tcx>,
|
||||
source: SelfSource<'_>,
|
||||
span: Span,
|
||||
item_kind: &str,
|
||||
item_name: Ident,
|
||||
ty_str: &str,
|
||||
) -> bool {
|
||||
let found_candidate = all_traits(self.tcx)
|
||||
.into_iter()
|
||||
.any(|info| self.associated_value(info.def_id, item_name).is_some());
|
||||
let found_assoc = |ty: Ty<'tcx>| {
|
||||
simplify_type(tcx, ty, TreatParams::AsPlaceholders)
|
||||
.and_then(|simp| {
|
||||
tcx.incoherent_impls(simp)
|
||||
.iter()
|
||||
.find_map(|&id| self.associated_value(id, item_name))
|
||||
})
|
||||
.is_some()
|
||||
};
|
||||
let found_candidate = found_candidate
|
||||
|| found_assoc(tcx.types.i8)
|
||||
|| found_assoc(tcx.types.i16)
|
||||
|| found_assoc(tcx.types.i32)
|
||||
|| found_assoc(tcx.types.i64)
|
||||
|| found_assoc(tcx.types.i128)
|
||||
|| found_assoc(tcx.types.u8)
|
||||
|| found_assoc(tcx.types.u16)
|
||||
|| found_assoc(tcx.types.u32)
|
||||
|| found_assoc(tcx.types.u64)
|
||||
|| found_assoc(tcx.types.u128)
|
||||
|| found_assoc(tcx.types.f32)
|
||||
|| found_assoc(tcx.types.f32);
|
||||
if found_candidate
|
||||
&& actual.is_numeric()
|
||||
&& !actual.has_concrete_skeleton()
|
||||
&& let SelfSource::MethodCall(expr) = source
|
||||
{
|
||||
let mut err = struct_span_err!(
|
||||
tcx.sess,
|
||||
span,
|
||||
E0689,
|
||||
"can't call {} `{}` on ambiguous numeric type `{}`",
|
||||
item_kind,
|
||||
item_name,
|
||||
ty_str
|
||||
);
|
||||
let concrete_type = if actual.is_integral() { "i32" } else { "f32" };
|
||||
match expr.kind {
|
||||
ExprKind::Lit(ref lit) => {
|
||||
// numeric literal
|
||||
let snippet = tcx
|
||||
.sess
|
||||
.source_map()
|
||||
.span_to_snippet(lit.span)
|
||||
.unwrap_or_else(|_| "<numeric literal>".to_owned());
|
||||
|
||||
// If this is a floating point literal that ends with '.',
|
||||
// get rid of it to stop this from becoming a member access.
|
||||
let snippet = snippet.strip_suffix('.').unwrap_or(&snippet);
|
||||
|
||||
err.span_suggestion(
|
||||
lit.span,
|
||||
&format!(
|
||||
"you must specify a concrete type for this numeric value, \
|
||||
like `{}`",
|
||||
concrete_type
|
||||
),
|
||||
format!("{snippet}_{concrete_type}"),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
ExprKind::Path(QPath::Resolved(_, path)) => {
|
||||
// local binding
|
||||
if let hir::def::Res::Local(hir_id) = path.res {
|
||||
let span = tcx.hir().span(hir_id);
|
||||
let snippet = tcx.sess.source_map().span_to_snippet(span);
|
||||
let filename = tcx.sess.source_map().span_to_filename(span);
|
||||
|
||||
let parent_node =
|
||||
self.tcx.hir().get(self.tcx.hir().get_parent_node(hir_id));
|
||||
let msg = format!(
|
||||
"you must specify a type for this binding, like `{}`",
|
||||
concrete_type,
|
||||
);
|
||||
|
||||
match (filename, parent_node, snippet) {
|
||||
(
|
||||
FileName::Real(_),
|
||||
Node::Local(hir::Local {
|
||||
source: hir::LocalSource::Normal,
|
||||
ty,
|
||||
..
|
||||
}),
|
||||
Ok(ref snippet),
|
||||
) => {
|
||||
err.span_suggestion(
|
||||
// account for `let x: _ = 42;`
|
||||
// ^^^^
|
||||
span.to(ty.as_ref().map(|ty| ty.span).unwrap_or(span)),
|
||||
&msg,
|
||||
format!("{}: {}", snippet, concrete_type),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
err.span_label(span, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
err.emit();
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
crate fn note_unmet_impls_on_type(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
|
@ -98,12 +98,15 @@
|
||||
pub use diverges::Diverges;
|
||||
pub use expectation::Expectation;
|
||||
pub use fn_ctxt::*;
|
||||
use hir::def::CtorOf;
|
||||
pub use inherited::{Inherited, InheritedBuilder};
|
||||
|
||||
use crate::astconv::AstConv;
|
||||
use crate::check::gather_locals::GatherLocalsVisitor;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan};
|
||||
use rustc_errors::{
|
||||
pluralize, struct_span_err, Applicability, DiagnosticBuilder, EmissionGuarantee, MultiSpan,
|
||||
};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
@ -988,3 +991,36 @@ fn has_expected_num_generic_args<'tcx>(
|
||||
generics.count() == expected + if generics.has_self { 1 } else { 0 }
|
||||
})
|
||||
}
|
||||
|
||||
/// Suggests calling the constructor of a tuple struct or enum variant
|
||||
///
|
||||
/// * `snippet` - The snippet of code that references the constructor
|
||||
/// * `span` - The span of the snippet
|
||||
/// * `params` - The number of parameters the constructor accepts
|
||||
/// * `err` - A mutable diagnostic builder to add the suggestion to
|
||||
fn suggest_call_constructor<G: EmissionGuarantee>(
|
||||
span: Span,
|
||||
kind: CtorOf,
|
||||
params: usize,
|
||||
err: &mut DiagnosticBuilder<'_, G>,
|
||||
) {
|
||||
// Note: tuple-structs don't have named fields, so just use placeholders
|
||||
let args = vec!["_"; params].join(", ");
|
||||
let applicable = if params > 0 {
|
||||
Applicability::HasPlaceholders
|
||||
} else {
|
||||
// When n = 0, it's an empty-tuple struct/enum variant
|
||||
// so we trivially know how to construct it
|
||||
Applicability::MachineApplicable
|
||||
};
|
||||
let kind = match kind {
|
||||
CtorOf::Struct => "a struct",
|
||||
CtorOf::Variant => "an enum variant",
|
||||
};
|
||||
err.span_label(span, &format!("this is the constructor of {kind}"));
|
||||
err.multipart_suggestion(
|
||||
"call the constructor",
|
||||
vec![(span.shrink_to_lo(), "(".to_string()), (span.shrink_to_hi(), format!(")({args})"))],
|
||||
applicable,
|
||||
);
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::DefIdTree;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::symbol::kw;
|
||||
use rustc_span::{sym, Symbol};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
@ -679,7 +680,7 @@ fn resolved_path<'cx>(
|
||||
|
||||
if print_all {
|
||||
for seg in &path.segments[..path.segments.len() - 1] {
|
||||
write!(w, "{}::", seg.name)?;
|
||||
write!(w, "{}::", if seg.name == kw::PathRoot { "" } else { seg.name.as_str() })?;
|
||||
}
|
||||
}
|
||||
if w.alternate() {
|
||||
|
@ -310,10 +310,20 @@ window.initSearch = function(rawSearchIndex) {
|
||||
*/
|
||||
function getIdentEndPosition(parserState) {
|
||||
let end = parserState.pos;
|
||||
let foundExclamation = false;
|
||||
while (parserState.pos < parserState.length) {
|
||||
const c = parserState.userQuery[parserState.pos];
|
||||
if (!isIdentCharacter(c)) {
|
||||
if (isErrorCharacter(c)) {
|
||||
if (c === "!") {
|
||||
if (foundExclamation) {
|
||||
throw new Error("Cannot have more than one `!` in an ident");
|
||||
} else if (parserState.pos + 1 < parserState.length &&
|
||||
isIdentCharacter(parserState.userQuery[parserState.pos + 1]))
|
||||
{
|
||||
throw new Error("`!` can only be at the end of an ident");
|
||||
}
|
||||
foundExclamation = true;
|
||||
} else if (isErrorCharacter(c)) {
|
||||
throw new Error(`Unexpected \`${c}\``);
|
||||
} else if (
|
||||
isStopCharacter(c) ||
|
||||
@ -329,6 +339,7 @@ window.initSearch = function(rawSearchIndex) {
|
||||
}
|
||||
// Skip current ":".
|
||||
parserState.pos += 1;
|
||||
foundExclamation = false;
|
||||
} else {
|
||||
throw new Error(`Unexpected \`${c}\``);
|
||||
}
|
||||
@ -591,7 +602,7 @@ window.initSearch = function(rawSearchIndex) {
|
||||
*
|
||||
* The supported syntax by this parser is as follow:
|
||||
*
|
||||
* ident = *(ALPHA / DIGIT / "_")
|
||||
* ident = *(ALPHA / DIGIT / "_") [!]
|
||||
* path = ident *(DOUBLE-COLON ident)
|
||||
* arg = path [generics]
|
||||
* arg-without-generic = path
|
||||
|
@ -35,6 +35,8 @@ const QUERY = [
|
||||
"a,:",
|
||||
" a<> :",
|
||||
"mod : :",
|
||||
"a!a",
|
||||
"a!!",
|
||||
];
|
||||
|
||||
const PARSED = [
|
||||
@ -362,4 +364,22 @@ const PARSED = [
|
||||
userQuery: "mod : :",
|
||||
error: 'Unexpected `:`',
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: "a!a",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "a!a",
|
||||
error: '`!` can only be at the end of an ident',
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: "a!!",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "a!!",
|
||||
error: 'Cannot have more than one `!` in an ident',
|
||||
},
|
||||
];
|
||||
|
93
src/test/rustdoc-js-std/parser-ident.js
Normal file
93
src/test/rustdoc-js-std/parser-ident.js
Normal file
@ -0,0 +1,93 @@
|
||||
const QUERY = [
|
||||
"R<!>",
|
||||
"!",
|
||||
"a!",
|
||||
"a!::b",
|
||||
"a!::b!",
|
||||
];
|
||||
|
||||
const PARSED = [
|
||||
{
|
||||
elems: [{
|
||||
name: "r",
|
||||
fullPath: ["r"],
|
||||
pathWithoutLast: [],
|
||||
pathLast: "r",
|
||||
generics: [
|
||||
{
|
||||
name: "!",
|
||||
fullPath: ["!"],
|
||||
pathWithoutLast: [],
|
||||
pathLast: "!",
|
||||
generics: [],
|
||||
},
|
||||
],
|
||||
}],
|
||||
foundElems: 1,
|
||||
original: "R<!>",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "r<!>",
|
||||
error: null,
|
||||
},
|
||||
{
|
||||
elems: [{
|
||||
name: "!",
|
||||
fullPath: ["!"],
|
||||
pathWithoutLast: [],
|
||||
pathLast: "!",
|
||||
generics: [],
|
||||
}],
|
||||
foundElems: 1,
|
||||
original: "!",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "!",
|
||||
error: null,
|
||||
},
|
||||
{
|
||||
elems: [{
|
||||
name: "a!",
|
||||
fullPath: ["a!"],
|
||||
pathWithoutLast: [],
|
||||
pathLast: "a!",
|
||||
generics: [],
|
||||
}],
|
||||
foundElems: 1,
|
||||
original: "a!",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "a!",
|
||||
error: null,
|
||||
},
|
||||
{
|
||||
elems: [{
|
||||
name: "a!::b",
|
||||
fullPath: ["a!", "b"],
|
||||
pathWithoutLast: ["a!"],
|
||||
pathLast: "b",
|
||||
generics: [],
|
||||
}],
|
||||
foundElems: 1,
|
||||
original: "a!::b",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "a!::b",
|
||||
error: null,
|
||||
},
|
||||
{
|
||||
elems: [{
|
||||
name: "a!::b!",
|
||||
fullPath: ["a!", "b!"],
|
||||
pathWithoutLast: ["a!"],
|
||||
pathLast: "b!",
|
||||
generics: [],
|
||||
}],
|
||||
foundElems: 1,
|
||||
original: "a!::b!",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "a!::b!",
|
||||
error: null,
|
||||
},
|
||||
];
|
@ -1,4 +1,10 @@
|
||||
const QUERY = ['-> F<P>', '-> P', '->,a', 'aaaaa->a'];
|
||||
const QUERY = [
|
||||
"-> F<P>",
|
||||
"-> P",
|
||||
"->,a",
|
||||
"aaaaa->a",
|
||||
"-> !",
|
||||
];
|
||||
|
||||
const PARSED = [
|
||||
{
|
||||
@ -75,4 +81,19 @@ const PARSED = [
|
||||
userQuery: "aaaaa->a",
|
||||
error: null,
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 1,
|
||||
original: "-> !",
|
||||
returned: [{
|
||||
name: "!",
|
||||
fullPath: ["!"],
|
||||
pathWithoutLast: [],
|
||||
pathLast: "!",
|
||||
generics: [],
|
||||
}],
|
||||
typeFilter: -1,
|
||||
userQuery: "-> !",
|
||||
error: null,
|
||||
},
|
||||
];
|
||||
|
2
src/test/rustdoc/issue-95873.rs
Normal file
2
src/test/rustdoc/issue-95873.rs
Normal file
@ -0,0 +1,2 @@
|
||||
// @has issue_95873/index.html "//*[@class='item-left import-item']" "pub use ::std as x;"
|
||||
pub use ::std as x;
|
16
src/test/rustdoc/issue-96381.rs
Normal file
16
src/test/rustdoc/issue-96381.rs
Normal file
@ -0,0 +1,16 @@
|
||||
// should-fail
|
||||
|
||||
#![allow(unused)]
|
||||
|
||||
trait Foo<T>: Sized {
|
||||
fn bar(i: i32, t: T, s: &Self) -> (T, i32);
|
||||
}
|
||||
|
||||
impl Foo<usize> for () {
|
||||
fn bar(i: _, t: _, s: _) -> _ {
|
||||
//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
|
||||
(1, 2)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -3,14 +3,14 @@ fn main() {
|
||||
let arc = std::sync::Arc::new(oops);
|
||||
//~^ ERROR cannot find value `oops` in this scope
|
||||
//~| NOTE not found
|
||||
// The error "note: `arc` is a function, perhaps you wish to call it" MUST NOT appear.
|
||||
// The error "note: this is a function, perhaps you wish to call it" MUST NOT appear.
|
||||
arc.blablabla();
|
||||
//~^ ERROR no method named `blablabla`
|
||||
//~| NOTE method not found
|
||||
let arc2 = std::sync::Arc::new(|| 1);
|
||||
// The error "note: `arc2` is a function, perhaps you wish to call it" SHOULD appear
|
||||
// The error "note: this is a function, perhaps you wish to call it" SHOULD appear
|
||||
arc2.blablabla();
|
||||
//~^ ERROR no method named `blablabla`
|
||||
//~| NOTE method not found
|
||||
//~| NOTE `arc2` is a function, perhaps you wish to call it
|
||||
//~| NOTE this is a function, perhaps you wish to call it
|
||||
}
|
||||
|
@ -14,9 +14,9 @@ error[E0599]: no method named `blablabla` found for struct `Arc<[closure@$DIR/fn
|
||||
--> $DIR/fn-help-with-err.rs:12:10
|
||||
|
|
||||
LL | arc2.blablabla();
|
||||
| ^^^^^^^^^ method not found in `Arc<[closure@$DIR/fn-help-with-err.rs:10:36: 10:40]>`
|
||||
|
|
||||
= note: `arc2` is a function, perhaps you wish to call it
|
||||
| ---- ^^^^^^^^^ method not found in `Arc<[closure@$DIR/fn-help-with-err.rs:10:36: 10:40]>`
|
||||
| |
|
||||
| this is a function, perhaps you wish to call it
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
@ -24,10 +24,14 @@ LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send
|
||||
LL | x
|
||||
| ^ returning this value requires that `'b` must outlive `'static`
|
||||
|
|
||||
help: to allow this `impl Trait` to capture borrowed data with lifetime `'b`, add `'b` as a bound
|
||||
help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'b` lifetime bound
|
||||
|
|
||||
LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> + 'b {
|
||||
| ++++
|
||||
help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'b` lifetime bound
|
||||
|
|
||||
LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a + 'b> {
|
||||
| ++++
|
||||
|
||||
error: implementation of `Hrtb` is not general enough
|
||||
--> $DIR/issue-88236-2.rs:20:5
|
||||
|
@ -32,7 +32,14 @@ LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
|
||||
| |
|
||||
| let's call the lifetime of this reference `'1`
|
||||
|
|
||||
= help: consider replacing `'1` with `'static`
|
||||
help: consider changing the `impl Trait`'s explicit `'static` bound to the lifetime of argument `x`
|
||||
|
|
||||
LL | fn elided2(x: &i32) -> impl Copy + '_ { x }
|
||||
| ~~
|
||||
help: alternatively, add an explicit `'static` bound to this reference
|
||||
|
|
||||
LL | fn elided2(x: &'static i32) -> impl Copy + 'static { x }
|
||||
| ~~~~~~~~~~~~
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/must_outlive_least_region_or_bound.rs:11:55
|
||||
@ -40,7 +47,14 @@ error: lifetime may not live long enough
|
||||
LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
|
||||
| -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static`
|
||||
|
|
||||
= help: consider replacing `'a` with `'static`
|
||||
help: consider changing the `impl Trait`'s explicit `'static` bound to the lifetime of argument `x`
|
||||
|
|
||||
LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'a { x }
|
||||
| ~~
|
||||
help: alternatively, add an explicit `'static` bound to this reference
|
||||
|
|
||||
LL | fn explicit2<'a>(x: &'static i32) -> impl Copy + 'static { x }
|
||||
| ~~~~~~~~~~~~
|
||||
|
||||
error[E0621]: explicit lifetime required in the type of `x`
|
||||
--> $DIR/must_outlive_least_region_or_bound.rs:13:41
|
||||
@ -57,6 +71,15 @@ LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
|
||||
| - ^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static`
|
||||
| |
|
||||
| let's call the lifetime of this reference `'1`
|
||||
|
|
||||
help: to declare that the trait object captures data from argument `x`, you can add an explicit `'_` lifetime bound
|
||||
|
|
||||
LL | fn elided5(x: &i32) -> (Box<dyn Debug + '_>, impl Debug) { (Box::new(x), x) }
|
||||
| ++++
|
||||
help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'_` lifetime bound
|
||||
|
|
||||
LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug + '_) { (Box::new(x), x) }
|
||||
| ++++
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/must_outlive_least_region_or_bound.rs:29:69
|
||||
@ -64,7 +87,14 @@ error: lifetime may not live long enough
|
||||
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
|
||||
| -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static`
|
||||
|
|
||||
= help: consider replacing `'a` with `'static`
|
||||
help: consider changing the `impl Trait`'s explicit `'static` bound to the lifetime of argument `x`
|
||||
|
|
||||
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'a { x }
|
||||
| ~~
|
||||
help: alternatively, add an explicit `'static` bound to this reference
|
||||
|
|
||||
LL | fn with_bound<'a>(x: &'static i32) -> impl LifetimeTrait<'a> + 'static { x }
|
||||
| ~~~~~~~~~~~~
|
||||
|
||||
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
|
||||
--> $DIR/must_outlive_least_region_or_bound.rs:34:5
|
||||
|
@ -5,6 +5,11 @@ LL | fn foo<T: Any>(value: &T) -> Box<dyn Any> {
|
||||
| - let's call the lifetime of this reference `'1`
|
||||
LL | Box::new(value) as Box<dyn Any>
|
||||
| ^^^^^^^^^^^^^^^ cast requires that `'1` must outlive `'static`
|
||||
|
|
||||
help: to declare that the trait object captures data from argument `value`, you can add an explicit `'_` lifetime bound
|
||||
|
|
||||
LL | fn foo<T: Any>(value: &T) -> Box<dyn Any + '_> {
|
||||
| ++++
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -2,17 +2,17 @@ error[E0599]: no method named `x` found for fn item `fn() -> Ret {Obj::func}` in
|
||||
--> $DIR/issue-29124.rs:15:15
|
||||
|
|
||||
LL | Obj::func.x();
|
||||
| ^ method not found in `fn() -> Ret {Obj::func}`
|
||||
|
|
||||
= note: `Obj::func` is a function, perhaps you wish to call it
|
||||
| --------- ^ method not found in `fn() -> Ret {Obj::func}`
|
||||
| |
|
||||
| this is a function, perhaps you wish to call it
|
||||
|
||||
error[E0599]: no method named `x` found for fn item `fn() -> Ret {func}` in the current scope
|
||||
--> $DIR/issue-29124.rs:17:10
|
||||
|
|
||||
LL | func.x();
|
||||
| ^ method not found in `fn() -> Ret {func}`
|
||||
|
|
||||
= note: `func` is a function, perhaps you wish to call it
|
||||
| ---- ^ method not found in `fn() -> Ret {func}`
|
||||
| |
|
||||
| this is a function, perhaps you wish to call it
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -2,9 +2,10 @@ error[E0599]: no method named `f` found for fn pointer `fn(&u8)` in the current
|
||||
--> $DIR/issue-57362-1.rs:20:7
|
||||
|
|
||||
LL | a.f();
|
||||
| ^ method not found in `fn(&u8)`
|
||||
| - ^ method not found in `fn(&u8)`
|
||||
| |
|
||||
| this is a function, perhaps you wish to call it
|
||||
|
|
||||
= note: `a` is a function, perhaps you wish to call it
|
||||
= help: items from traits can only be used if the trait is implemented and in scope
|
||||
note: `Trait` defines an item `f`, perhaps you need to implement it
|
||||
--> $DIR/issue-57362-1.rs:8:1
|
||||
|
@ -5,6 +5,11 @@ LL | fn bar<'a>(x: &'a u32) -> &'static dyn Debug {
|
||||
| -- lifetime `'a` defined here
|
||||
LL | x
|
||||
| ^ returning this value requires that `'a` must outlive `'static`
|
||||
|
|
||||
help: to declare that the trait object captures data from argument `x`, you can add an explicit `'a` lifetime bound
|
||||
|
|
||||
LL | fn bar<'a>(x: &'a u32) -> &'static dyn Debug + 'a {
|
||||
| ++++
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -6,6 +6,11 @@ LL | fn load(ss: &mut SomeStruct) -> Box<dyn SomeTrait> {
|
||||
...
|
||||
LL | ss.r
|
||||
| ^^^^ returning this value requires that `'1` must outlive `'static`
|
||||
|
|
||||
help: to declare that the trait object captures data from argument `ss`, you can add an explicit `'_` lifetime bound
|
||||
|
|
||||
LL | fn load(ss: &mut SomeStruct) -> Box<dyn SomeTrait + '_> {
|
||||
| ++++
|
||||
|
||||
error[E0507]: cannot move out of `ss.r` which is behind a mutable reference
|
||||
--> $DIR/object-lifetime-default-from-box-error.rs:18:5
|
||||
|
@ -5,6 +5,15 @@ LL | fn a(v: &[u8]) -> Box<dyn Foo + 'static> {
|
||||
| - let's call the lifetime of this reference `'1`
|
||||
LL | let x: Box<dyn Foo + 'static> = Box::new(v);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'1` must outlive `'static`
|
||||
|
|
||||
help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
|
||||
|
|
||||
LL | fn a(v: &[u8]) -> Box<dyn Foo + '_> {
|
||||
| ~~
|
||||
help: alternatively, add an explicit `'static` bound to this reference
|
||||
|
|
||||
LL | fn a(v: &'static [u8]) -> Box<dyn Foo + 'static> {
|
||||
| ~~~~~~~~~~~~~
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/region-object-lifetime-in-coercion.rs:19:5
|
||||
@ -13,6 +22,15 @@ LL | fn b(v: &[u8]) -> Box<dyn Foo + 'static> {
|
||||
| - let's call the lifetime of this reference `'1`
|
||||
LL | Box::new(v)
|
||||
| ^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static`
|
||||
|
|
||||
help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
|
||||
|
|
||||
LL | fn b(v: &[u8]) -> Box<dyn Foo + '_> {
|
||||
| ~~
|
||||
help: alternatively, add an explicit `'static` bound to this reference
|
||||
|
|
||||
LL | fn b(v: &'static [u8]) -> Box<dyn Foo + 'static> {
|
||||
| ~~~~~~~~~~~~~
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/region-object-lifetime-in-coercion.rs:27:5
|
||||
@ -22,6 +40,11 @@ LL | fn c(v: &[u8]) -> Box<dyn Foo> {
|
||||
...
|
||||
LL | Box::new(v)
|
||||
| ^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static`
|
||||
|
|
||||
help: to declare that the trait object captures data from argument `v`, you can add an explicit `'_` lifetime bound
|
||||
|
|
||||
LL | fn c(v: &[u8]) -> Box<dyn Foo + '_> {
|
||||
| ++++
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/region-object-lifetime-in-coercion.rs:33:5
|
||||
|
@ -5,6 +5,15 @@ LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> {
|
||||
| -- lifetime `'a` defined here
|
||||
LL | Box::new(B(&*v)) as Box<dyn X>
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
|
||||
|
|
||||
help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
|
||||
|
|
||||
LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'a> {
|
||||
| ~~
|
||||
help: alternatively, add an explicit `'static` bound to this reference
|
||||
|
|
||||
LL | fn g<'a, T: 'static>(v: Box<(dyn A<T> + 'static)>) -> Box<dyn X + 'static> {
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error[E0515]: cannot return value referencing local data `*v`
|
||||
--> $DIR/regions-close-object-into-object-2.rs:13:5
|
||||
|
@ -29,6 +29,15 @@ LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
|
||||
| -- lifetime `'a` defined here
|
||||
LL | Box::new(B(&*v)) as Box<dyn X>
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
|
||||
|
|
||||
help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
|
||||
|
|
||||
LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'a> {
|
||||
| ~~
|
||||
help: alternatively, add an explicit `'static` bound to this reference
|
||||
|
|
||||
LL | fn i<'a, T, U>(v: Box<(dyn A<U> + 'static)>) -> Box<dyn X + 'static> {
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error[E0515]: cannot return value referencing local data `*v`
|
||||
--> $DIR/regions-close-object-into-object-4.rs:13:5
|
||||
|
@ -6,6 +6,15 @@ LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + 'static> {
|
||||
LL | // This is illegal, because the region bound on `proc` is 'static.
|
||||
LL | Box::new(move || { *x })
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static`
|
||||
|
|
||||
help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x`
|
||||
|
|
||||
LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + '_> {
|
||||
| ~~
|
||||
help: alternatively, add an explicit `'static` bound to this reference
|
||||
|
|
||||
LL | fn static_proc(x: &'static isize) -> Box<dyn FnMut() -> (isize) + 'static> {
|
||||
| ~~~~~~~~~~~~~~
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -9,10 +9,14 @@ LL | | remaining: self.0.iter(),
|
||||
LL | | }
|
||||
| |_________^ returning this value requires that `'1` must outlive `'static`
|
||||
|
|
||||
help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a bound
|
||||
help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'_` lifetime bound
|
||||
|
|
||||
LL | fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ {
|
||||
| ++++
|
||||
help: to declare that the trait object captures data from argument `self`, you can add an explicit `'_` lifetime bound
|
||||
|
|
||||
LL | fn iter(&self) -> impl Iterator<Item = Box<dyn Foo + '_>> {
|
||||
| ++++
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/trait-object-nested-in-impl-trait.rs:39:9
|
||||
@ -24,6 +28,11 @@ LL | | current: None,
|
||||
LL | | remaining: self.0.iter(),
|
||||
LL | | }
|
||||
| |_________^ returning this value requires that `'1` must outlive `'static`
|
||||
|
|
||||
help: to declare that the trait object captures data from argument `self`, you can add an explicit `'_` lifetime bound
|
||||
|
|
||||
LL | fn iter(&self) -> impl Iterator<Item = Box<dyn Foo + '_>> + '_ {
|
||||
| ++++
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/trait-object-nested-in-impl-trait.rs:50:9
|
||||
@ -35,6 +44,11 @@ LL | | current: None,
|
||||
LL | | remaining: self.0.iter(),
|
||||
LL | | }
|
||||
| |_________^ returning this value requires that `'a` must outlive `'static`
|
||||
|
|
||||
help: to declare that the trait object captures data from argument `self`, you can add an explicit `'a` lifetime bound
|
||||
|
|
||||
LL | fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo + 'a>> + 'a {
|
||||
| ++++
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/trait-object-nested-in-impl-trait.rs:61:9
|
||||
@ -47,10 +61,14 @@ LL | | remaining: self.0.iter(),
|
||||
LL | | }
|
||||
| |_________^ returning this value requires that `'a` must outlive `'static`
|
||||
|
|
||||
help: to allow this `impl Trait` to capture borrowed data with lifetime `'a`, add `'a` as a bound
|
||||
help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'a` lifetime bound
|
||||
|
|
||||
LL | fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a {
|
||||
| ++++
|
||||
help: to declare that the trait object captures data from argument `self`, you can add an explicit `'a` lifetime bound
|
||||
|
|
||||
LL | fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo + 'a>> {
|
||||
| ++++
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
14
src/test/ui/typeck/issue-87181/empty-tuple-method.rs
Normal file
14
src/test/ui/typeck/issue-87181/empty-tuple-method.rs
Normal file
@ -0,0 +1,14 @@
|
||||
struct Bar<T> {
|
||||
bar: T
|
||||
}
|
||||
|
||||
struct Foo();
|
||||
impl Foo {
|
||||
fn foo() { }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let thing = Bar { bar: Foo };
|
||||
thing.bar.foo();
|
||||
//~^ ERROR no method named `foo` found for fn item `fn() -> Foo {Foo}` in the current scope [E0599]
|
||||
}
|
16
src/test/ui/typeck/issue-87181/empty-tuple-method.stderr
Normal file
16
src/test/ui/typeck/issue-87181/empty-tuple-method.stderr
Normal file
@ -0,0 +1,16 @@
|
||||
error[E0599]: no method named `foo` found for fn item `fn() -> Foo {Foo}` in the current scope
|
||||
--> $DIR/empty-tuple-method.rs:12:15
|
||||
|
|
||||
LL | thing.bar.foo();
|
||||
| --------- ^^^ method not found in `fn() -> Foo {Foo}`
|
||||
| |
|
||||
| this is the constructor of a struct
|
||||
|
|
||||
help: call the constructor
|
||||
|
|
||||
LL | (thing.bar)().foo();
|
||||
| + +++
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0599`.
|
16
src/test/ui/typeck/issue-87181/enum-variant.rs
Normal file
16
src/test/ui/typeck/issue-87181/enum-variant.rs
Normal file
@ -0,0 +1,16 @@
|
||||
struct Bar<T> {
|
||||
bar: T
|
||||
}
|
||||
|
||||
enum Foo{
|
||||
Tup()
|
||||
}
|
||||
impl Foo {
|
||||
fn foo() { }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let thing = Bar { bar: Foo::Tup };
|
||||
thing.bar.foo();
|
||||
//~^ ERROR no method named `foo` found for fn item `fn() -> Foo {Foo::Tup}` in the current scope [E0599]
|
||||
}
|
16
src/test/ui/typeck/issue-87181/enum-variant.stderr
Normal file
16
src/test/ui/typeck/issue-87181/enum-variant.stderr
Normal file
@ -0,0 +1,16 @@
|
||||
error[E0599]: no method named `foo` found for fn item `fn() -> Foo {Foo::Tup}` in the current scope
|
||||
--> $DIR/enum-variant.rs:14:15
|
||||
|
|
||||
LL | thing.bar.foo();
|
||||
| --------- ^^^ method not found in `fn() -> Foo {Foo::Tup}`
|
||||
| |
|
||||
| this is the constructor of an enum variant
|
||||
|
|
||||
help: call the constructor
|
||||
|
|
||||
LL | (thing.bar)().foo();
|
||||
| + +++
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0599`.
|
14
src/test/ui/typeck/issue-87181/tuple-field.rs
Normal file
14
src/test/ui/typeck/issue-87181/tuple-field.rs
Normal file
@ -0,0 +1,14 @@
|
||||
struct Bar<T> {
|
||||
bar: T
|
||||
}
|
||||
|
||||
struct Foo(char, u16);
|
||||
impl Foo {
|
||||
fn foo() { }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let thing = Bar { bar: Foo };
|
||||
thing.bar.0;
|
||||
//~^ ERROR no field `0` on type `fn(char, u16) -> Foo {Foo}` [E0609]
|
||||
}
|
16
src/test/ui/typeck/issue-87181/tuple-field.stderr
Normal file
16
src/test/ui/typeck/issue-87181/tuple-field.stderr
Normal file
@ -0,0 +1,16 @@
|
||||
error[E0609]: no field `0` on type `fn(char, u16) -> Foo {Foo}`
|
||||
--> $DIR/tuple-field.rs:12:15
|
||||
|
|
||||
LL | thing.bar.0;
|
||||
| --------- ^
|
||||
| |
|
||||
| this is the constructor of a struct
|
||||
|
|
||||
help: call the constructor
|
||||
|
|
||||
LL | (thing.bar)(_, _).0;
|
||||
| + +++++++
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0609`.
|
14
src/test/ui/typeck/issue-87181/tuple-method.rs
Normal file
14
src/test/ui/typeck/issue-87181/tuple-method.rs
Normal file
@ -0,0 +1,14 @@
|
||||
struct Bar<T> {
|
||||
bar: T
|
||||
}
|
||||
|
||||
struct Foo(u8, i32);
|
||||
impl Foo {
|
||||
fn foo() { }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let thing = Bar { bar: Foo };
|
||||
thing.bar.foo();
|
||||
//~^ ERROR no method named `foo` found for fn item `fn(u8, i32) -> Foo {Foo}` in the current scope [E0599]
|
||||
}
|
16
src/test/ui/typeck/issue-87181/tuple-method.stderr
Normal file
16
src/test/ui/typeck/issue-87181/tuple-method.stderr
Normal file
@ -0,0 +1,16 @@
|
||||
error[E0599]: no method named `foo` found for fn item `fn(u8, i32) -> Foo {Foo}` in the current scope
|
||||
--> $DIR/tuple-method.rs:12:15
|
||||
|
|
||||
LL | thing.bar.foo();
|
||||
| --------- ^^^ method not found in `fn(u8, i32) -> Foo {Foo}`
|
||||
| |
|
||||
| this is the constructor of a struct
|
||||
|
|
||||
help: call the constructor
|
||||
|
|
||||
LL | (thing.bar)(_, _).foo();
|
||||
| + +++++++
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0599`.
|
@ -2,9 +2,9 @@ error[E0599]: no method named `call` found for closure `[closure@$DIR/unboxed-cl
|
||||
--> $DIR/unboxed-closures-static-call-wrong-trait.rs:7:10
|
||||
|
|
||||
LL | mut_.call((0, ));
|
||||
| ^^^^ method not found in `[closure@$DIR/unboxed-closures-static-call-wrong-trait.rs:6:26: 6:31]`
|
||||
|
|
||||
= note: `mut_` is a function, perhaps you wish to call it
|
||||
| ---- ^^^^ method not found in `[closure@$DIR/unboxed-closures-static-call-wrong-trait.rs:6:26: 6:31]`
|
||||
| |
|
||||
| this is a function, perhaps you wish to call it
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -6,6 +6,11 @@ LL | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> {
|
||||
LL | // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static`
|
||||
LL | Box::new(items.iter())
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static`
|
||||
|
|
||||
help: to declare that the trait object captures data from argument `items`, you can add an explicit `'_` lifetime bound
|
||||
|
|
||||
LL | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T> + '_> {
|
||||
| ++++
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user