mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
Make ProjectionTy::trait_ref truncate substs again
Also make sure that type arguments of associated types are printed in some error messages.
This commit is contained in:
parent
79f6f11816
commit
dfee89f755
@ -1,5 +1,6 @@
|
|||||||
use crate::traits::{ObligationCause, ObligationCauseCode};
|
use crate::traits::{ObligationCause, ObligationCauseCode};
|
||||||
use crate::ty::diagnostics::suggest_constraining_type_param;
|
use crate::ty::diagnostics::suggest_constraining_type_param;
|
||||||
|
use crate::ty::print::{FmtPrinter, Printer};
|
||||||
use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt};
|
use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt};
|
||||||
use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
|
use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
|
||||||
use rustc_errors::{pluralize, DiagnosticBuilder};
|
use rustc_errors::{pluralize, DiagnosticBuilder};
|
||||||
@ -400,14 +401,22 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||||||
{
|
{
|
||||||
// Synthesize the associated type restriction `Add<Output = Expected>`.
|
// Synthesize the associated type restriction `Add<Output = Expected>`.
|
||||||
// FIXME: extract this logic for use in other diagnostics.
|
// FIXME: extract this logic for use in other diagnostics.
|
||||||
let trait_ref = proj.trait_ref(self);
|
let (trait_ref, assoc_substs) = proj.trait_ref_and_own_substs(self);
|
||||||
let path =
|
let path =
|
||||||
self.def_path_str_with_substs(trait_ref.def_id, trait_ref.substs);
|
self.def_path_str_with_substs(trait_ref.def_id, trait_ref.substs);
|
||||||
let item_name = self.item_name(proj.item_def_id);
|
let item_name = self.item_name(proj.item_def_id);
|
||||||
|
let item_args = self.format_generic_args(assoc_substs);
|
||||||
|
|
||||||
let path = if path.ends_with('>') {
|
let path = if path.ends_with('>') {
|
||||||
format!("{}, {} = {}>", &path[..path.len() - 1], item_name, p)
|
format!(
|
||||||
|
"{}, {}{} = {}>",
|
||||||
|
&path[..path.len() - 1],
|
||||||
|
item_name,
|
||||||
|
item_args,
|
||||||
|
p
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
format!("{}<{} = {}>", path, item_name, p)
|
format!("{}<{}{} = {}>", path, item_name, item_args, p)
|
||||||
};
|
};
|
||||||
note = !suggest_constraining_type_param(
|
note = !suggest_constraining_type_param(
|
||||||
self,
|
self,
|
||||||
@ -556,7 +565,7 @@ impl<T> Trait<T> for X {
|
|||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let assoc = self.associated_item(proj_ty.item_def_id);
|
let assoc = self.associated_item(proj_ty.item_def_id);
|
||||||
let trait_ref = proj_ty.trait_ref(self);
|
let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(self);
|
||||||
if let Some(item) = self.hir().get_if_local(body_owner_def_id) {
|
if let Some(item) = self.hir().get_if_local(body_owner_def_id) {
|
||||||
if let Some(hir_generics) = item.generics() {
|
if let Some(hir_generics) = item.generics() {
|
||||||
// Get the `DefId` for the type parameter corresponding to `A` in `<A as T>::Foo`.
|
// Get the `DefId` for the type parameter corresponding to `A` in `<A as T>::Foo`.
|
||||||
@ -590,6 +599,7 @@ impl<T> Trait<T> for X {
|
|||||||
&trait_ref,
|
&trait_ref,
|
||||||
pred.bounds,
|
pred.bounds,
|
||||||
&assoc,
|
&assoc,
|
||||||
|
assoc_substs,
|
||||||
ty,
|
ty,
|
||||||
msg,
|
msg,
|
||||||
) {
|
) {
|
||||||
@ -607,6 +617,7 @@ impl<T> Trait<T> for X {
|
|||||||
&trait_ref,
|
&trait_ref,
|
||||||
param.bounds,
|
param.bounds,
|
||||||
&assoc,
|
&assoc,
|
||||||
|
assoc_substs,
|
||||||
ty,
|
ty,
|
||||||
msg,
|
msg,
|
||||||
);
|
);
|
||||||
@ -692,6 +703,7 @@ impl<T> Trait<T> for X {
|
|||||||
db,
|
db,
|
||||||
self.def_span(def_id),
|
self.def_span(def_id),
|
||||||
&assoc,
|
&assoc,
|
||||||
|
proj_ty.trait_ref_and_own_substs(self).1,
|
||||||
values.found,
|
values.found,
|
||||||
&msg,
|
&msg,
|
||||||
) {
|
) {
|
||||||
@ -856,6 +868,7 @@ fn foo(&self) -> Self::T { String::new() }
|
|||||||
trait_ref: &ty::TraitRef<'tcx>,
|
trait_ref: &ty::TraitRef<'tcx>,
|
||||||
bounds: hir::GenericBounds<'_>,
|
bounds: hir::GenericBounds<'_>,
|
||||||
assoc: &ty::AssocItem,
|
assoc: &ty::AssocItem,
|
||||||
|
assoc_substs: &[ty::GenericArg<'tcx>],
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
msg: &str,
|
msg: &str,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
@ -865,7 +878,12 @@ fn foo(&self) -> Self::T { String::new() }
|
|||||||
// Relate the type param against `T` in `<A as T>::Foo`.
|
// Relate the type param against `T` in `<A as T>::Foo`.
|
||||||
ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id)
|
ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id)
|
||||||
&& self.constrain_associated_type_structured_suggestion(
|
&& self.constrain_associated_type_structured_suggestion(
|
||||||
db, ptr.span, assoc, ty, msg,
|
db,
|
||||||
|
ptr.span,
|
||||||
|
assoc,
|
||||||
|
assoc_substs,
|
||||||
|
ty,
|
||||||
|
msg,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
@ -879,6 +897,7 @@ fn foo(&self) -> Self::T { String::new() }
|
|||||||
db: &mut DiagnosticBuilder<'_>,
|
db: &mut DiagnosticBuilder<'_>,
|
||||||
span: Span,
|
span: Span,
|
||||||
assoc: &ty::AssocItem,
|
assoc: &ty::AssocItem,
|
||||||
|
assoc_substs: &[ty::GenericArg<'tcx>],
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
msg: &str,
|
msg: &str,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
@ -890,11 +909,20 @@ fn foo(&self) -> Self::T { String::new() }
|
|||||||
let span = Span::new(pos, pos, span.ctxt());
|
let span = Span::new(pos, pos, span.ctxt());
|
||||||
(span, format!(", {} = {}", assoc.ident, ty))
|
(span, format!(", {} = {}", assoc.ident, ty))
|
||||||
} else {
|
} else {
|
||||||
(span.shrink_to_hi(), format!("<{} = {}>", assoc.ident, ty))
|
let item_args = self.format_generic_args(assoc_substs);
|
||||||
|
(span.shrink_to_hi(), format!("<{}{} = {}>", assoc.ident, item_args, ty))
|
||||||
};
|
};
|
||||||
db.span_suggestion_verbose(span, msg, sugg, MaybeIncorrect);
|
db.span_suggestion_verbose(span, msg, sugg, MaybeIncorrect);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn format_generic_args(self, args: &[ty::GenericArg<'tcx>]) -> String {
|
||||||
|
let mut item_args = String::new();
|
||||||
|
FmtPrinter::new(self, &mut item_args, hir::def::Namespace::TypeNS)
|
||||||
|
.path_generic_args(Ok, args)
|
||||||
|
.expect("could not write to `String`.");
|
||||||
|
item_args
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1289,8 +1289,22 @@ impl<'tcx> PolyProjectionPredicate<'tcx> {
|
|||||||
self.skip_binder().projection_ty.item_def_id
|
self.skip_binder().projection_ty.item_def_id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the `DefId` of the trait of the associated item being projected.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_poly_trait_ref(&self, tcx: TyCtxt<'tcx>) -> PolyTraitRef<'tcx> {
|
pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId {
|
||||||
|
self.skip_binder().projection_ty.trait_def_id(tcx)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn projection_self_ty(&self) -> Binder<Ty<'tcx>> {
|
||||||
|
self.map_bound(|predicate| predicate.projection_ty.self_ty())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the [PolyTraitRef] required for this projection to be well formed.
|
||||||
|
/// Note that for generic associated types the predicates of the associated
|
||||||
|
/// type also need to be checked.
|
||||||
|
#[inline]
|
||||||
|
pub fn required_poly_trait_ref(&self, tcx: TyCtxt<'tcx>) -> PolyTraitRef<'tcx> {
|
||||||
// Note: unlike with `TraitRef::to_poly_trait_ref()`,
|
// Note: unlike with `TraitRef::to_poly_trait_ref()`,
|
||||||
// `self.0.trait_ref` is permitted to have escaping regions.
|
// `self.0.trait_ref` is permitted to have escaping regions.
|
||||||
// This is because here `self` has a `Binder` and so does our
|
// This is because here `self` has a `Binder` and so does our
|
||||||
|
@ -17,7 +17,7 @@ use rustc_hir as hir;
|
|||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_index::vec::Idx;
|
use rustc_index::vec::Idx;
|
||||||
use rustc_macros::HashStable;
|
use rustc_macros::HashStable;
|
||||||
use rustc_span::symbol::{kw, Ident, Symbol};
|
use rustc_span::symbol::{kw, Symbol};
|
||||||
use rustc_target::abi::VariantIdx;
|
use rustc_target::abi::VariantIdx;
|
||||||
use rustc_target::spec::abi;
|
use rustc_target::spec::abi;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
@ -1112,20 +1112,35 @@ pub struct ProjectionTy<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ProjectionTy<'tcx> {
|
impl<'tcx> ProjectionTy<'tcx> {
|
||||||
|
pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId {
|
||||||
|
tcx.associated_item(self.item_def_id).container.id()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extracts the underlying trait reference and own substs from this projection.
|
||||||
|
/// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
|
||||||
|
/// then this function would return a `T: Iterator` trait reference and `['a]` as the own substs
|
||||||
|
pub fn trait_ref_and_own_substs(
|
||||||
|
&self,
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) {
|
||||||
|
let def_id = tcx.associated_item(self.item_def_id).container.id();
|
||||||
|
let trait_generics = tcx.generics_of(def_id);
|
||||||
|
(
|
||||||
|
ty::TraitRef { def_id, substs: self.substs.truncate_to(tcx, trait_generics) },
|
||||||
|
&self.substs[trait_generics.count()..],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// Extracts the underlying trait reference from this projection.
|
/// Extracts the underlying trait reference from this projection.
|
||||||
/// For example, if this is a projection of `<T as Iterator>::Item`,
|
/// For example, if this is a projection of `<T as Iterator>::Item`,
|
||||||
/// then this function would return a `T: Iterator` trait reference.
|
/// then this function would return a `T: Iterator` trait reference.
|
||||||
|
///
|
||||||
|
/// WARNING: This will drop the substs for generic associated types
|
||||||
|
/// consider calling [Self::trait_ref_and_own_substs] to get those
|
||||||
|
/// as well.
|
||||||
pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
|
pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
|
||||||
// FIXME: This method probably shouldn't exist at all, since it's not
|
let def_id = self.trait_def_id(tcx);
|
||||||
// clear what this method really intends to do. Be careful when
|
ty::TraitRef { def_id, substs: self.substs.truncate_to(tcx, tcx.generics_of(def_id)) }
|
||||||
// using this method since the resulting TraitRef additionally
|
|
||||||
// contains the substs for the assoc_item, which strictly speaking
|
|
||||||
// is not correct
|
|
||||||
let def_id = tcx.associated_item(self.item_def_id).container.id();
|
|
||||||
// Include substitutions for generic arguments of associated types
|
|
||||||
let assoc_item = tcx.associated_item(self.item_def_id);
|
|
||||||
let substs_assoc_item = self.substs.truncate_to(tcx, tcx.generics_of(assoc_item.def_id));
|
|
||||||
ty::TraitRef { def_id, substs: substs_assoc_item }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn self_ty(&self) -> Ty<'tcx> {
|
pub fn self_ty(&self) -> Ty<'tcx> {
|
||||||
|
@ -1589,8 +1589,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
|
|||||||
self.emit_inference_failure_err(body_id, span, a.into(), vec![], ErrorCode::E0282)
|
self.emit_inference_failure_err(body_id, span, a.into(), vec![], ErrorCode::E0282)
|
||||||
}
|
}
|
||||||
ty::PredicateKind::Projection(data) => {
|
ty::PredicateKind::Projection(data) => {
|
||||||
let trait_ref = bound_predicate.rebind(data).to_poly_trait_ref(self.tcx);
|
let self_ty = data.projection_ty.self_ty();
|
||||||
let self_ty = trait_ref.skip_binder().self_ty();
|
|
||||||
let ty = data.ty;
|
let ty = data.ty;
|
||||||
if predicate.references_error() {
|
if predicate.references_error() {
|
||||||
return;
|
return;
|
||||||
|
@ -779,14 +779,11 @@ impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::AliasEqBound<RustInterner<'tcx>
|
|||||||
self,
|
self,
|
||||||
interner: &RustInterner<'tcx>,
|
interner: &RustInterner<'tcx>,
|
||||||
) -> chalk_solve::rust_ir::AliasEqBound<RustInterner<'tcx>> {
|
) -> chalk_solve::rust_ir::AliasEqBound<RustInterner<'tcx>> {
|
||||||
let trait_ref = self.projection_ty.trait_ref(interner.tcx);
|
let (trait_ref, own_substs) = self.projection_ty.trait_ref_and_own_substs(interner.tcx);
|
||||||
chalk_solve::rust_ir::AliasEqBound {
|
chalk_solve::rust_ir::AliasEqBound {
|
||||||
trait_bound: trait_ref.lower_into(interner),
|
trait_bound: trait_ref.lower_into(interner),
|
||||||
associated_ty_id: chalk_ir::AssocTypeId(self.projection_ty.item_def_id),
|
associated_ty_id: chalk_ir::AssocTypeId(self.projection_ty.item_def_id),
|
||||||
parameters: self.projection_ty.substs[trait_ref.substs.len()..]
|
parameters: own_substs.iter().map(|arg| arg.lower_into(interner)).collect(),
|
||||||
.iter()
|
|
||||||
.map(|arg| arg.lower_into(interner))
|
|
||||||
.collect(),
|
|
||||||
value: self.ty.lower_into(interner),
|
value: self.ty.lower_into(interner),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -208,7 +208,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Even if we can't infer the full signature, we may be able to
|
// Even if we can't infer the full signature, we may be able to
|
||||||
// infer the kind. This can occur if there is a trait-reference
|
// infer the kind. This can occur when we elaborate a predicate
|
||||||
// like `F : Fn<A>`. Note that due to subtyping we could encounter
|
// like `F : Fn<A>`. Note that due to subtyping we could encounter
|
||||||
// many viable options, so pick the most restrictive.
|
// many viable options, so pick the most restrictive.
|
||||||
let expected_kind = self
|
let expected_kind = self
|
||||||
@ -234,11 +234,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
|
|
||||||
debug!("deduce_sig_from_projection({:?})", projection);
|
debug!("deduce_sig_from_projection({:?})", projection);
|
||||||
|
|
||||||
let trait_ref = projection.to_poly_trait_ref(tcx);
|
let trait_def_id = projection.trait_def_id(tcx);
|
||||||
|
|
||||||
let is_fn = tcx.fn_trait_kind_from_lang_item(trait_ref.def_id()).is_some();
|
let is_fn = tcx.fn_trait_kind_from_lang_item(trait_def_id).is_some();
|
||||||
let gen_trait = tcx.require_lang_item(LangItem::Generator, cause_span);
|
let gen_trait = tcx.require_lang_item(LangItem::Generator, cause_span);
|
||||||
let is_gen = gen_trait == trait_ref.def_id();
|
let is_gen = gen_trait == trait_def_id;
|
||||||
if !is_fn && !is_gen {
|
if !is_fn && !is_gen {
|
||||||
debug!("deduce_sig_from_projection: not fn or generator");
|
debug!("deduce_sig_from_projection: not fn or generator");
|
||||||
return None;
|
return None;
|
||||||
@ -256,7 +256,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let input_tys = if is_fn {
|
let input_tys = if is_fn {
|
||||||
let arg_param_ty = trait_ref.skip_binder().substs.type_at(1);
|
let arg_param_ty = projection.skip_binder().projection_ty.substs.type_at(1);
|
||||||
let arg_param_ty = self.resolve_vars_if_possible(arg_param_ty);
|
let arg_param_ty = self.resolve_vars_if_possible(arg_param_ty);
|
||||||
debug!("deduce_sig_from_projection: arg_param_ty={:?}", arg_param_ty);
|
debug!("deduce_sig_from_projection: arg_param_ty={:?}", arg_param_ty);
|
||||||
|
|
||||||
@ -662,9 +662,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Check that this is a projection from the `Future` trait.
|
// Check that this is a projection from the `Future` trait.
|
||||||
let trait_ref = predicate.projection_ty.trait_ref(self.tcx);
|
let trait_def_id = predicate.projection_ty.trait_def_id(self.tcx);
|
||||||
let future_trait = self.tcx.require_lang_item(LangItem::Future, Some(cause_span));
|
let future_trait = self.tcx.require_lang_item(LangItem::Future, Some(cause_span));
|
||||||
if trait_ref.def_id != future_trait {
|
if trait_def_id != future_trait {
|
||||||
debug!("deduce_future_output_from_projection: not a future");
|
debug!("deduce_future_output_from_projection: not a future");
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -769,9 +769,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
.filter_map(move |obligation| {
|
.filter_map(move |obligation| {
|
||||||
let bound_predicate = obligation.predicate.kind();
|
let bound_predicate = obligation.predicate.kind();
|
||||||
match bound_predicate.skip_binder() {
|
match bound_predicate.skip_binder() {
|
||||||
ty::PredicateKind::Projection(data) => {
|
ty::PredicateKind::Projection(data) => Some((
|
||||||
Some((bound_predicate.rebind(data).to_poly_trait_ref(self.tcx), obligation))
|
bound_predicate.rebind(data).required_poly_trait_ref(self.tcx),
|
||||||
}
|
obligation,
|
||||||
|
)),
|
||||||
ty::PredicateKind::Trait(data, _) => {
|
ty::PredicateKind::Trait(data, _) => {
|
||||||
Some((bound_predicate.rebind(data).to_poly_trait_ref(), obligation))
|
Some((bound_predicate.rebind(data).to_poly_trait_ref(), obligation))
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
|
|||||||
use rustc_trait_selection::traits::Obligation;
|
use rustc_trait_selection::traits::Obligation;
|
||||||
|
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
use std::iter;
|
||||||
|
|
||||||
use super::probe::Mode;
|
use super::probe::Mode;
|
||||||
use super::{CandidateSource, MethodError, NoMatchData};
|
use super::{CandidateSource, MethodError, NoMatchData};
|
||||||
@ -649,21 +650,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
ty::PredicateKind::Projection(pred) => {
|
ty::PredicateKind::Projection(pred) => {
|
||||||
let pred = bound_predicate.rebind(pred);
|
let pred = bound_predicate.rebind(pred);
|
||||||
// `<Foo as Iterator>::Item = String`.
|
// `<Foo as Iterator>::Item = String`.
|
||||||
let trait_ref =
|
let projection_ty = pred.skip_binder().projection_ty;
|
||||||
pred.skip_binder().projection_ty.trait_ref(self.tcx);
|
|
||||||
let assoc = self
|
let substs_with_infer_self = tcx.mk_substs(
|
||||||
.tcx
|
iter::once(tcx.mk_ty_var(ty::TyVid { index: 0 }).into())
|
||||||
.associated_item(pred.skip_binder().projection_ty.item_def_id);
|
.chain(projection_ty.substs.iter().skip(1)),
|
||||||
let ty = pred.skip_binder().ty;
|
|
||||||
let obligation = format!("{}::{} = {}", trait_ref, assoc.ident, ty);
|
|
||||||
let quiet = format!(
|
|
||||||
"<_ as {}>::{} = {}",
|
|
||||||
trait_ref.print_only_trait_path(),
|
|
||||||
assoc.ident,
|
|
||||||
ty
|
|
||||||
);
|
);
|
||||||
bound_span_label(trait_ref.self_ty(), &obligation, &quiet);
|
|
||||||
Some((obligation, trait_ref.self_ty()))
|
let quiet_projection_ty = ty::ProjectionTy {
|
||||||
|
substs: substs_with_infer_self,
|
||||||
|
item_def_id: projection_ty.item_def_id,
|
||||||
|
};
|
||||||
|
|
||||||
|
let ty = pred.skip_binder().ty;
|
||||||
|
|
||||||
|
let obligation = format!("{} = {}", projection_ty, ty);
|
||||||
|
let quiet = format!("{} = {}", quiet_projection_ty, ty);
|
||||||
|
|
||||||
|
bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
|
||||||
|
Some((obligation, projection_ty.self_ty()))
|
||||||
}
|
}
|
||||||
ty::PredicateKind::Trait(poly_trait_ref, _) => {
|
ty::PredicateKind::Trait(poly_trait_ref, _) => {
|
||||||
let p = poly_trait_ref.trait_ref;
|
let p = poly_trait_ref.trait_ref;
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
// Test that correct syntax is used in suggestion to constrain associated type
|
||||||
|
|
||||||
|
#![feature(generic_associated_types)]
|
||||||
|
//~^ WARNING the feature `generic_associated_types` is incomplete
|
||||||
|
|
||||||
|
trait X {
|
||||||
|
type Y<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f<T: X>(a: T::Y<i32>) {
|
||||||
|
//~^ HELP consider constraining the associated type `<T as X>::Y<i32>` to `Vec<i32>`
|
||||||
|
//~| SUGGESTION Y<i32> = Vec<i32>>
|
||||||
|
let b: Vec<i32> = a;
|
||||||
|
//~^ ERROR mismatched types
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
@ -0,0 +1,27 @@
|
|||||||
|
warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||||
|
--> $DIR/constraint-assoc-type-suggestion.rs:3:12
|
||||||
|
|
|
||||||
|
LL | #![feature(generic_associated_types)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `#[warn(incomplete_features)]` on by default
|
||||||
|
= note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/constraint-assoc-type-suggestion.rs:13:23
|
||||||
|
|
|
||||||
|
LL | let b: Vec<i32> = a;
|
||||||
|
| -------- ^ expected struct `Vec`, found associated type
|
||||||
|
| |
|
||||||
|
| expected due to this
|
||||||
|
|
|
||||||
|
= note: expected struct `Vec<i32>`
|
||||||
|
found associated type `<T as X>::Y<i32>`
|
||||||
|
help: consider constraining the associated type `<T as X>::Y<i32>` to `Vec<i32>`
|
||||||
|
|
|
||||||
|
LL | fn f<T: X<Y<i32> = Vec<i32>>>(a: T::Y<i32>) {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to previous error; 1 warning emitted
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
@ -0,0 +1,35 @@
|
|||||||
|
// Test that the predicate printed in an unresolved method error prints the
|
||||||
|
// generics for a generic associated type.
|
||||||
|
|
||||||
|
#![feature(generic_associated_types)]
|
||||||
|
//~^ WARNING the feature `generic_associated_types` is incomplete
|
||||||
|
//~| NOTE `#[warn(incomplete_features)]` on by default
|
||||||
|
//~| NOTE see issue #44265
|
||||||
|
|
||||||
|
trait X {
|
||||||
|
type Y<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait M {
|
||||||
|
fn f(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: X<Y<i32> = i32>> M for T {}
|
||||||
|
|
||||||
|
struct S;
|
||||||
|
//~^ NOTE method `f` not found for this
|
||||||
|
//~| NOTE doesn't satisfy `<S as X>::Y<i32> = i32`
|
||||||
|
//~| NOTE doesn't satisfy `S: M`
|
||||||
|
|
||||||
|
impl X for S {
|
||||||
|
type Y<T> = bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f(a: S) {
|
||||||
|
a.f();
|
||||||
|
//~^ ERROR the method `f` exists for struct `S`, but its trait bounds were not satisfied
|
||||||
|
//~| NOTE method cannot be called on `S` due to unsatisfied trait bounds
|
||||||
|
//~| NOTE the following trait bounds were not satisfied:
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
@ -0,0 +1,29 @@
|
|||||||
|
warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||||
|
--> $DIR/method-unsatified-assoc-type-predicate.rs:4:12
|
||||||
|
|
|
||||||
|
LL | #![feature(generic_associated_types)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `#[warn(incomplete_features)]` on by default
|
||||||
|
= note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
|
||||||
|
|
||||||
|
error[E0599]: the method `f` exists for struct `S`, but its trait bounds were not satisfied
|
||||||
|
--> $DIR/method-unsatified-assoc-type-predicate.rs:29:7
|
||||||
|
|
|
||||||
|
LL | struct S;
|
||||||
|
| ---------
|
||||||
|
| |
|
||||||
|
| method `f` not found for this
|
||||||
|
| doesn't satisfy `<S as X>::Y<i32> = i32`
|
||||||
|
| doesn't satisfy `S: M`
|
||||||
|
...
|
||||||
|
LL | a.f();
|
||||||
|
| ^ method cannot be called on `S` due to unsatisfied trait bounds
|
||||||
|
|
|
||||||
|
= note: the following trait bounds were not satisfied:
|
||||||
|
`<S as X>::Y<i32> = i32`
|
||||||
|
which is required by `S: M`
|
||||||
|
|
||||||
|
error: aborting due to previous error; 1 warning emitted
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0599`.
|
Loading…
Reference in New Issue
Block a user