Skip to content

Commit

Permalink
Rollup merge of rust-lang#123962 - oli-obk:define_opaque_types5, r=lcnr
Browse files Browse the repository at this point in the history
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!()
}
```

r? `````@compiler-errors`````

fixes  rust-lang#121404

cc rust-lang#116652
  • Loading branch information
matthiaskrgr committed Jun 13, 2024
2 parents 4d79179 + 9cf60ee commit 3d7a326
Show file tree
Hide file tree
Showing 42 changed files with 922 additions and 79 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -628,7 +628,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return;
};

let pick = self.confirm_method(
let pick = self.confirm_method_for_diagnostic(
call_expr.span,
callee_expr,
call_expr,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1418,7 +1418,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let impl_ty = self.normalize(span, tcx.type_of(impl_def_id).instantiate(tcx, args));
let self_ty = self.normalize(span, self_ty);
match self.at(&self.misc(span), self.param_env).eq(
DefineOpaqueTypes::No,
DefineOpaqueTypes::Yes,
impl_ty,
self_ty,
) {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/method/confirm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
args,
})),
);
match self.at(&cause, self.param_env).sup(DefineOpaqueTypes::No, method_self_ty, self_ty) {
match self.at(&cause, self.param_env).sup(DefineOpaqueTypes::Yes, method_self_ty, self_ty) {
Ok(InferOk { obligations, value: () }) => {
self.register_predicates(obligations);
}
Expand Down
65 changes: 29 additions & 36 deletions compiler/rustc_hir_typeck/src/method/probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -634,8 +634,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
}

#[instrument(level = "debug", skip(self))]
fn assemble_probe(&mut self, self_ty: &Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>) {
debug!("assemble_probe: self_ty={:?}", self_ty);
let raw_self_ty = self_ty.value.value;
match *raw_self_ty.kind() {
ty::Dynamic(data, ..) if let Some(p) = data.principal() => {
Expand Down Expand Up @@ -713,13 +713,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
}

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

debug!("assemble_inherent_impl_probe {:?}", impl_def_id);

for item in self.impl_or_trait_item(impl_def_id) {
if !self.has_applicable_self(&item) {
// No receiver declared. Not a candidate.
Expand All @@ -737,9 +736,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
}

#[instrument(level = "debug", skip(self))]
fn assemble_inherent_candidates_from_object(&mut self, self_ty: Ty<'tcx>) {
debug!("assemble_inherent_candidates_from_object(self_ty={:?})", self_ty);

let principal = match self_ty.kind() {
ty::Dynamic(ref data, ..) => Some(data),
_ => None,
Expand Down Expand Up @@ -768,9 +766,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
});
}

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

let bounds = self.param_env.caller_bounds().iter().filter_map(|predicate| {
let bound_predicate = predicate.kind();
Expand Down Expand Up @@ -826,6 +824,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
}

#[instrument(level = "debug", skip(self))]
fn assemble_extension_candidates_for_traits_in_scope(&mut self) {
let mut duplicates = FxHashSet::default();
let opt_applicable_traits = self.tcx.in_scope_traits(self.scope_expr_id);
Expand All @@ -842,6 +841,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
}

#[instrument(level = "debug", skip(self))]
fn assemble_extension_candidates_for_all_traits(&mut self) {
let mut duplicates = FxHashSet::default();
for trait_info in suggest::all_traits(self.tcx) {
Expand All @@ -863,12 +863,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
}

#[instrument(level = "debug", skip(self))]
fn assemble_extension_candidates_for_trait(
&mut self,
import_ids: &SmallVec<[LocalDefId; 1]>,
trait_def_id: DefId,
) {
debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})", trait_def_id);
let trait_args = self.fresh_args_for_item(self.span, trait_def_id);
let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, trait_args);

Expand Down Expand Up @@ -958,6 +958,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
///////////////////////////////////////////////////////////////////////////
// THE ACTUAL SEARCH

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

Expand Down Expand Up @@ -1386,6 +1387,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
}

#[instrument(level = "trace", skip(self, possibly_unsatisfied_predicates), ret)]
fn consider_probe(
&self,
self_ty: Ty<'tcx>,
Expand Down Expand Up @@ -1415,15 +1417,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
(xform_self_ty, xform_ret_ty) =
self.xform_self_ty(probe.item, impl_ty, impl_args);
xform_self_ty = ocx.normalize(cause, self.param_env, xform_self_ty);
// FIXME: Make this `ocx.sup` once we define opaques more eagerly.
match self.at(cause, self.param_env).sup(
DefineOpaqueTypes::No,
xform_self_ty,
self_ty,
) {
Ok(infer_ok) => {
ocx.register_infer_ok_obligations(infer_ok);
}
match ocx.sup(cause, self.param_env, xform_self_ty, self_ty) {
Ok(()) => {}
Err(err) => {
debug!("--> cannot relate self-types {:?}", err);
return ProbeResult::NoMatch;
Expand Down Expand Up @@ -1484,19 +1479,23 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
(xform_self_ty, xform_ret_ty) =
self.xform_self_ty(probe.item, trait_ref.self_ty(), trait_ref.args);
xform_self_ty = ocx.normalize(cause, self.param_env, xform_self_ty);
// FIXME: Make this `ocx.sup` once we define opaques more eagerly.
match self.at(cause, self.param_env).sup(
DefineOpaqueTypes::No,
xform_self_ty,
self_ty,
) {
Ok(infer_ok) => {
ocx.register_infer_ok_obligations(infer_ok);
}
Err(err) => {
debug!("--> cannot relate self-types {:?}", err);
match self_ty.kind() {
// HACK: opaque types will match anything for which their bounds hold.
// Thus we need to prevent them from trying to match the `&_` autoref
// candidates that get created for `&self` trait methods.
ty::Alias(ty::Opaque, alias_ty)
if self.infcx.can_define_opaque_ty(alias_ty.def_id)
&& !xform_self_ty.is_ty_var() =>
{
return ProbeResult::NoMatch;
}
_ => match ocx.sup(cause, self.param_env, xform_self_ty, self_ty) {
Ok(()) => {}
Err(err) => {
debug!("--> cannot relate self-types {:?}", err);
return ProbeResult::NoMatch;
}
},
}
let obligation = traits::Obligation::new(
self.tcx,
Expand Down Expand Up @@ -1536,15 +1535,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
(xform_self_ty, xform_ret_ty) =
self.xform_self_ty(probe.item, trait_ref.self_ty(), trait_ref.args);
xform_self_ty = ocx.normalize(cause, self.param_env, xform_self_ty);
// FIXME: Make this `ocx.sup` once we define opaques more eagerly.
match self.at(cause, self.param_env).sup(
DefineOpaqueTypes::No,
xform_self_ty,
self_ty,
) {
Ok(infer_ok) => {
ocx.register_infer_ok_obligations(infer_ok);
}
match ocx.sup(cause, self.param_env, xform_self_ty, self_ty) {
Ok(()) => {}
Err(err) => {
debug!("--> cannot relate self-types {:?}", err);
return ProbeResult::NoMatch;
Expand Down Expand Up @@ -1665,6 +1657,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
/// Similarly to `probe_for_return_type`, this method attempts to find the best matching
/// candidate method where the method name may have been misspelled. Similarly to other
/// edit distance based suggestions, we provide at most one such suggestion.
#[instrument(level = "debug", skip(self))]
pub(crate) fn probe_for_similar_candidate(
&mut self,
) -> Result<Option<ty::AssocItem>, MethodError<'tcx>> {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/traits/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ pub struct CandidateStep<'tcx> {

#[derive(Copy, Clone, Debug, HashStable)]
pub struct MethodAutoderefStepsResult<'tcx> {
/// The valid autoderef steps that could be find.
/// The valid autoderef steps that could be found.
pub steps: &'tcx [CandidateStep<'tcx>],
/// If Some(T), a type autoderef reported an error on.
pub opt_bad_ty: Option<&'tcx MethodAutoderefBadTy<'tcx>>,
Expand Down
17 changes: 17 additions & 0 deletions tests/ui/impl-trait/call_method_ambiguous.next.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
error[E0282]: type annotations needed
--> $DIR/call_method_ambiguous.rs:29:13
|
LL | let mut iter = foo(n - 1, m);
| ^^^^^^^^
LL |
LL | assert_eq!(iter.get(), 1);
| ---- type must be known at this point
|
help: consider giving `iter` an explicit type
|
LL | let mut iter: /* Type */ = foo(n - 1, m);
| ++++++++++++

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0282`.
39 changes: 39 additions & 0 deletions tests/ui/impl-trait/call_method_ambiguous.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//@ revisions: current next
//@[next] compile-flags: -Znext-solver
//@[current] run-pass

#![feature(precise_capturing)]
#![allow(incomplete_features)]

trait Get {
fn get(&mut self) -> u32;
}

impl Get for () {
fn get(&mut self) -> u32 {
0
}
}

impl<T> Get for &mut T
where
T: Get,
{
fn get(&mut self) -> u32 {
T::get(self) + 1
}
}

fn foo(n: usize, m: &mut ()) -> impl use<'_> Get {
if n > 0 {
let mut iter = foo(n - 1, m);
//[next]~^ type annotations needed
assert_eq!(iter.get(), 1);
}
m
}

fn main() {
let g = foo(1, &mut ()).get();
assert_eq!(g, 1);
}
17 changes: 17 additions & 0 deletions tests/ui/impl-trait/call_method_on_inherent_impl.next.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
error[E0282]: type annotations needed
--> $DIR/call_method_on_inherent_impl.rs:18:13
|
LL | let x = my_foo();
| ^
LL |
LL | x.my_debug();
| - type must be known at this point
|
help: consider giving `x` an explicit type
|
LL | let x: /* Type */ = my_foo();
| ++++++++++++

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0282`.
25 changes: 25 additions & 0 deletions tests/ui/impl-trait/call_method_on_inherent_impl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//@ revisions: current next
//@[next] compile-flags: -Znext-solver
//@[current] check-pass

trait MyDebug {
fn my_debug(&self);
}

impl<T> MyDebug for T
where
T: std::fmt::Debug,
{
fn my_debug(&self) {}
}

fn my_foo() -> impl std::fmt::Debug {
if false {
let x = my_foo();
//[next]~^ type annotations needed
x.my_debug();
}
()
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
error[E0599]: no method named `my_debug` found for reference `&impl Debug` in the current scope
--> $DIR/call_method_on_inherent_impl_on_rigid_type.rs:16:11
|
LL | x.my_debug();
| ^^^^^^^^ method not found in `&impl Debug`
|
= help: items from traits can only be used if the trait is implemented and in scope
note: `MyDebug` defines an item `my_debug`, perhaps you need to implement it
--> $DIR/call_method_on_inherent_impl_on_rigid_type.rs:4:1
|
LL | trait MyDebug {
| ^^^^^^^^^^^^^

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0599`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
error[E0282]: type annotations needed for `&_`
--> $DIR/call_method_on_inherent_impl_on_rigid_type.rs:14:13
|
LL | let x = &my_foo();
| ^
LL |
LL | x.my_debug();
| -------- type must be known at this point
|
help: consider giving `x` an explicit type, where the placeholders `_` are specified
|
LL | let x: &_ = &my_foo();
| ++++

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0282`.
22 changes: 22 additions & 0 deletions tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//@ revisions: current next
//@[next] compile-flags: -Znext-solver

trait MyDebug {
fn my_debug(&self);
}

impl MyDebug for &() {
fn my_debug(&self) {}
}

fn my_foo() -> impl std::fmt::Debug {
if false {
let x = &my_foo();
//[next]~^ ERROR: type annotations needed
x.my_debug();
//[current]~^ ERROR: no method named `my_debug`
}
()
}

fn main() {}
Loading

0 comments on commit 3d7a326

Please sign in to comment.