Skip to content

Commit

Permalink
Rollup merge of rust-lang#64056 - estebank:arbitrary-self-types, r=Ce…
Browse files Browse the repository at this point in the history
…ntril

Account for arbitrary self types in E0599

Fix rust-lang#62373
  • Loading branch information
Centril authored Sep 3, 2019
2 parents 1143c8a + 141f5a7 commit ececd71
Show file tree
Hide file tree
Showing 11 changed files with 148 additions and 26 deletions.
6 changes: 6 additions & 0 deletions src/librustc/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2402,6 +2402,12 @@ impl<'tcx> TyCtxt<'tcx> {
self.mk_generic_adt(def_id, ty)
}

#[inline]
pub fn mk_lang_item(self, ty: Ty<'tcx>, item: lang_items::LangItem) -> Ty<'tcx> {
let def_id = self.require_lang_item(item, None);
self.mk_generic_adt(def_id, ty)
}

#[inline]
pub fn mk_maybe_uninit(self, ty: Ty<'tcx>) -> Ty<'tcx> {
let def_id = self.require_lang_item(lang_items::MaybeUninitLangItem, None);
Expand Down
88 changes: 68 additions & 20 deletions src/librustc_typeck/check/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::check::fatally_break_rust;
use crate::check::report_unexpected_variant_res;
use crate::check::Needs;
use crate::check::TupleArgumentsFlag::DontTupleArguments;
use crate::check::method::SelfSource;
use crate::check::method::{probe, SelfSource, MethodError};
use crate::util::common::ErrorReported;
use crate::util::nodemap::FxHashMap;
use crate::astconv::AstConv as _;
Expand All @@ -29,6 +29,7 @@ use rustc::hir::def::{CtorKind, Res, DefKind};
use rustc::hir::ptr::P;
use rustc::infer;
use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc::middle::lang_items;
use rustc::mir::interpret::GlobalId;
use rustc::ty;
use rustc::ty::adjustment::{
Expand Down Expand Up @@ -775,35 +776,80 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// no need to check for bot/err -- callee does that
let rcvr_t = self.structurally_resolved_type(args[0].span, rcvr_t);

let method = match self.lookup_method(rcvr_t,
segment,
span,
expr,
rcvr) {
let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr) {
Ok(method) => {
self.write_method_call(expr.hir_id, method);
Ok(method)
}
Err(error) => {
if segment.ident.name != kw::Invalid {
self.report_method_error(span,
rcvr_t,
segment.ident,
SelfSource::MethodCall(rcvr),
error,
Some(args));
self.report_extended_method_error(segment, span, args, rcvr_t, error);
}
Err(())
}
};

// Call the generic checker.
self.check_method_argument_types(span,
expr.span,
method,
&args[1..],
DontTupleArguments,
expected)
self.check_method_argument_types(
span,
expr.span,
method,
&args[1..],
DontTupleArguments,
expected,
)
}

fn report_extended_method_error(
&self,
segment: &hir::PathSegment,
span: Span,
args: &'tcx [hir::Expr],
rcvr_t: Ty<'tcx>,
error: MethodError<'tcx>
) {
let rcvr = &args[0];
let try_alt_rcvr = |err: &mut DiagnosticBuilder<'_>, new_rcvr_t| {
if let Ok(pick) = self.lookup_probe(
span,
segment.ident,
new_rcvr_t,
rcvr,
probe::ProbeScope::AllTraits,
) {
err.span_label(
pick.item.ident.span,
&format!("the method is available for `{}` here", new_rcvr_t),
);
}
};

if let Some(mut err) = self.report_method_error(
span,
rcvr_t,
segment.ident,
SelfSource::MethodCall(rcvr),
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_lang_item(
rcvr_t,
lang_items::PinTypeLangItem,
);
try_alt_rcvr(&mut err, pin_rcvr_t);
let arc_rcvr_t = self.tcx.mk_lang_item(rcvr_t, lang_items::Arc);
try_alt_rcvr(&mut err, arc_rcvr_t);
let rc_rcvr_t = self.tcx.mk_lang_item(rcvr_t, lang_items::Rc);
try_alt_rcvr(&mut err, rc_rcvr_t);
}
err.emit();
}
}

fn check_expr_cast(
Expand Down Expand Up @@ -1466,8 +1512,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let struct_variant_def = def.non_enum_variant();
let field_names = self.available_field_names(struct_variant_def);
if !field_names.is_empty() {
err.note(&format!("available fields are: {}",
self.name_series_display(field_names)));
err.note(&format!(
"available fields are: {}",
self.name_series_display(field_names),
));
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_typeck/check/method/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Ok(result.callee)
}

fn lookup_probe(
pub fn lookup_probe(
&self,
span: Span,
method_name: ast::Ident,
Expand Down
9 changes: 5 additions & 4 deletions src/librustc_typeck/check/method/suggest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
source: SelfSource<'b>,
error: MethodError<'tcx>,
args: Option<&'tcx [hir::Expr]>,
) {
) -> Option<DiagnosticBuilder<'_>> {
let orig_span = span;
let mut span = span;
// Avoid suggestions when we don't know what's going on.
if rcvr_ty.references_error() {
return;
return None;
}

let print_disambiguation_help = |
Expand Down Expand Up @@ -314,7 +314,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
_ => {}
}
err.emit();
return;
return None;
} else {
span = item_name.span;
let mut err = struct_span_err!(
Expand Down Expand Up @@ -529,7 +529,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
}

err.emit();
return Some(err);
}

MethodError::Ambiguity(sources) => {
Expand Down Expand Up @@ -573,6 +573,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
bug!("no return type expectations but got BadReturnType")
}
}
None
}

fn suggest_use_candidates(&self,
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3580,7 +3580,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
SelfSource::QPath(qself),
error,
None,
);
).map(|mut e| e.emit());
}
result
});
Expand Down
8 changes: 8 additions & 0 deletions src/test/ui/impl-trait/no-method-suggested-traits.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
--> $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();
| ^^^^^^
|
Expand Down
9 changes: 9 additions & 0 deletions src/test/ui/self/point-at-arbitrary-self-type-method.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
struct A;

impl A {
fn foo(self: Box<Self>) {}
}

fn main() {
A.foo(); //~ ERROR E0599
}
15 changes: 15 additions & 0 deletions src/test/ui/self/point-at-arbitrary-self-type-method.stderr
Original file line number Diff line number Diff line change
@@ -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`.
10 changes: 10 additions & 0 deletions src/test/ui/self/point-at-arbitrary-self-type-trait-method.rs
Original file line number Diff line number Diff line change
@@ -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
}
18 changes: 18 additions & 0 deletions src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr
Original file line number Diff line number Diff line change
@@ -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`.
7 changes: 7 additions & 0 deletions src/test/ui/traits/trait-item-privacy.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ error[E0599]: no method named `b` found for type `S` in the current scope
LL | struct S;
| --------- 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();
| ^
|
Expand Down

0 comments on commit ececd71

Please sign in to comment.