Skip to content

Commit ececd71

Browse files
authored
Rollup merge of rust-lang#64056 - estebank:arbitrary-self-types, r=Centril
Account for arbitrary self types in E0599 Fix rust-lang#62373
2 parents 1143c8a + 141f5a7 commit ececd71

11 files changed

+148
-26
lines changed

src/librustc/ty/context.rs

+6
Original file line numberDiff line numberDiff line change
@@ -2402,6 +2402,12 @@ impl<'tcx> TyCtxt<'tcx> {
24022402
self.mk_generic_adt(def_id, ty)
24032403
}
24042404

2405+
#[inline]
2406+
pub fn mk_lang_item(self, ty: Ty<'tcx>, item: lang_items::LangItem) -> Ty<'tcx> {
2407+
let def_id = self.require_lang_item(item, None);
2408+
self.mk_generic_adt(def_id, ty)
2409+
}
2410+
24052411
#[inline]
24062412
pub fn mk_maybe_uninit(self, ty: Ty<'tcx>) -> Ty<'tcx> {
24072413
let def_id = self.require_lang_item(lang_items::MaybeUninitLangItem, None);

src/librustc_typeck/check/expr.rs

+68-20
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::check::fatally_break_rust;
1212
use crate::check::report_unexpected_variant_res;
1313
use crate::check::Needs;
1414
use crate::check::TupleArgumentsFlag::DontTupleArguments;
15-
use crate::check::method::SelfSource;
15+
use crate::check::method::{probe, SelfSource, MethodError};
1616
use crate::util::common::ErrorReported;
1717
use crate::util::nodemap::FxHashMap;
1818
use crate::astconv::AstConv as _;
@@ -29,6 +29,7 @@ use rustc::hir::def::{CtorKind, Res, DefKind};
2929
use rustc::hir::ptr::P;
3030
use rustc::infer;
3131
use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
32+
use rustc::middle::lang_items;
3233
use rustc::mir::interpret::GlobalId;
3334
use rustc::ty;
3435
use rustc::ty::adjustment::{
@@ -775,35 +776,80 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
775776
// no need to check for bot/err -- callee does that
776777
let rcvr_t = self.structurally_resolved_type(args[0].span, rcvr_t);
777778

778-
let method = match self.lookup_method(rcvr_t,
779-
segment,
780-
span,
781-
expr,
782-
rcvr) {
779+
let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr) {
783780
Ok(method) => {
784781
self.write_method_call(expr.hir_id, method);
785782
Ok(method)
786783
}
787784
Err(error) => {
788785
if segment.ident.name != kw::Invalid {
789-
self.report_method_error(span,
790-
rcvr_t,
791-
segment.ident,
792-
SelfSource::MethodCall(rcvr),
793-
error,
794-
Some(args));
786+
self.report_extended_method_error(segment, span, args, rcvr_t, error);
795787
}
796788
Err(())
797789
}
798790
};
799791

800792
// Call the generic checker.
801-
self.check_method_argument_types(span,
802-
expr.span,
803-
method,
804-
&args[1..],
805-
DontTupleArguments,
806-
expected)
793+
self.check_method_argument_types(
794+
span,
795+
expr.span,
796+
method,
797+
&args[1..],
798+
DontTupleArguments,
799+
expected,
800+
)
801+
}
802+
803+
fn report_extended_method_error(
804+
&self,
805+
segment: &hir::PathSegment,
806+
span: Span,
807+
args: &'tcx [hir::Expr],
808+
rcvr_t: Ty<'tcx>,
809+
error: MethodError<'tcx>
810+
) {
811+
let rcvr = &args[0];
812+
let try_alt_rcvr = |err: &mut DiagnosticBuilder<'_>, new_rcvr_t| {
813+
if let Ok(pick) = self.lookup_probe(
814+
span,
815+
segment.ident,
816+
new_rcvr_t,
817+
rcvr,
818+
probe::ProbeScope::AllTraits,
819+
) {
820+
err.span_label(
821+
pick.item.ident.span,
822+
&format!("the method is available for `{}` here", new_rcvr_t),
823+
);
824+
}
825+
};
826+
827+
if let Some(mut err) = self.report_method_error(
828+
span,
829+
rcvr_t,
830+
segment.ident,
831+
SelfSource::MethodCall(rcvr),
832+
error,
833+
Some(args),
834+
) {
835+
if let ty::Adt(..) = rcvr_t.sty {
836+
// Try alternative arbitrary self types that could fulfill this call.
837+
// FIXME: probe for all types that *could* be arbitrary self-types, not
838+
// just this whitelist.
839+
let box_rcvr_t = self.tcx.mk_box(rcvr_t);
840+
try_alt_rcvr(&mut err, box_rcvr_t);
841+
let pin_rcvr_t = self.tcx.mk_lang_item(
842+
rcvr_t,
843+
lang_items::PinTypeLangItem,
844+
);
845+
try_alt_rcvr(&mut err, pin_rcvr_t);
846+
let arc_rcvr_t = self.tcx.mk_lang_item(rcvr_t, lang_items::Arc);
847+
try_alt_rcvr(&mut err, arc_rcvr_t);
848+
let rc_rcvr_t = self.tcx.mk_lang_item(rcvr_t, lang_items::Rc);
849+
try_alt_rcvr(&mut err, rc_rcvr_t);
850+
}
851+
err.emit();
852+
}
807853
}
808854

809855
fn check_expr_cast(
@@ -1466,8 +1512,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14661512
let struct_variant_def = def.non_enum_variant();
14671513
let field_names = self.available_field_names(struct_variant_def);
14681514
if !field_names.is_empty() {
1469-
err.note(&format!("available fields are: {}",
1470-
self.name_series_display(field_names)));
1515+
err.note(&format!(
1516+
"available fields are: {}",
1517+
self.name_series_display(field_names),
1518+
));
14711519
}
14721520
}
14731521
}

src/librustc_typeck/check/method/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
245245
Ok(result.callee)
246246
}
247247

248-
fn lookup_probe(
248+
pub fn lookup_probe(
249249
&self,
250250
span: Span,
251251
method_name: ast::Ident,

src/librustc_typeck/check/method/suggest.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
6969
source: SelfSource<'b>,
7070
error: MethodError<'tcx>,
7171
args: Option<&'tcx [hir::Expr]>,
72-
) {
72+
) -> Option<DiagnosticBuilder<'_>> {
7373
let orig_span = span;
7474
let mut span = span;
7575
// Avoid suggestions when we don't know what's going on.
7676
if rcvr_ty.references_error() {
77-
return;
77+
return None;
7878
}
7979

8080
let print_disambiguation_help = |
@@ -314,7 +314,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
314314
_ => {}
315315
}
316316
err.emit();
317-
return;
317+
return None;
318318
} else {
319319
span = item_name.span;
320320
let mut err = struct_span_err!(
@@ -529,7 +529,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
529529
);
530530
}
531531

532-
err.emit();
532+
return Some(err);
533533
}
534534

535535
MethodError::Ambiguity(sources) => {
@@ -573,6 +573,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
573573
bug!("no return type expectations but got BadReturnType")
574574
}
575575
}
576+
None
576577
}
577578

578579
fn suggest_use_candidates(&self,

src/librustc_typeck/check/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3580,7 +3580,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
35803580
SelfSource::QPath(qself),
35813581
error,
35823582
None,
3583-
);
3583+
).map(|mut e| e.emit());
35843584
}
35853585
result
35863586
});

src/test/ui/impl-trait/no-method-suggested-traits.stderr

+8
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,14 @@ LL | use foo::Bar;
4949
error[E0599]: no method named `method` found for type `std::rc::Rc<&mut std::boxed::Box<&char>>` in the current scope
5050
--> $DIR/no-method-suggested-traits.rs:32:43
5151
|
52+
LL | fn method(&self) {}
53+
| ------
54+
| |
55+
| the method is available for `std::boxed::Box<std::rc::Rc<&mut std::boxed::Box<&char>>>` here
56+
| the method is available for `std::pin::Pin<std::rc::Rc<&mut std::boxed::Box<&char>>>` here
57+
| the method is available for `std::sync::Arc<std::rc::Rc<&mut std::boxed::Box<&char>>>` here
58+
| the method is available for `std::rc::Rc<std::rc::Rc<&mut std::boxed::Box<&char>>>` here
59+
...
5260
LL | std::rc::Rc::new(&mut Box::new(&'a')).method();
5361
| ^^^^^^
5462
|
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
struct A;
2+
3+
impl A {
4+
fn foo(self: Box<Self>) {}
5+
}
6+
7+
fn main() {
8+
A.foo(); //~ ERROR E0599
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0599]: no method named `foo` found for type `A` in the current scope
2+
--> $DIR/point-at-arbitrary-self-type-method.rs:8:7
3+
|
4+
LL | struct A;
5+
| --------- method `foo` not found for this
6+
...
7+
LL | fn foo(self: Box<Self>) {}
8+
| --- the method is available for `std::boxed::Box<A>` here
9+
...
10+
LL | A.foo();
11+
| ^^^
12+
13+
error: aborting due to previous error
14+
15+
For more information about this error, try `rustc --explain E0599`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
trait B { fn foo(self: Box<Self>); }
2+
struct A;
3+
4+
impl B for A {
5+
fn foo(self: Box<Self>) {}
6+
}
7+
8+
fn main() {
9+
A.foo() //~ ERROR E0599
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error[E0599]: no method named `foo` found for type `A` in the current scope
2+
--> $DIR/point-at-arbitrary-self-type-trait-method.rs:9:7
3+
|
4+
LL | trait B { fn foo(self: Box<Self>); }
5+
| --- the method is available for `std::boxed::Box<A>` here
6+
LL | struct A;
7+
| --------- method `foo` not found for this
8+
...
9+
LL | A.foo()
10+
| ^^^
11+
|
12+
= help: items from traits can only be used if the trait is implemented and in scope
13+
= note: the following trait defines an item `foo`, perhaps you need to implement it:
14+
candidate #1: `B`
15+
16+
error: aborting due to previous error
17+
18+
For more information about this error, try `rustc --explain E0599`.

src/test/ui/traits/trait-item-privacy.stderr

+7
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@ error[E0599]: no method named `b` found for type `S` in the current scope
1717
LL | struct S;
1818
| --------- method `b` not found for this
1919
...
20+
LL | fn b(&self) { }
21+
| -
22+
| |
23+
| the method is available for `std::boxed::Box<S>` here
24+
| the method is available for `std::sync::Arc<S>` here
25+
| the method is available for `std::rc::Rc<S>` here
26+
...
2027
LL | S.b();
2128
| ^
2229
|

0 commit comments

Comments
 (0)