Account for arbitrary self types in E0599
This commit is contained in:
parent
fba38ac27e
commit
a9ce33c059
11 changed files with 144 additions and 26 deletions
|
@ -2402,6 +2402,24 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
self.mk_generic_adt(def_id, ty)
|
self.mk_generic_adt(def_id, ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn mk_pin(self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||||
|
let def_id = self.require_lang_item(lang_items::PinTypeLangItem, None);
|
||||||
|
self.mk_generic_adt(def_id, ty)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn mk_rc(self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||||
|
let def_id = self.require_lang_item(lang_items::Rc, None);
|
||||||
|
self.mk_generic_adt(def_id, ty)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn mk_arc(self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||||
|
let def_id = self.require_lang_item(lang_items::Arc, None);
|
||||||
|
self.mk_generic_adt(def_id, ty)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn mk_maybe_uninit(self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
pub fn mk_maybe_uninit(self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||||
let def_id = self.require_lang_item(lang_items::MaybeUninitLangItem, None);
|
let def_id = self.require_lang_item(lang_items::MaybeUninitLangItem, None);
|
||||||
|
|
|
@ -12,7 +12,7 @@ use crate::check::fatally_break_rust;
|
||||||
use crate::check::report_unexpected_variant_res;
|
use crate::check::report_unexpected_variant_res;
|
||||||
use crate::check::Needs;
|
use crate::check::Needs;
|
||||||
use crate::check::TupleArgumentsFlag::DontTupleArguments;
|
use crate::check::TupleArgumentsFlag::DontTupleArguments;
|
||||||
use crate::check::method::SelfSource;
|
use crate::check::method::{probe, SelfSource};
|
||||||
use crate::util::common::ErrorReported;
|
use crate::util::common::ErrorReported;
|
||||||
use crate::util::nodemap::FxHashMap;
|
use crate::util::nodemap::FxHashMap;
|
||||||
use crate::astconv::AstConv as _;
|
use crate::astconv::AstConv as _;
|
||||||
|
@ -775,35 +775,65 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
// no need to check for bot/err -- callee does that
|
// no need to check for bot/err -- callee does that
|
||||||
let rcvr_t = self.structurally_resolved_type(args[0].span, rcvr_t);
|
let rcvr_t = self.structurally_resolved_type(args[0].span, rcvr_t);
|
||||||
|
|
||||||
let method = match self.lookup_method(rcvr_t,
|
let try_alt_rcvr = |err: &mut DiagnosticBuilder<'_>, new_rcvr_t| {
|
||||||
segment,
|
if let Ok(pick) = self.lookup_probe(
|
||||||
span,
|
span,
|
||||||
expr,
|
segment.ident,
|
||||||
rcvr) {
|
new_rcvr_t,
|
||||||
|
rcvr,
|
||||||
|
probe::ProbeScope::AllTraits,
|
||||||
|
) {
|
||||||
|
err.span_label(
|
||||||
|
pick.item.ident.span,
|
||||||
|
&format!("the method is available for `{}` here", new_rcvr_t),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr) {
|
||||||
Ok(method) => {
|
Ok(method) => {
|
||||||
self.write_method_call(expr.hir_id, method);
|
self.write_method_call(expr.hir_id, method);
|
||||||
Ok(method)
|
Ok(method)
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
if segment.ident.name != kw::Invalid {
|
if segment.ident.name != kw::Invalid {
|
||||||
self.report_method_error(span,
|
if let Some(mut err) = self.report_method_error(
|
||||||
rcvr_t,
|
span,
|
||||||
segment.ident,
|
rcvr_t,
|
||||||
SelfSource::MethodCall(rcvr),
|
segment.ident,
|
||||||
error,
|
SelfSource::MethodCall(rcvr),
|
||||||
Some(args));
|
error,
|
||||||
|
Some(args),
|
||||||
|
) {
|
||||||
|
if let ty::Adt(..) = rcvr_t.sty {
|
||||||
|
// Try alternative arbitrary self types that could fulfill this call.
|
||||||
|
// FIXME: probe for all types that *could* be arbitrary self-types, not
|
||||||
|
// just this whitelist.
|
||||||
|
let box_rcvr_t = self.tcx.mk_box(rcvr_t);
|
||||||
|
try_alt_rcvr(&mut err, box_rcvr_t);
|
||||||
|
let pin_rcvr_t = self.tcx.mk_pin(rcvr_t);
|
||||||
|
try_alt_rcvr(&mut err, pin_rcvr_t);
|
||||||
|
let arc_rcvr_t = self.tcx.mk_arc(rcvr_t);
|
||||||
|
try_alt_rcvr(&mut err, arc_rcvr_t);
|
||||||
|
let rc_rcvr_t = self.tcx.mk_rc(rcvr_t);
|
||||||
|
try_alt_rcvr(&mut err, rc_rcvr_t);
|
||||||
|
}
|
||||||
|
err.emit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Call the generic checker.
|
// Call the generic checker.
|
||||||
self.check_method_argument_types(span,
|
self.check_method_argument_types(
|
||||||
expr.span,
|
span,
|
||||||
method,
|
expr.span,
|
||||||
&args[1..],
|
method,
|
||||||
DontTupleArguments,
|
&args[1..],
|
||||||
expected)
|
DontTupleArguments,
|
||||||
|
expected,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_expr_cast(
|
fn check_expr_cast(
|
||||||
|
@ -1466,8 +1496,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
let struct_variant_def = def.non_enum_variant();
|
let struct_variant_def = def.non_enum_variant();
|
||||||
let field_names = self.available_field_names(struct_variant_def);
|
let field_names = self.available_field_names(struct_variant_def);
|
||||||
if !field_names.is_empty() {
|
if !field_names.is_empty() {
|
||||||
err.note(&format!("available fields are: {}",
|
err.note(&format!(
|
||||||
self.name_series_display(field_names)));
|
"available fields are: {}",
|
||||||
|
self.name_series_display(field_names),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -245,7 +245,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
Ok(result.callee)
|
Ok(result.callee)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lookup_probe(
|
pub fn lookup_probe(
|
||||||
&self,
|
&self,
|
||||||
span: Span,
|
span: Span,
|
||||||
method_name: ast::Ident,
|
method_name: ast::Ident,
|
||||||
|
|
|
@ -69,12 +69,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
source: SelfSource<'b>,
|
source: SelfSource<'b>,
|
||||||
error: MethodError<'tcx>,
|
error: MethodError<'tcx>,
|
||||||
args: Option<&'tcx [hir::Expr]>,
|
args: Option<&'tcx [hir::Expr]>,
|
||||||
) {
|
) -> Option<DiagnosticBuilder<'_>> {
|
||||||
let orig_span = span;
|
let orig_span = span;
|
||||||
let mut span = span;
|
let mut span = span;
|
||||||
// Avoid suggestions when we don't know what's going on.
|
// Avoid suggestions when we don't know what's going on.
|
||||||
if rcvr_ty.references_error() {
|
if rcvr_ty.references_error() {
|
||||||
return;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let print_disambiguation_help = |
|
let print_disambiguation_help = |
|
||||||
|
@ -314,7 +314,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
err.emit();
|
err.emit();
|
||||||
return;
|
return None;
|
||||||
} else {
|
} else {
|
||||||
span = item_name.span;
|
span = item_name.span;
|
||||||
let mut err = struct_span_err!(
|
let mut err = struct_span_err!(
|
||||||
|
@ -529,7 +529,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
err.emit();
|
return Some(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
MethodError::Ambiguity(sources) => {
|
MethodError::Ambiguity(sources) => {
|
||||||
|
@ -573,6 +573,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
bug!("no return type expectations but got BadReturnType")
|
bug!("no return type expectations but got BadReturnType")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn suggest_use_candidates(&self,
|
fn suggest_use_candidates(&self,
|
||||||
|
|
|
@ -3580,7 +3580,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
SelfSource::QPath(qself),
|
SelfSource::QPath(qself),
|
||||||
error,
|
error,
|
||||||
None,
|
None,
|
||||||
);
|
).map(|mut e| e.emit());
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
});
|
});
|
||||||
|
|
|
@ -49,6 +49,14 @@ LL | use foo::Bar;
|
||||||
error[E0599]: no method named `method` found for type `std::rc::Rc<&mut std::boxed::Box<&char>>` in the current scope
|
error[E0599]: no method named `method` found for type `std::rc::Rc<&mut std::boxed::Box<&char>>` in the current scope
|
||||||
--> $DIR/no-method-suggested-traits.rs:32:43
|
--> $DIR/no-method-suggested-traits.rs:32:43
|
||||||
|
|
|
|
||||||
|
LL | fn method(&self) {}
|
||||||
|
| ------
|
||||||
|
| |
|
||||||
|
| the method is available for `std::boxed::Box<std::rc::Rc<&mut std::boxed::Box<&char>>>` here
|
||||||
|
| the method is available for `std::pin::Pin<std::rc::Rc<&mut std::boxed::Box<&char>>>` here
|
||||||
|
| the method is available for `std::sync::Arc<std::rc::Rc<&mut std::boxed::Box<&char>>>` here
|
||||||
|
| the method is available for `std::rc::Rc<std::rc::Rc<&mut std::boxed::Box<&char>>>` here
|
||||||
|
...
|
||||||
LL | std::rc::Rc::new(&mut Box::new(&'a')).method();
|
LL | std::rc::Rc::new(&mut Box::new(&'a')).method();
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
|
|
||||||
|
|
9
src/test/ui/self/point-at-arbitrary-self-type-method.rs
Normal file
9
src/test/ui/self/point-at-arbitrary-self-type-method.rs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
struct A;
|
||||||
|
|
||||||
|
impl A {
|
||||||
|
fn foo(self: Box<Self>) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
A.foo(); //~ ERROR E0599
|
||||||
|
}
|
15
src/test/ui/self/point-at-arbitrary-self-type-method.stderr
Normal file
15
src/test/ui/self/point-at-arbitrary-self-type-method.stderr
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
error[E0599]: no method named `foo` found for type `A` in the current scope
|
||||||
|
--> $DIR/point-at-arbitrary-self-type-method.rs:8:7
|
||||||
|
|
|
||||||
|
LL | struct A;
|
||||||
|
| --------- method `foo` not found for this
|
||||||
|
...
|
||||||
|
LL | fn foo(self: Box<Self>) {}
|
||||||
|
| --- the method is available for `std::boxed::Box<A>` here
|
||||||
|
...
|
||||||
|
LL | A.foo();
|
||||||
|
| ^^^
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0599`.
|
|
@ -0,0 +1,10 @@
|
||||||
|
trait B { fn foo(self: Box<Self>); }
|
||||||
|
struct A;
|
||||||
|
|
||||||
|
impl B for A {
|
||||||
|
fn foo(self: Box<Self>) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
A.foo() //~ ERROR E0599
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
error[E0599]: no method named `foo` found for type `A` in the current scope
|
||||||
|
--> $DIR/point-at-arbitrary-self-type-trait-method.rs:9:7
|
||||||
|
|
|
||||||
|
LL | trait B { fn foo(self: Box<Self>); }
|
||||||
|
| --- the method is available for `std::boxed::Box<A>` here
|
||||||
|
LL | struct A;
|
||||||
|
| --------- method `foo` not found for this
|
||||||
|
...
|
||||||
|
LL | A.foo()
|
||||||
|
| ^^^
|
||||||
|
|
|
||||||
|
= help: items from traits can only be used if the trait is implemented and in scope
|
||||||
|
= note: the following trait defines an item `foo`, perhaps you need to implement it:
|
||||||
|
candidate #1: `B`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0599`.
|
|
@ -17,6 +17,13 @@ error[E0599]: no method named `b` found for type `S` in the current scope
|
||||||
LL | struct S;
|
LL | struct S;
|
||||||
| --------- method `b` not found for this
|
| --------- method `b` not found for this
|
||||||
...
|
...
|
||||||
|
LL | fn b(&self) { }
|
||||||
|
| -
|
||||||
|
| |
|
||||||
|
| the method is available for `std::boxed::Box<S>` here
|
||||||
|
| the method is available for `std::sync::Arc<S>` here
|
||||||
|
| the method is available for `std::rc::Rc<S>` here
|
||||||
|
...
|
||||||
LL | S.b();
|
LL | S.b();
|
||||||
| ^
|
| ^
|
||||||
|
|
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue