Rollup merge of #121912 - fmease:diag-method-chains-gat, r=compiler-errors,estebank
Properly deal with GATs when looking for method chains to point at Fixes #121898. ~~While it prevents an ICE and the structured suggestion is correct, the method chain diagnostic notes are weird / useless / incorrect judging by a quick look. I guess I should improve that in this PR.~~ Sufficiently taken care of. r? estebank or compiler-errors (#105332, #105674).
This commit is contained in:
commit
cd9e5b5f43
@ -16,6 +16,7 @@
|
||||
#![allow(internal_features)]
|
||||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(associated_type_bounds)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(control_flow_enum)]
|
||||
|
@ -38,6 +38,7 @@
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::{BytePos, DesugaringKind, ExpnKind, MacroKind, Span, DUMMY_SP};
|
||||
use rustc_target::spec::abi;
|
||||
use std::assert_matches::debug_assert_matches;
|
||||
use std::borrow::Cow;
|
||||
use std::iter;
|
||||
|
||||
@ -4219,30 +4220,25 @@ fn probe_assoc_types_at_expr(
|
||||
};
|
||||
|
||||
let origin = TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span };
|
||||
let trait_def_id = proj.trait_def_id(self.tcx);
|
||||
// Make `Self` be equivalent to the type of the call chain
|
||||
// expression we're looking at now, so that we can tell what
|
||||
// for example `Iterator::Item` is at this point in the chain.
|
||||
let args = GenericArgs::for_item(self.tcx, trait_def_id, |param, _| {
|
||||
match param.kind {
|
||||
ty::GenericParamDefKind::Type { .. } => {
|
||||
if param.index == 0 {
|
||||
return prev_ty.into();
|
||||
}
|
||||
}
|
||||
ty::GenericParamDefKind::Lifetime | ty::GenericParamDefKind::Const { .. } => {}
|
||||
let args = GenericArgs::for_item(self.tcx, proj.def_id, |param, _| {
|
||||
if param.index == 0 {
|
||||
debug_assert_matches!(param.kind, ty::GenericParamDefKind::Type { .. });
|
||||
return prev_ty.into();
|
||||
}
|
||||
self.var_for_def(span, param)
|
||||
});
|
||||
// This will hold the resolved type of the associated type, if the
|
||||
// current expression implements the trait that associated type is
|
||||
// in. For example, this would be what `Iterator::Item` is here.
|
||||
let ty_var = self.infcx.next_ty_var(origin);
|
||||
let ty = self.infcx.next_ty_var(origin);
|
||||
// This corresponds to `<ExprTy as Iterator>::Item = _`.
|
||||
let projection = ty::Binder::dummy(ty::PredicateKind::Clause(
|
||||
ty::ClauseKind::Projection(ty::ProjectionPredicate {
|
||||
projection_ty: ty::AliasTy::new(self.tcx, proj.def_id, args),
|
||||
term: ty_var.into(),
|
||||
term: ty.into(),
|
||||
}),
|
||||
));
|
||||
let body_def_id = self.tcx.hir().enclosing_body_owner(body_id);
|
||||
@ -4254,14 +4250,15 @@ fn probe_assoc_types_at_expr(
|
||||
param_env,
|
||||
projection,
|
||||
));
|
||||
if ocx.select_where_possible().is_empty() {
|
||||
// `ty_var` now holds the type that `Item` is for `ExprTy`.
|
||||
let ty_var = self.resolve_vars_if_possible(ty_var);
|
||||
assocs_in_this_method.push(Some((span, (proj.def_id, ty_var))));
|
||||
if ocx.select_where_possible().is_empty()
|
||||
&& let ty = self.resolve_vars_if_possible(ty)
|
||||
&& !ty.is_ty_var()
|
||||
{
|
||||
assocs_in_this_method.push(Some((span, (proj.def_id, ty))));
|
||||
} else {
|
||||
// `<ExprTy as Iterator>` didn't select, so likely we've
|
||||
// reached the end of the iterator chain, like the originating
|
||||
// `Vec<_>`.
|
||||
// `Vec<_>` or the `ty` couldn't be determined.
|
||||
// Keep the space consistent for later zipping.
|
||||
assocs_in_this_method.push(None);
|
||||
}
|
||||
|
22
tests/ui/typeck/method-chain-gats.rs
Normal file
22
tests/ui/typeck/method-chain-gats.rs
Normal file
@ -0,0 +1,22 @@
|
||||
// Regression test for issue #121898.
|
||||
|
||||
trait Base {
|
||||
type Base<B>;
|
||||
}
|
||||
|
||||
trait Functor<A>: Base {
|
||||
fn fmap<B>(self, f: impl Fn(A) -> B) -> Self::Base<B>
|
||||
where
|
||||
Self::Base<B>: Functor<B>;
|
||||
}
|
||||
|
||||
fn fmap2<T, A, B, C>(input: T, f1: impl Fn(A) -> B, f2: impl Fn(B) -> C) -> T::Base<C>
|
||||
where
|
||||
T: Functor<A>,
|
||||
T::Base<B>: Functor<B, Base<C> = T::Base<C>>,
|
||||
{
|
||||
input.fmap(f1).fmap(f2)
|
||||
//~^ ERROR the trait bound `<T as Base>::Base<C>: Functor<C>` is not satisfied
|
||||
}
|
||||
|
||||
fn main() {}
|
27
tests/ui/typeck/method-chain-gats.stderr
Normal file
27
tests/ui/typeck/method-chain-gats.stderr
Normal file
@ -0,0 +1,27 @@
|
||||
error[E0277]: the trait bound `<T as Base>::Base<C>: Functor<C>` is not satisfied
|
||||
--> $DIR/method-chain-gats.rs:18:20
|
||||
|
|
||||
LL | input.fmap(f1).fmap(f2)
|
||||
| ^^^^ the trait `Functor<C>` is not implemented for `<T as Base>::Base<C>`
|
||||
|
|
||||
note: the method call chain might not have had the expected associated types
|
||||
--> $DIR/method-chain-gats.rs:13:29
|
||||
|
|
||||
LL | fn fmap2<T, A, B, C>(input: T, f1: impl Fn(A) -> B, f2: impl Fn(B) -> C) -> T::Base<C>
|
||||
| ^ `Base::Base` is `<T as Base>::Base<_>` here
|
||||
note: required by a bound in `Functor::fmap`
|
||||
--> $DIR/method-chain-gats.rs:10:24
|
||||
|
|
||||
LL | fn fmap<B>(self, f: impl Fn(A) -> B) -> Self::Base<B>
|
||||
| ---- required by a bound in this associated function
|
||||
LL | where
|
||||
LL | Self::Base<B>: Functor<B>;
|
||||
| ^^^^^^^^^^ required by this bound in `Functor::fmap`
|
||||
help: consider further restricting the associated type
|
||||
|
|
||||
LL | T::Base<B>: Functor<B, Base<C> = T::Base<C>>, <T as Base>::Base<C>: Functor<C>
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
Loading…
Reference in New Issue
Block a user