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:
bors 2022-04-27 01:01:58 +00:00
commit 99b70ee230
39 changed files with 906 additions and 432 deletions

View File

@ -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())),
);
}
}
}

View File

@ -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.

View File

@ -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 {

View File

@ -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

View File

@ -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(

View File

@ -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);
}
_ => {}
}

View File

@ -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,

View File

@ -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,
);
}

View File

@ -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() {

View File

@ -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

View File

@ -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',
},
];

View 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,
},
];

View File

@ -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,
},
];

View 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;

View 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() {}

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View 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]
}

View 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`.

View 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]
}

View 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`.

View 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]
}

View 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`.

View 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]
}

View 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`.

View File

@ -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

View File

@ -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