Skip to content

Commit 384ba20

Browse files
committed
Auto merge of rust-lang#123962 - oli-obk:define_opaque_types5, r=<try>
change method resolution to constrain hidden types instead of rejecting method candidates Some of these are in probes and may affect inference. This is therefore a breaking change. This allows new code to compile on stable: ```rust trait Trait {} impl Trait for u32 {} struct Bar<T>(T); impl Bar<u32> { fn foo(self) {} } fn foo(x: bool) -> Bar<impl Sized> { if x { let x = foo(false); x.foo(); //^ this used to not find the `foo` method, because while we did equate `x`'s type with possible candidates, we didn't allow opaque type inference while doing so } todo!() } ``` But it is also a breaking change, since `&self` and `&mut self` method calls on recursive RPIT function calls now constrain the hidden type to `&_` and `&mut _` respectively. This is not what users really expect or want from this, but there's way around this. r? `@compiler-errors` fixes rust-lang#121404 cc rust-lang#116652
2 parents 7f2fc33 + 919500f commit 384ba20

31 files changed

+569
-63
lines changed

compiler/rustc_data_structures/src/obligation_forest/mod.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,10 @@ impl<O: ForestObligation> ObligationForest<O> {
359359
Entry::Vacant(v) => {
360360
let obligation_tree_id = match parent {
361361
Some(parent_index) => self.nodes[parent_index].obligation_tree_id,
362-
None => self.obligation_tree_id_generator.next().unwrap(),
362+
// FIXME(type_alias_impl_trait): with `#[defines]` attributes required to define hidden
363+
// types we can convert this back to a `next` method call, as this function shouldn't be
364+
// defining a hidden type anyway.
365+
None => Iterator::next(&mut self.obligation_tree_id_generator).unwrap(),
363366
};
364367

365368
let already_failed = parent.is_some()

compiler/rustc_hir_typeck/src/callee.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -627,7 +627,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
627627
return;
628628
};
629629

630-
let pick = self.confirm_method(
630+
let pick = self.confirm_method_for_diagnostic(
631631
call_expr.span,
632632
callee_expr,
633633
call_expr,

compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1435,7 +1435,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14351435
let impl_ty = self.normalize(span, tcx.type_of(impl_def_id).instantiate(tcx, args));
14361436
let self_ty = self.normalize(span, self_ty);
14371437
match self.at(&self.misc(span), self.param_env).eq(
1438-
DefineOpaqueTypes::No,
1438+
DefineOpaqueTypes::Yes,
14391439
impl_ty,
14401440
self_ty,
14411441
) {

compiler/rustc_hir_typeck/src/method/confirm.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
499499
args,
500500
})),
501501
);
502-
match self.at(&cause, self.param_env).sup(DefineOpaqueTypes::No, method_self_ty, self_ty) {
502+
match self.at(&cause, self.param_env).sup(DefineOpaqueTypes::Yes, method_self_ty, self_ty) {
503503
Ok(InferOk { obligations, value: () }) => {
504504
self.register_predicates(obligations);
505505
}

compiler/rustc_hir_typeck/src/method/probe.rs

+29-17
Original file line numberDiff line numberDiff line change
@@ -651,8 +651,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
651651
}
652652
}
653653

654+
#[instrument(level = "debug", skip(self))]
654655
fn assemble_probe(&mut self, self_ty: &Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>) {
655-
debug!("assemble_probe: self_ty={:?}", self_ty);
656656
let raw_self_ty = self_ty.value.value;
657657
match *raw_self_ty.kind() {
658658
ty::Dynamic(data, ..) if let Some(p) = data.principal() => {
@@ -730,13 +730,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
730730
}
731731
}
732732

733+
#[instrument(level = "debug", skip(self))]
733734
fn assemble_inherent_impl_probe(&mut self, impl_def_id: DefId) {
734735
if !self.impl_dups.insert(impl_def_id) {
735736
return; // already visited
736737
}
737738

738-
debug!("assemble_inherent_impl_probe {:?}", impl_def_id);
739-
740739
for item in self.impl_or_trait_item(impl_def_id) {
741740
if !self.has_applicable_self(&item) {
742741
// No receiver declared. Not a candidate.
@@ -786,9 +785,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
786785
}
787786
}
788787

788+
#[instrument(level = "debug", skip(self))]
789789
fn assemble_inherent_candidates_from_object(&mut self, self_ty: Ty<'tcx>) {
790-
debug!("assemble_inherent_candidates_from_object(self_ty={:?})", self_ty);
791-
792790
let principal = match self_ty.kind() {
793791
ty::Dynamic(ref data, ..) => Some(data),
794792
_ => None,
@@ -835,9 +833,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
835833
});
836834
}
837835

836+
#[instrument(level = "debug", skip(self))]
838837
fn assemble_inherent_candidates_from_param(&mut self, param_ty: ty::ParamTy) {
839838
// FIXME: do we want to commit to this behavior for param bounds?
840-
debug!("assemble_inherent_candidates_from_param(param_ty={:?})", param_ty);
841839

842840
let bounds = self.param_env.caller_bounds().iter().filter_map(|predicate| {
843841
let bound_predicate = predicate.kind();
@@ -904,6 +902,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
904902
}
905903
}
906904

905+
#[instrument(level = "debug", skip(self))]
907906
fn assemble_extension_candidates_for_traits_in_scope(&mut self) {
908907
let mut duplicates = FxHashSet::default();
909908
let opt_applicable_traits = self.tcx.in_scope_traits(self.scope_expr_id);
@@ -920,6 +919,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
920919
}
921920
}
922921

922+
#[instrument(level = "debug", skip(self))]
923923
fn assemble_extension_candidates_for_all_traits(&mut self) {
924924
let mut duplicates = FxHashSet::default();
925925
for trait_info in suggest::all_traits(self.tcx) {
@@ -956,12 +956,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
956956
}
957957
}
958958

959+
#[instrument(level = "debug", skip(self))]
959960
fn assemble_extension_candidates_for_trait(
960961
&mut self,
961962
import_ids: &SmallVec<[LocalDefId; 1]>,
962963
trait_def_id: DefId,
963964
) {
964-
debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})", trait_def_id);
965965
let trait_args = self.fresh_args_for_item(self.span, trait_def_id);
966966
let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, trait_args);
967967

@@ -1066,6 +1066,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
10661066
///////////////////////////////////////////////////////////////////////////
10671067
// THE ACTUAL SEARCH
10681068

1069+
#[instrument(level = "debug", skip(self))]
10691070
fn pick(mut self) -> PickResult<'tcx> {
10701071
assert!(self.method_name.is_some());
10711072

@@ -1474,6 +1475,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
14741475
}
14751476
}
14761477

1478+
#[instrument(level = "trace", skip(self, possibly_unsatisfied_predicates), ret)]
14771479
fn consider_probe(
14781480
&self,
14791481
self_ty: Ty<'tcx>,
@@ -1484,20 +1486,29 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
14841486
Option<ObligationCause<'tcx>>,
14851487
)>,
14861488
) -> ProbeResult {
1487-
debug!("consider_probe: self_ty={:?} probe={:?}", self_ty, probe);
1488-
14891489
self.probe(|_| {
14901490
// First check that the self type can be related.
1491-
let sub_obligations = match self.at(&ObligationCause::dummy(), self.param_env).sup(
1492-
DefineOpaqueTypes::No,
1493-
probe.xform_self_ty,
1494-
self_ty,
1495-
) {
1496-
Ok(InferOk { obligations, value: () }) => obligations,
1497-
Err(err) => {
1498-
debug!("--> cannot relate self-types {:?}", err);
1491+
let sub_obligations = match self_ty.kind() {
1492+
// HACK: opaque types will match anything for which their bounds hold.
1493+
// Thus we need to prevent them from trying to match the `&_` autoref
1494+
// candidates that get created for `&self` trait methods.
1495+
ty::Alias(ty::Opaque, alias_ty)
1496+
if self.infcx.can_define_opaque_ty(alias_ty.def_id)
1497+
&& !probe.xform_self_ty.is_ty_var() =>
1498+
{
14991499
return ProbeResult::NoMatch;
15001500
}
1501+
_ => match self.at(&ObligationCause::dummy(), self.param_env).sup(
1502+
DefineOpaqueTypes::Yes,
1503+
probe.xform_self_ty,
1504+
self_ty,
1505+
) {
1506+
Ok(InferOk { obligations, value: () }) => obligations,
1507+
Err(err) => {
1508+
debug!("--> cannot relate self-types {:?}", err);
1509+
return ProbeResult::NoMatch;
1510+
}
1511+
},
15011512
};
15021513

15031514
let mut result = ProbeResult::Match;
@@ -1755,6 +1766,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
17551766
/// Similarly to `probe_for_return_type`, this method attempts to find the best matching
17561767
/// candidate method where the method name may have been misspelled. Similarly to other
17571768
/// edit distance based suggestions, we provide at most one such suggestion.
1769+
#[instrument(level = "debug", skip(self))]
17581770
pub(crate) fn probe_for_similar_candidate(
17591771
&mut self,
17601772
) -> Result<Option<ty::AssocItem>, MethodError<'tcx>> {

compiler/rustc_middle/src/traits/query.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ pub struct CandidateStep<'tcx> {
162162

163163
#[derive(Copy, Clone, Debug, HashStable)]
164164
pub struct MethodAutoderefStepsResult<'tcx> {
165-
/// The valid autoderef steps that could be find.
165+
/// The valid autoderef steps that could be found.
166166
pub steps: &'tcx [CandidateStep<'tcx>],
167167
/// If Some(T), a type autoderef reported an error on.
168168
pub opt_bad_ty: Option<&'tcx MethodAutoderefBadTy<'tcx>>,

tests/ui/impl-trait/issues/issue-70877.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ fn ham() -> Foo {
2727

2828
fn oof(_: Foo) -> impl std::fmt::Debug {
2929
let mut bar = ham();
30-
let func = bar.next().unwrap();
30+
// Need to UFC invoke `Iterator::next`,
31+
// as otherwise the hidden type gets constrained to `&mut _`
32+
let func = Iterator::next(&mut bar).unwrap();
3133
return func(&"oof"); //~ ERROR opaque type's hidden type cannot be another opaque type
3234
}
3335

tests/ui/impl-trait/issues/issue-70877.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: opaque type's hidden type cannot be another opaque type from the same scope
2-
--> $DIR/issue-70877.rs:31:12
2+
--> $DIR/issue-70877.rs:33:12
33
|
44
LL | return func(&"oof");
55
| ^^^^^^^^^^^^ one of the two opaque types used here has to be outside its defining scope
+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//! Since there is only one possible `bar` method, we invoke it and subsequently
2+
//! constrain `foo`'s RPIT to `u32`.
3+
4+
//@ revisions: current next
5+
//@[next] compile-flags: -Znext-solver
6+
//@ check-pass
7+
8+
trait Trait {}
9+
10+
impl Trait for u32 {}
11+
12+
struct Bar<T>(T);
13+
14+
impl Bar<u32> {
15+
fn bar(self) {}
16+
}
17+
18+
fn foo(x: bool) -> Bar<impl Sized> {
19+
if x {
20+
let x = foo(false);
21+
x.bar();
22+
}
23+
todo!()
24+
}
25+
26+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error[E0034]: multiple applicable items in scope
2+
--> $DIR/method-resolution2.rs:25:11
3+
|
4+
LL | x.bar();
5+
| ^^^ multiple `bar` found
6+
|
7+
note: candidate #1 is defined in an impl for the type `Bar<T>`
8+
--> $DIR/method-resolution2.rs:19:5
9+
|
10+
LL | fn bar(self) {}
11+
| ^^^^^^^^^^^^
12+
note: candidate #2 is defined in an impl for the type `Bar<u32>`
13+
--> $DIR/method-resolution2.rs:15:5
14+
|
15+
LL | fn bar(self) {}
16+
| ^^^^^^^^^^^^
17+
18+
error: aborting due to 1 previous error
19+
20+
For more information about this error, try `rustc --explain E0034`.
+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//! Check that the method call does not constrain the RPIT to `i32`, even though
2+
//! `i32` is the only type that satisfies the RPIT's trait bounds.
3+
4+
//@ revisions: current next
5+
//@[next] compile-flags: -Znext-solver
6+
//@[current] check-pass
7+
8+
trait Trait {}
9+
10+
impl Trait for i32 {}
11+
12+
struct Bar<T>(T);
13+
14+
impl Bar<u32> {
15+
fn bar(self) {}
16+
}
17+
18+
impl<T: Trait> Bar<T> {
19+
fn bar(self) {}
20+
}
21+
22+
fn foo(x: bool) -> Bar<impl Trait> {
23+
if x {
24+
let x = foo(false);
25+
x.bar();
26+
//[next]~^ ERROR: multiple applicable items in scope
27+
}
28+
Bar(42_i32)
29+
}
30+
31+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error[E0034]: multiple applicable items in scope
2+
--> $DIR/method-resolution3.rs:21:11
3+
|
4+
LL | x.bar();
5+
| ^^^ multiple `bar` found
6+
|
7+
note: candidate #1 is defined in an impl for the type `Bar<i32>`
8+
--> $DIR/method-resolution3.rs:15:5
9+
|
10+
LL | fn bar(self) {}
11+
| ^^^^^^^^^^^^
12+
note: candidate #2 is defined in an impl for the type `Bar<u32>`
13+
--> $DIR/method-resolution3.rs:11:5
14+
|
15+
LL | fn bar(self) {}
16+
| ^^^^^^^^^^^^
17+
18+
error: aborting due to 1 previous error
19+
20+
For more information about this error, try `rustc --explain E0034`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error[E0034]: multiple applicable items in scope
2+
--> $DIR/method-resolution3.rs:21:11
3+
|
4+
LL | x.bar();
5+
| ^^^ multiple `bar` found
6+
|
7+
note: candidate #1 is defined in an impl for the type `Bar<i32>`
8+
--> $DIR/method-resolution3.rs:15:5
9+
|
10+
LL | fn bar(self) {}
11+
| ^^^^^^^^^^^^
12+
note: candidate #2 is defined in an impl for the type `Bar<u32>`
13+
--> $DIR/method-resolution3.rs:11:5
14+
|
15+
LL | fn bar(self) {}
16+
| ^^^^^^^^^^^^
17+
18+
error: aborting due to 1 previous error
19+
20+
For more information about this error, try `rustc --explain E0034`.
+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//! Check that we consider `Bar<impl Sized>` to successfully unify
2+
//! with both `Bar<u32>` and `Bar<i32>` (in isolation), so we bail
3+
//! out with ambiguity.
4+
5+
//@ revisions: current next
6+
//@[next] compile-flags: -Znext-solver
7+
8+
struct Bar<T>(T);
9+
10+
impl Bar<u32> {
11+
fn bar(self) {}
12+
}
13+
14+
impl Bar<i32> {
15+
fn bar(self) {}
16+
}
17+
18+
fn foo(x: bool) -> Bar<impl Sized> {
19+
if x {
20+
let x = foo(false);
21+
x.bar();
22+
//~^ ERROR: multiple applicable items in scope
23+
}
24+
todo!()
25+
}
26+
27+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error[E0282]: type annotations needed
2+
--> $DIR/method-resolution4.rs:13:9
3+
|
4+
LL | foo(false).next().unwrap();
5+
| ^^^^^^^^^^ cannot infer type
6+
7+
error[E0308]: mismatched types
8+
--> $DIR/method-resolution4.rs:16:5
9+
|
10+
LL | fn foo(b: bool) -> impl Iterator<Item = ()> {
11+
| ------------------------ the expected opaque type
12+
...
13+
LL | std::iter::empty()
14+
| ^^^^^^^^^^^^^^^^^^ types differ
15+
|
16+
= note: expected opaque type `impl Iterator<Item = ()>`
17+
found struct `std::iter::Empty<_>`
18+
19+
error: aborting due to 2 previous errors
20+
21+
Some errors have detailed explanations: E0282, E0308.
22+
For more information about an error, try `rustc --explain E0282`.

0 commit comments

Comments
 (0)