Skip to content

Commit 286503a

Browse files
committed
Refactor and add comments to code in receiver_is_valid
also updated some error messages removed the code manually checking for `receiver_ty: Deref<Target=self_ty>`, in favour of using autoderef but only doing one iteration. This will cause error messages to be more consistent. Before, a "mismatched method receiver" error would be emitted when `receiver_ty` was valid except for a lifetime parameter, but only when `feature(arbitrary_self_types)` was enabled, and without the feature flag the error would be "uncoercible receiver". Now it emits "mismatched method receiver" in both cases.
1 parent 1d93c61 commit 286503a

File tree

5 files changed

+46
-69
lines changed

5 files changed

+46
-69
lines changed

src/librustc_typeck/check/wfcheck.rs

+34-57
Original file line numberDiff line numberDiff line change
@@ -760,8 +760,8 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
760760
if !receiver_is_valid(fcx, span, receiver_ty, self_ty, true) {
761761
// report error, arbitrary_self_types was enabled
762762
fcx.tcx.sess.diagnostic().mut_span_err(
763-
span, &format!("invalid `self` type: {:?}", receiver_ty)
764-
).note(&format!("type must be `{:?}` or a type that dereferences to it", self_ty))
763+
span, &format!("invalid method receiver type: {:?}", receiver_ty)
764+
).note("type of `self` must be `Self` or a type that dereferences to it")
765765
.help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`")
766766
.code(DiagnosticId::Error("E0307".into()))
767767
.emit();
@@ -785,8 +785,8 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
785785
} else {
786786
// report error, would not have worked with arbitrary_self_types
787787
fcx.tcx.sess.diagnostic().mut_span_err(
788-
span, &format!("invalid `self` type: {:?}", receiver_ty)
789-
).note(&format!("type must be `{:?}` or a type that dereferences to it", self_ty))
788+
span, &format!("invalid method receiver type: {:?}", receiver_ty)
789+
).note("type must be `Self` or a type that dereferences to it")
790790
.help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`")
791791
.code(DiagnosticId::Error("E0307".into()))
792792
.emit();
@@ -800,9 +800,9 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
800800
/// through a `*const/mut T` raw pointer. If the feature is not enabled, the requirements are more
801801
/// strict: `receiver_ty` must implement `Receiver` and directly implement `Deref<Target=self_ty>`.
802802
///
803-
/// NB: there are cases this function returns `true` but then causes an error to be raised later,
803+
/// NB: there are cases this function returns `true` but causes an error to be emitted,
804804
/// particularly when `receiver_ty` derefs to a type that is the same as `self_ty` but has the
805-
/// wrong lifetime.
805+
/// wrong lifetime. Be careful of this if you are calling this function speculatively.
806806
fn receiver_is_valid<'fcx, 'tcx, 'gcx>(
807807
fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
808808
span: Span,
@@ -814,6 +814,7 @@ fn receiver_is_valid<'fcx, 'tcx, 'gcx>(
814814

815815
let can_eq_self = |ty| fcx.infcx.can_eq(fcx.param_env, self_ty, ty).is_ok();
816816

817+
// `self: Self` is always valid
817818
if can_eq_self(receiver_ty) {
818819
if let Some(mut err) = fcx.demand_eqtype_with_origin(&cause, self_ty, receiver_ty) {
819820
err.emit();
@@ -823,96 +824,72 @@ fn receiver_is_valid<'fcx, 'tcx, 'gcx>(
823824

824825
let mut autoderef = fcx.autoderef(span, receiver_ty);
825826

827+
// the `arbitrary_self_types` feature allows raw pointer receivers like `self: *const Self`
826828
if arbitrary_self_types_enabled {
827829
autoderef = autoderef.include_raw_pointers();
828830
}
829831

830-
// skip the first type, we know its not equal to `self_ty`
832+
// the first type is `receiver_ty`, which we know its not equal to `self_ty`. skip it.
831833
autoderef.next();
832834

833-
let potential_self_ty = loop {
835+
// keep dereferencing `receiver_ty` until we get to `self_ty`
836+
loop {
834837
if let Some((potential_self_ty, _)) = autoderef.next() {
835838
debug!("receiver_is_valid: potential self type `{:?}` to match `{:?}`",
836839
potential_self_ty, self_ty);
837840

838841
if can_eq_self(potential_self_ty) {
839-
break potential_self_ty
842+
autoderef.finalize(fcx);
843+
844+
if let Some(mut err) = fcx.demand_eqtype_with_origin(
845+
&cause, self_ty, potential_self_ty
846+
) {
847+
err.emit();
848+
}
849+
850+
break
840851
}
841852
} else {
842853
debug!("receiver_is_valid: type `{:?}` does not deref to `{:?}`",
843854
receiver_ty, self_ty);
844855
return false
845856
}
846-
};
847857

848-
if !arbitrary_self_types_enabled {
849-
// check that receiver_ty: Receiver<Target=self_ty>
858+
// without the `arbitrary_self_types` feature, `receiver_ty` must directly deref to
859+
// `self_ty`. Enforce this by only doing one iteration of the loop
860+
if !arbitrary_self_types_enabled {
861+
return false
862+
}
863+
}
850864

851-
let receiver_trait_def_id = match fcx.tcx.lang_items().receiver_trait() {
865+
// without `feature(arbitrary_self_types)`, we require that `receiver_ty` implements `Receiver`
866+
if !arbitrary_self_types_enabled {
867+
let trait_def_id = match fcx.tcx.lang_items().receiver_trait() {
852868
Some(did) => did,
853869
None => {
854870
debug!("receiver_is_valid: missing Receiver trait");
855871
return false
856872
}
857873
};
858874

859-
let receiver_trait_ref = ty::TraitRef{
860-
def_id: receiver_trait_def_id,
875+
let trait_ref = ty::TraitRef{
876+
def_id: trait_def_id,
861877
substs: fcx.tcx.mk_substs_trait(receiver_ty, &[]),
862878
};
863879

864-
let receiver_obligation = traits::Obligation::new(
880+
let obligation = traits::Obligation::new(
865881
cause.clone(),
866882
fcx.param_env,
867-
receiver_trait_ref.to_predicate()
883+
trait_ref.to_predicate()
868884
);
869885

870-
if !fcx.predicate_must_hold(&receiver_obligation) {
886+
if !fcx.predicate_must_hold(&obligation) {
871887
debug!("receiver_is_valid: type `{:?}` does not implement `Receiver` trait",
872888
receiver_ty);
873889
return false
874890
}
875-
876-
let deref_trait_def_id = match fcx.tcx.lang_items().deref_trait() {
877-
Some(did) => did,
878-
None => {
879-
debug!("receiver_is_valid: missing Deref trait");
880-
return false
881-
}
882-
};
883-
884-
let deref_trait_ref = ty::TraitRef {
885-
def_id: deref_trait_def_id,
886-
substs: fcx.tcx.mk_substs_trait(receiver_ty, &[]),
887-
};
888-
889-
let projection_ty = ty::ProjectionTy::from_ref_and_name(
890-
fcx.tcx, deref_trait_ref, ast::Ident::from_str("Target")
891-
);
892-
893-
let projection_predicate = ty::Binder::dummy(ty::ProjectionPredicate {
894-
projection_ty, ty: self_ty
895-
}).to_predicate();
896-
897-
let deref_obligation = traits::Obligation::new(
898-
cause.clone(),
899-
fcx.param_env,
900-
projection_predicate,
901-
);
902-
903-
if !fcx.predicate_must_hold(&deref_obligation) {
904-
debug!("receiver_is_valid: type `{:?}` does not directly deref to `{:?}`",
905-
receiver_ty, self_ty);
906-
return false
907-
}
908-
}
909-
910-
if let Some(mut err) = fcx.demand_eqtype_with_origin(&cause, self_ty, potential_self_ty) {
911-
err.emit();
912891
}
913892

914-
autoderef.finalize(fcx);
915-
916893
true
917894
}
918895

src/test/ui/span/issue-27522.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
struct SomeType {}
1414

1515
trait Foo {
16-
fn handler(self: &SomeType); //~ ERROR invalid `self` type
16+
fn handler(self: &SomeType); //~ ERROR invalid method receiver type
1717
}
1818

1919
fn main() {}

src/test/ui/span/issue-27522.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
error[E0307]: invalid `self` type: &SomeType
1+
error[E0307]: invalid method receiver type: &SomeType
22
--> $DIR/issue-27522.rs:16:22
33
|
4-
LL | fn handler(self: &SomeType); //~ ERROR invalid `self` type
4+
LL | fn handler(self: &SomeType); //~ ERROR invalid method receiver type
55
| ^^^^^^^^^
66
|
77
= note: type must be `Self` or a type that dereferences to it

src/test/ui/ufcs/ufcs-explicit-self-bad.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ struct Foo {
1616

1717
impl Foo {
1818
fn foo(self: isize, x: isize) -> isize {
19-
//~^ ERROR invalid `self` type
19+
//~^ ERROR invalid method receiver type
2020
self.f + x
2121
}
2222
}
@@ -27,11 +27,11 @@ struct Bar<T> {
2727

2828
impl<T> Bar<T> {
2929
fn foo(self: Bar<isize>, x: isize) -> isize {
30-
//~^ ERROR invalid `self` type
30+
//~^ ERROR invalid method receiver type
3131
x
3232
}
3333
fn bar(self: &Bar<usize>, x: isize) -> isize {
34-
//~^ ERROR invalid `self` type
34+
//~^ ERROR invalid method receiver type
3535
x
3636
}
3737
}

src/test/ui/ufcs/ufcs-explicit-self-bad.stderr

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,28 @@
1-
error[E0307]: invalid `self` type: isize
1+
error[E0307]: invalid method receiver type: isize
22
--> $DIR/ufcs-explicit-self-bad.rs:18:18
33
|
44
LL | fn foo(self: isize, x: isize) -> isize {
55
| ^^^^^
66
|
7-
= note: type must be `Foo` or a type that dereferences to it
7+
= note: type must be `Self` or a type that dereferences to it
88
= help: consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`
99

10-
error[E0307]: invalid `self` type: Bar<isize>
10+
error[E0307]: invalid method receiver type: Bar<isize>
1111
--> $DIR/ufcs-explicit-self-bad.rs:29:18
1212
|
1313
LL | fn foo(self: Bar<isize>, x: isize) -> isize {
1414
| ^^^^^^^^^^
1515
|
16-
= note: type must be `Bar<T>` or a type that dereferences to it
16+
= note: type must be `Self` or a type that dereferences to it
1717
= help: consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`
1818

19-
error[E0307]: invalid `self` type: &Bar<usize>
19+
error[E0307]: invalid method receiver type: &Bar<usize>
2020
--> $DIR/ufcs-explicit-self-bad.rs:33:18
2121
|
2222
LL | fn bar(self: &Bar<usize>, x: isize) -> isize {
2323
| ^^^^^^^^^^^
2424
|
25-
= note: type must be `Bar<T>` or a type that dereferences to it
25+
= note: type must be `Self` or a type that dereferences to it
2626
= help: consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`
2727

2828
error[E0308]: mismatched method receiver

0 commit comments

Comments
 (0)