Rollup merge of #123962 - oli-obk:define_opaque_types5, r=lcnr

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  #121404

cc https://github.com/rust-lang/rust/issues/116652
This commit is contained in:
Matthias Krüger 2024-06-14 08:35:46 +02:00 committed by GitHub
commit 0468462538
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
42 changed files with 922 additions and 79 deletions

View file

@ -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,

View file

@ -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,
) {

View file

@ -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);
}

View file

@ -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() => {
@ -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.
@ -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,
@ -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();
@ -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);
@ -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) {
@ -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);
@ -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());
@ -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>,
@ -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;
@ -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,
@ -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;
@ -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>> {

View file

@ -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>>,

View file

@ -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`.

View file

@ -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);
}

View file

@ -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`.

View file

@ -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() {}

View file

@ -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`.

View file

@ -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`.

View file

@ -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() {}

View file

@ -0,0 +1,40 @@
error[E0599]: no method named `my_debug` found for opaque type `impl Debug` in the current scope
--> $DIR/call_method_on_inherent_impl_ref.rs:20:11
|
LL | fn my_debug(&self);
| -------- the method is available for `&impl Debug` here
...
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_ref.rs:4:1
|
LL | trait MyDebug {
| ^^^^^^^^^^^^^
error[E0391]: cycle detected when computing type of opaque `my_foo::{opaque#0}`
--> $DIR/call_method_on_inherent_impl_ref.rs:15:16
|
LL | fn my_foo() -> impl std::fmt::Debug {
| ^^^^^^^^^^^^^^^^^^^^
|
note: ...which requires type-checking `my_foo`...
--> $DIR/call_method_on_inherent_impl_ref.rs:20:9
|
LL | x.my_debug();
| ^
= note: ...which requires evaluating trait selection obligation `my_foo::{opaque#0}: core::marker::Unpin`...
= note: ...which again requires computing type of opaque `my_foo::{opaque#0}`, completing the cycle
note: cycle used when computing type of `my_foo::{opaque#0}`
--> $DIR/call_method_on_inherent_impl_ref.rs:15:16
|
LL | fn my_foo() -> impl std::fmt::Debug {
| ^^^^^^^^^^^^^^^^^^^^
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0391, E0599.
For more information about an error, try `rustc --explain E0391`.

View file

@ -0,0 +1,31 @@
error[E0282]: type annotations needed
--> $DIR/call_method_on_inherent_impl_ref.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[E0282]: type annotations needed for `&_`
--> $DIR/call_method_on_inherent_impl_ref.rs:28:13
|
LL | let x = &my_bar();
| ^
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_bar();
| ++++
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0282`.

View file

@ -0,0 +1,35 @@
//@ revisions: current next
//@[next] compile-flags: -Znext-solver
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 {
//[current]~^ cycle
if false {
let x = my_foo();
//[next]~^ type annotations needed
x.my_debug();
//[current]~^ no method named `my_debug` found
}
()
}
fn my_bar() -> impl std::fmt::Debug {
if false {
let x = &my_bar();
//[next]~^ type annotations needed
x.my_debug();
}
()
}
fn main() {}

View file

@ -0,0 +1,37 @@
error[E0599]: no method named `fmt` found for opaque type `impl Debug` in the current scope
--> $DIR/call_method_without_import.rs:17:11
|
LL | x.fmt(f);
| ^^^ method not found in `impl Debug`
--> $SRC_DIR/core/src/fmt/mod.rs:LL:COL
|
= note: the method is available for `impl Debug` here
|
= help: items from traits can only be used if the trait is in scope
help: trait `Debug` which provides `fmt` is implemented but not in scope; perhaps you want to import it
|
LL + use std::fmt::Debug;
|
error[E0599]: no method named `fmt` found for mutable reference `&mut impl Debug` in the current scope
--> $DIR/call_method_without_import.rs:26:11
|
LL | x.fmt(f);
| ^^^ method not found in `&mut impl Debug`
|
= help: items from traits can only be used if the trait is in scope
help: the following traits which provide `fmt` are implemented but not in scope; perhaps you want to import one of them
|
LL + use std::fmt::Binary;
|
LL + use std::fmt::Debug;
|
LL + use std::fmt::Display;
|
LL + use std::fmt::LowerExp;
|
and 5 other candidates
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0599`.

View file

@ -0,0 +1,42 @@
//! Test that opaque types only pick up methods from traits in their bounds
//! if the trait is imported.
//!
//! FIXME: always look through the bounds of an opaque type to see if there are
//! methods that could be called on any of the bound traits, irrespective of
//! imported traits.
//@ revisions: import no_import
//@[import] check-pass
#[cfg(import)]
use std::fmt::Debug as _;
fn foo(f: &mut std::fmt::Formatter<'_>) -> impl std::fmt::Debug {
if false {
let x = foo(f);
x.fmt(f);
//[no_import]~^ ERROR: no method named `fmt` found
}
()
}
fn foo1(f: &mut std::fmt::Formatter<'_>) -> impl std::fmt::Debug {
if false {
let x = &mut foo(f);
x.fmt(f);
//[no_import]~^ ERROR: no method named `fmt` found
}
()
}
// inconsistent with this
fn bar<T>(t: impl std::fmt::Debug, f: &mut std::fmt::Formatter<'_>) {
t.fmt(f);
}
// and the desugared version, of course
fn baz<T: std::fmt::Debug>(t: T, f: &mut std::fmt::Formatter<'_>) {
t.fmt(f);
}
fn main() {}

View file

@ -0,0 +1,26 @@
//! Since there is only one possible `bar` method, we invoke it and subsequently
//! constrain `foo`'s RPIT to `u32`.
//@ revisions: current next
//@[next] compile-flags: -Znext-solver
//@ check-pass
trait Trait {}
impl Trait for u32 {}
struct Bar<T>(T);
impl Bar<u32> {
fn bar(self) {}
}
fn foo(x: bool) -> Bar<impl Sized> {
if x {
let x = foo(false);
x.bar();
}
todo!()
}
fn main() {}

View file

@ -0,0 +1,20 @@
error[E0034]: multiple applicable items in scope
--> $DIR/method-resolution2.rs:25:11
|
LL | x.bar();
| ^^^ multiple `bar` found
|
note: candidate #1 is defined in an impl for the type `Bar<T>`
--> $DIR/method-resolution2.rs:19:5
|
LL | fn bar(self) {}
| ^^^^^^^^^^^^
note: candidate #2 is defined in an impl for the type `Bar<u32>`
--> $DIR/method-resolution2.rs:15:5
|
LL | fn bar(self) {}
| ^^^^^^^^^^^^
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0034`.

View file

@ -0,0 +1,31 @@
//! Check that the method call does not constrain the RPIT to `i32`, even though
//! `i32` is the only type that satisfies the RPIT's trait bounds.
//@ revisions: current next
//@[next] compile-flags: -Znext-solver
//@[current] check-pass
trait Trait {}
impl Trait for i32 {}
struct Bar<T>(T);
impl Bar<u32> {
fn bar(self) {}
}
impl<T: Trait> Bar<T> {
fn bar(self) {}
}
fn foo(x: bool) -> Bar<impl Trait> {
if x {
let x = foo(false);
x.bar();
//[next]~^ ERROR: multiple applicable items in scope
}
Bar(42_i32)
}
fn main() {}

View file

@ -0,0 +1,20 @@
error[E0034]: multiple applicable items in scope
--> $DIR/method-resolution3.rs:21:11
|
LL | x.bar();
| ^^^ multiple `bar` found
|
note: candidate #1 is defined in an impl for the type `Bar<i32>`
--> $DIR/method-resolution3.rs:15:5
|
LL | fn bar(self) {}
| ^^^^^^^^^^^^
note: candidate #2 is defined in an impl for the type `Bar<u32>`
--> $DIR/method-resolution3.rs:11:5
|
LL | fn bar(self) {}
| ^^^^^^^^^^^^
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0034`.

View file

@ -0,0 +1,20 @@
error[E0034]: multiple applicable items in scope
--> $DIR/method-resolution3.rs:21:11
|
LL | x.bar();
| ^^^ multiple `bar` found
|
note: candidate #1 is defined in an impl for the type `Bar<i32>`
--> $DIR/method-resolution3.rs:15:5
|
LL | fn bar(self) {}
| ^^^^^^^^^^^^
note: candidate #2 is defined in an impl for the type `Bar<u32>`
--> $DIR/method-resolution3.rs:11:5
|
LL | fn bar(self) {}
| ^^^^^^^^^^^^
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0034`.

View file

@ -0,0 +1,27 @@
//! Check that we consider `Bar<impl Sized>` to successfully unify
//! with both `Bar<u32>` and `Bar<i32>` (in isolation), so we bail
//! out with ambiguity.
//@ revisions: current next
//@[next] compile-flags: -Znext-solver
struct Bar<T>(T);
impl Bar<u32> {
fn bar(self) {}
}
impl Bar<i32> {
fn bar(self) {}
}
fn foo(x: bool) -> Bar<impl Sized> {
if x {
let x = foo(false);
x.bar();
//~^ ERROR: multiple applicable items in scope
}
todo!()
}
fn main() {}

View file

@ -0,0 +1,22 @@
error[E0282]: type annotations needed
--> $DIR/method-resolution4.rs:13:9
|
LL | foo(false).next().unwrap();
| ^^^^^^^^^^ cannot infer type
error[E0308]: mismatched types
--> $DIR/method-resolution4.rs:16:5
|
LL | fn foo(b: bool) -> impl Iterator<Item = ()> {
| ------------------------ the expected opaque type
...
LL | std::iter::empty()
| ^^^^^^^^^^^^^^^^^^ types differ
|
= note: expected opaque type `impl Iterator<Item = ()>`
found struct `std::iter::Empty<_>`
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0282, E0308.
For more information about an error, try `rustc --explain E0282`.

View file

@ -0,0 +1,20 @@
//! The recursive method call yields the opaque type. The
//! `next` method call then constrains the hidden type to `&mut _`
//! because `next` takes `&mut self`. We never resolve the inference
//! variable, but get a type mismatch when comparing `&mut _` with
//! `std::iter::Empty`.
//@ revisions: current next
//@[next] compile-flags: -Znext-solver
//@[current] check-pass
fn foo(b: bool) -> impl Iterator<Item = ()> {
if b {
foo(false).next().unwrap();
//[next]~^ type annotations needed
}
std::iter::empty()
//[next]~^ mismatched types
}
fn main() {}

View file

@ -0,0 +1,42 @@
//! This test checks that we can resolve the `boxed` method call to `FutureExt`,
//! because we know that the anonymous future does not implement `StreamExt`.
//@ edition: 2021
//@ check-pass
use std::future::Future;
use std::pin::Pin;
trait FutureExt: Future + Sized + Send + 'static {
fn boxed(self) -> Pin<Box<dyn Future<Output = Self::Output> + Send + 'static>> {
Box::pin(self)
}
}
trait StreamExt: Future + Sized + Send + 'static {
fn boxed(self) -> Pin<Box<dyn Future<Output = Self::Output> + Send + 'static>> {
Box::pin(self)
}
}
impl<T: Future + Sized + Send + 'static> FutureExt for T {}
fn go(i: usize) -> impl Future<Output = ()> + Send + 'static {
async move {
if i != 0 {
spawn(async move {
let fut = go(i - 1).boxed();
fut.await;
})
.await;
}
}
}
pub fn spawn<T: Send>(
_: impl Future<Output = T> + Send + 'static,
) -> impl Future<Output = ()> + Send + 'static {
async move { todo!() }
}
fn main() {}

View file

@ -1,4 +1,7 @@
#![feature(type_alias_impl_trait)]
//@ check-pass
struct Foo<T>(T);
impl Foo<u32> {
@ -15,14 +18,11 @@ fn bar() -> Bar {
impl Foo<Bar> {
fn foo() -> Bar {
Self::method();
//~^ ERROR: no function or associated item named `method` found for struct `Foo<Bar>`
Foo::<Bar>::method();
//~^ ERROR: no function or associated item named `method` found for struct `Foo<Bar>`
let x = Foo(bar());
Foo::method2(x);
let x = Self(bar());
Self::method2(x);
//~^ ERROR: no function or associated item named `method2` found for struct `Foo<Bar>`
todo!()
}
}

View file

@ -1,36 +0,0 @@
error[E0599]: no function or associated item named `method` found for struct `Foo<Bar>` in the current scope
--> $DIR/opaque_param_in_ufc.rs:17:15
|
LL | struct Foo<T>(T);
| ------------- function or associated item `method` not found for this struct
...
LL | Self::method();
| ^^^^^^ function or associated item not found in `Foo<Bar>`
|
= note: the function or associated item was found for
- `Foo<u32>`
error[E0599]: no function or associated item named `method` found for struct `Foo<Bar>` in the current scope
--> $DIR/opaque_param_in_ufc.rs:19:21
|
LL | struct Foo<T>(T);
| ------------- function or associated item `method` not found for this struct
...
LL | Foo::<Bar>::method();
| ^^^^^^ function or associated item not found in `Foo<Bar>`
|
= note: the function or associated item was found for
- `Foo<u32>`
error[E0599]: no function or associated item named `method2` found for struct `Foo<Bar>` in the current scope
--> $DIR/opaque_param_in_ufc.rs:24:15
|
LL | struct Foo<T>(T);
| ------------- function or associated item `method2` not found for this struct
...
LL | Self::method2(x);
| ^^^^^^^ function or associated item not found in `Foo<Bar>`
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0599`.

View file

@ -0,0 +1,15 @@
error[E0599]: no method named `bar` found for struct `Bar<u32>` in the current scope
--> $DIR/method_resolution.rs:21:14
|
LL | struct Bar<T>(T);
| ------------- method `bar` not found for this struct
...
LL | self.bar()
| ^^^ method not found in `Bar<u32>`
|
= note: the method was found for
- `Bar<Foo>`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0599`.

View file

@ -0,0 +1,12 @@
error[E0599]: no method named `bar` found for struct `Bar<u32>` in the current scope
--> $DIR/method_resolution.rs:21:14
|
LL | struct Bar<T>(T);
| ------------- method `bar` not found for this struct
...
LL | self.bar()
| ^^^ method cannot be called on `Bar<u32>` due to unsatisfied trait bounds
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0599`.

View file

@ -0,0 +1,30 @@
//! `Bar<u32>::foo` is not defining `Foo`, so it cannot rely on the fact that
//! `u32` is the hidden type of `Foo` to call `bar`
//@ revisions: current next
//@[next] compile-flags: -Znext-solver
#![feature(type_alias_impl_trait)]
type Foo = impl Sized;
struct Bar<T>(T);
impl Bar<Foo> {
fn bar(mut self) {
self.0 = 42_u32;
}
}
impl Bar<u32> {
fn foo(self) {
self.bar()
//~^ ERROR: no method named `bar`
}
}
fn foo() -> Foo {
42_u32
}
fn main() {}

View file

@ -0,0 +1,28 @@
//! Check that we do unify `Bar<Foo>` with `Bar<u32>`, as the
//! `foo` method call can be resolved unambiguously by doing so.
//@ revisions: current next
//@[next] compile-flags: -Znext-solver
//@ check-pass
#![feature(type_alias_impl_trait)]
type Foo = impl Sized;
struct Bar<T>(T);
impl Bar<Foo> {
fn bar(self) {
self.foo()
}
}
impl Bar<u32> {
fn foo(self) {}
}
fn foo() -> Foo {
42_u32
}
fn main() {}

View file

@ -0,0 +1,21 @@
error[E0307]: invalid `self` parameter type: `Bar<u32>`
--> $DIR/method_resolution3.rs:16:18
|
LL | fn bar(self: Bar<u32>) {
| ^^^^^^^^
|
= note: type of `self` must be `Self` or a type that dereferences to it
= help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
error[E0307]: invalid `self` parameter type: `&Bar<u32>`
--> $DIR/method_resolution3.rs:21:18
|
LL | fn baz(self: &Bar<u32>) {
| ^^^^^^^^^
|
= note: type of `self` must be `Self` or a type that dereferences to it
= help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0307`.

View file

@ -0,0 +1,15 @@
error[E0271]: type mismatch resolving `Foo == u32`
--> $DIR/method_resolution3.rs:16:18
|
LL | fn bar(self: Bar<u32>) {
| ^^^^^^^^ types differ
error[E0271]: type mismatch resolving `Foo == u32`
--> $DIR/method_resolution3.rs:21:18
|
LL | fn baz(self: &Bar<u32>) {
| ^^^^^^^^^ types differ
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0271`.

View file

@ -0,0 +1,36 @@
//! Check that one cannot use arbitrary self types where a generic parameter
//! mismatches with an opaque type. In theory this could unify with the opaque
//! type, registering the generic parameter as the hidden type of the opaque type.
//@ revisions: current next
//@[next] compile-flags: -Znext-solver
#![feature(type_alias_impl_trait, arbitrary_self_types)]
type Foo = impl Copy;
#[derive(Copy, Clone)]
struct Bar<T>(T);
impl Bar<Foo> {
fn bar(self: Bar<u32>) {
//[current]~^ ERROR: invalid `self` parameter
//[next]~^^ ERROR: type mismatch resolving `Foo == u32`
self.foo()
}
fn baz(self: &Bar<u32>) {
//[current]~^ ERROR: invalid `self` parameter
//[next]~^^ ERROR: type mismatch resolving `Foo == u32`
self.foo()
}
}
impl Bar<u32> {
fn foo(self) {}
}
fn foo() -> Foo {
42_u32
}
fn main() {}

View file

@ -0,0 +1,21 @@
error[E0307]: invalid `self` parameter type: `Bar<Foo>`
--> $DIR/method_resolution4.rs:27:18
|
LL | fn foo(self: Bar<Foo>) {
| ^^^^^^^^
|
= note: type of `self` must be `Self` or a type that dereferences to it
= help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
error[E0307]: invalid `self` parameter type: `&Bar<Foo>`
--> $DIR/method_resolution4.rs:32:20
|
LL | fn foomp(self: &Bar<Foo>) {
| ^^^^^^^^^
|
= note: type of `self` must be `Self` or a type that dereferences to it
= help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0307`.

View file

@ -0,0 +1,15 @@
error[E0271]: type mismatch resolving `u32 == Foo`
--> $DIR/method_resolution4.rs:27:18
|
LL | fn foo(self: Bar<Foo>) {
| ^^^^^^^^ types differ
error[E0271]: type mismatch resolving `u32 == Foo`
--> $DIR/method_resolution4.rs:32:20
|
LL | fn foomp(self: &Bar<Foo>) {
| ^^^^^^^^^ types differ
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0271`.

View file

@ -0,0 +1,39 @@
//! Check that one cannot use arbitrary self types where a generic parameter
//! mismatches with an opaque type. In theory this could unify with the opaque
//! type, registering the generic parameter as the hidden type of the opaque type.
//@ revisions: current next
//@[next] compile-flags: -Znext-solver
#![feature(type_alias_impl_trait, arbitrary_self_types)]
mod foo {
pub type Foo = impl Copy;
fn foo() -> Foo {
42_u32
}
}
use foo::Foo;
#[derive(Copy, Clone)]
struct Bar<T>(T);
impl Bar<Foo> {
fn bar(self) {}
}
impl Bar<u32> {
fn foo(self: Bar<Foo>) {
//[current]~^ ERROR: invalid `self` parameter
//[next]~^^ ERROR: type mismatch resolving `u32 == Foo`
self.bar()
}
fn foomp(self: &Bar<Foo>) {
//[current]~^ ERROR: invalid `self` parameter
//[next]~^^ ERROR: type mismatch resolving `u32 == Foo`
self.bar()
}
}
fn main() {}

View file

@ -0,0 +1,33 @@
//! Even though `Bar<u32>::foo` is defining `Foo`, the old solver does
//! not figure out that `u32` is the hidden type of `Foo` to call `bar`.
//@ revisions: current next
//@[next] compile-flags: -Znext-solver
//@ check-pass
#![feature(type_alias_impl_trait)]
type Foo = impl Sized;
struct Bar<T>(T);
impl Bar<Foo> {
fn bar(mut self) {
self.0 = 42_u32;
}
}
impl Bar<u32> {
fn foo(self)
where
Foo:,
{
self.bar()
}
}
fn foo() -> Foo {
42_u32
}
fn main() {}

View file

@ -0,0 +1,15 @@
error: item does not constrain `Tait::{opaque#0}`, but has it in its signature
--> $DIR/method_resolution_trait_method_from_opaque.rs:24:8
|
LL | fn foo(&mut self) {
| ^^^
|
= note: consider moving the opaque type's declaration and defining uses into a separate module
note: this opaque type is in the signature
--> $DIR/method_resolution_trait_method_from_opaque.rs:17:13
|
LL | type Tait = impl Iterator<Item = ()>;
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error

View file

@ -0,0 +1,9 @@
error[E0282]: type annotations needed
--> $DIR/method_resolution_trait_method_from_opaque.rs:26:9
|
LL | self.bar.next().unwrap();
| ^^^^^^^^ cannot infer type
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0282`.

View file

@ -0,0 +1,31 @@
//! This test demonstrates how method calls will attempt to unify an opaque type with a reference
//! if the method takes `&self` as its argument. This is almost never what is desired, as the user
//! would like to have method resolution happen on the opaque type instead of inferring the hidden
//! type. Once type-alias-impl-trait requires annotating which functions should constrain the hidden
//! type, this won't be as much of a problem, as most functions that do method calls on opaque types
//! won't also be the ones defining the hidden type.
//@ revisions: current next
//@[next] compile-flags: -Znext-solver
#![feature(type_alias_impl_trait)]
pub struct Foo {
bar: Tait,
}
type Tait = impl Iterator<Item = ()>;
impl Foo {
pub fn new() -> Foo {
Foo { bar: std::iter::empty() }
}
fn foo(&mut self) {
//[current]~^ ERROR: item does not constrain
self.bar.next().unwrap();
//[next]~^ ERROR: type annotations needed
}
}
fn main() {}